4 MLE JavaScriptモジュールのインポートの概要

MLEの主な利点の1つに、JavaScriptコードのモジュールをOracle Databaseに格納できることがあります。モジュールを使用できることは自己完結型で再利用可能なコードの実現に役立ち、このことがソフトウェア・プロジェクトの成功の鍵となります。

MLEモジュールは、インポートおよびエクスポートを通じて相互に対話します。具体的には、モジュールが別のモジュールによって提供される機能を使用する場合は、ソース・モジュールをエクスポートしてからコール元のモジュールのスコープにインポートする必要があります。

アーキテクチャの違いにより、Oracle Databaseでのモジュール・インポートの動作は、他の開発環境と比較すると若干異なります。たとえば、Node.jsで使用されるJavaScriptソース・コードは、ディスク上の特定のディレクトリ構造に格納されます。または、MLEモジュールは、ファイル・システムではなくデータベースとともに格納されるため、別の方法で参照する必要があります。

MLEでは、モジュール・インポートに使用できるオプションが2つあります:
  • モジュール機能を別のモジュールにインポートします
  • モジュール機能をコード・スニペットにインポートして動的MLEを介して実行します(DBMS_MLE PL/SQLパッケージを使用)

ノート:

MLEは、純粋なJavaScript実装をサポートしています。モジュールのエクスポートおよびインポートは、exportおよびimportキーワードを使用すると、ECMAScriptモジュールとして容易になります。CommonJSや非同期モジュール定義(AMD)などの他のJavaScriptモジュラ化テクノロジは使用できません。

関連項目:

MLEモジュールの詳細は、「MLE JavaScriptモジュールおよび環境」を参照してください

トピック

JavaScriptモジュールの階層

ファイル・システムの場所ではなくインポート名を使用してMLEモジュールに解決するする方法について説明します。

一般的なNode.jsまたはブラウザベースのワークフローでは、モジュール・インポートの後にファイル・システム内のその場所を指定する必要があります。たとえば、次の行はNode.jsの有効なモジュール・インポート文です:

import * as myMath from './myMath.mjs'

Node.jsで使用すると、この文はmyMathのコンテンツを現在のスコープにインポートします。

ただし、MLE JavaScriptモジュールはデータベースに格納されるため、識別に使用するファイル・システム・パスはありません。かわりに、MLEは、目的のモジュールに解決されるインポート名を使用します。

ノート:

モジュール・インポートがJavaScriptランタイム・エンジンによって検出されるとすぐに、strict modeが適用されます。

トピック

MLE環境を使用したインポート名の解決

MLEは、ファイル・システムの場所ではなく、いわゆるインポート名をかわりに使用します。インポート名は有効なJavaScript識別子である必要がありますが、この点以外は自由に選択できます。

例4-1 MLE環境を使用したモジュールへのインポート名のマップ

この例は、例4-2で定義されているモジュールnamed_exports_module内の機能を参照するコードのインポート名を使用する方法を示しています。

Oracle DatabaseのMLEには、実行時にインポート名namedExportsとその対応するMLEモジュールnamed_exports_moduleの間のリンクが必要です。インポート名と同様に、MLE環境に任意の有効な名前を選択できます。潜在的なマッピングを次のスニペットに示します。モジュールmod_object_import_modの完全な定義は、例4-6を参照してください。

CREATE OR REPLACE MLE ENV named_exports_env
    imports ('namedExports' MODULE named_exports_module);
/

CREATE OR REPLACE MLE MODULE mod_object_import_mod LANGUAGE JAVASCRIPT AS

import * as myMath from "namedExports";

function mySum() {...}
/

エクスポート機能

ネイティブJavaScriptモジュールで一般的にエクスポートされる識別子には、変数、定数、ファンクションおよびクラスが含まれます。

トピック

名前付きエクスポート

export文での識別子の明示的な使用は、JavaScriptでの名前付きエクスポートの使用と呼ばれます。

例4-2は、名前付きエクスポートを使用した複数のファンクションのエクスポートを示しています。

例4-2 名前付きエクスポートを使用したファンクションのエクスポート

このコード・スニペットは、named_exports_moduleというモジュールを作成し、sum()difference()という2つのファンクションを定義した後、名前付きエクスポートを使用して、リストされたファンクションをインポートする他のモジュールへのアクセスを提供します。

CREATE OR REPLACE MLE MODULE named_exports_module LANGUAGE JAVASCRIPT AS

function sum(a, b) {
    return a + b;
}

function difference(a, b) {
    return a - b;
}

export {sum, difference};
/

モジュールの最後のexport{}文に注意してください。名前付きエクスポートでは、識別子をリストする際に中カッコを使用する必要があります。中カッコの間に配置された識別子はすべてエクスポートされます。リストされていないものはエクスポートされません。

モジュールの最後にexport文を使用するのではなく、インラインでexportキーワードを使用して識別子の前に付加することもできます。次の例は、前述の例と同じモジュールを、JavaScriptコードでインラインで指定されているexportキーワードを使用してリライトする方法を示しています。

例4-3 インラインでexportキーワードを使用したファンクションのエクスポート

このコード・スニペットは、inline_export_moduleというモジュールを作成し、sum()difference()という2つのファンクションを定義します。これらの両方のファンクションには、インラインでexportキーワードが先頭に付加されます。

CREATE OR REPLACE MLE MODULE inline_export_module LANGUAGE JAVASCRIPT AS

export function sum(a, b) {
    return a + b;
}

export function difference(a, b) {
    return a - b;
}
/

例4-2named_exports_moduleinline_export_moduleはどちらも意味的に同じです。ファンクションのエクスポートに使用するメソッドのみが構文上で異なっています。

デフォルト・エクスポート

名前付きエクスポートのかわりに、JavaScriptでデフォルト・エクスポートを定義できます。デフォルト・エクスポートは、名前付きエクスポートとは構文が異なります。後者とは異なり、デフォルト・エクスポートには一連の中カッコは必要ありません。

ノート:

ECMAScript標準に従い、モジュールごとに可能なデフォルト・エクスポートは1つのみです。

例4-4 デフォルト・エクスポートを使用したクラスのエクスポート

次のコード・スニペットは、default_export_moduleというモジュールを作成し、myMathというクラスを定義し、デフォルト・エクスポートを使用してこのクラスをデフォルトに設定します。

CREATE OR REPLACE MLE MODULE default_export_module 
LANGUAGE JAVASCRIPT AS

export default class myMath {

    static sum(operand1, operand2) {
        return operand1 + operand2;
    }

    static difference(operand1, operand2) {
        return operand1 - operand2;
    }
}
/

プライベート識別子

モジュールからエクスポートされない識別子はプライベートとみなされ、モジュールのスコープ外またはモジュール・コール仕様では参照できません。

例4-5 1つのファンクションの名前付きエクスポート

次のコード・スニペットは、private_export_moduleというモジュールを作成し、sum()difference()という2つのファンクションを定義し、名前付きエクスポートを介してファンクションsum()をエクスポートします。ファンクションdifference()はexport文に含まれていないため、その独自のモジュールのスコープ内でのみ使用できます。

CREATE OR REPLACE MLE MODULE private_export_module
LANGUAGE JAVASCRIPT AS

function sum(a, b) {
    return a + b;
}

function difference(a, b) {
    return a - b;
}

export { sum };
/

インポート機能

importキーワードを使用すると、開発者はソース・モジュールによってエクスポートされた機能をインポートできます。

トピック

モジュール・オブジェクト

モジュール・オブジェクトは、モジュールによってエクスポートされたすべてのものをインポートする便利な方法を提供します。

モジュール・オブジェクトは、モジュールによってエクスポートされたすべての識別子にアクセスする手段を提供し、インポートを参照するときに一種のネームスペースとして使用されます。

例4-6 モジュール・オブジェクトの定義

CREATE MLE ENV named_exports_env
    IMPORTS('namedExports' module named_exports_module);

CREATE OR REPLACE MLE MODULE mod_object_import_mod
LANGUAGE JAVASCRIPT AS

//the definition of a module object is demonstrated by the next line
import * as myMath from "namedExports"

function mySum(){
    const result = myMath.sum(4, 2);
    console.log(`the sum of 4 and 2 is ${result}`);
}

function myDifference(){
    const result = myMath.difference(4, 2);
    console.log(`the difference between 4 and 2 is ${result}`);
}

export {mySum, myDifference};
/

myMathはモジュール・オブジェクトを示し、named_exports_moduleはモジュール名です。sum()difference()の両方がmod_object_import_modmyMathスコープで使用可能です。

名前付きインポート

ECMAScript標準では、名前付きインポートを指定します。インポート名を使用するかわりに、識別子を指定するオプションもあります。

例4-7 指定した識別子を使用した名前付きインポート

CREATE OR REPLACE MLE MODULE named_imports_module
LANGUAGE JAVASCRIPT AS

import {sum, difference} from "namedExports";

function mySum(){
    const result = sum(4, 2);
    console.log(`the sum of 4 and 2 is ${result}`);
}

function myDifference(){
    const result = difference(4, 2);
    console.log(`the difference between 4 and 2 is ${result}`);
}

export {mySum, myDifference};
/

複数のモジュールが同じ識別子をエクスポートすると、ネームスペースの競合が発生することがあります。この問題を回避するために、import文で別名を指定できます。

例4-8 別名を使用した名前付きインポート

CREATE OR REPLACE MLE MODULE named_imports_alias_module 
LANGUAGE JAVASCRIPT AS

//note the use of aliases in the next line
import {sum as theSum, difference as theDifference} from "namedExports";

function mySum(){
    const result = theSum(4, 2);
    console.log(`the sum of 4 and 2 is ${result}`);
}

function myDifference(){
    const result = theDifference(4, 2);
    console.log(`the difference between 4 and 2 is ${result}`);
}

export {mySum, myDifference};
/

エクスポートされたファンクションを元の名前で参照するかわりに、別名が使用されます。

デフォルト・インポート

名前付きインポートとは異なり、デフォルト・インポートでは中カッコを使用する必要はありません。この構文上の違いは、MLEの組込みモジュールにも関連します。

例4-9 デフォルト・インポート

この例では、myMathClassのデフォルト・インポートを示します。

CREATE OR REPLACE MLE ENV default_export_env 
    IMPORTS('defaultExportModule' MODULE default_export_module);

CREATE MLE MODULE default_import_module LANGUAGE JAVASCRIPT AS

//note the lack of curly braces in the next line
import myMathClass from "defaultExportModule";

export function mySum(){
    const result = myMathClass.sum(4, 2);
    console.log(`the sum of 4 and 2 is ${result}`);
}
/

同じ手法は、SQLドライバなどのMLEの組込みモジュールの使用にも適用されます。例4-10は、JavaScriptコードでのSQLドライバの使用を示しています。

例4-10 組込みモジュールを使用したデフォルト・インポート

CREATE MLE MODULE default_import_built_in_mod 
LANGUAGE JAVASCRIPT AS

//note that there is no need to use MLE environments with built-in modules
import oracledb from "mle-js-oracledb";

export function hello(){
    const options = {
        resultSet: false,
        outFormat: oracledb.OUT_FORMAT_OBJECT
    };
    const bindvars = [];

const conn = oracledb.defaultConnection();
const result = conn.execute('select user', bindvars, options);
console.log(`hello, ${result.rows[0].USER}`);
}
/

カスタムのJavaScriptモジュールを使用する他の例とは異なり、組込みモジュールのインポートにMLE環境は必要ありません。

関連項目:

組込みJavaScriptモジュールの詳細は、サーバー側JavaScript APIのドキュメントを参照してください