さて、JavaScriptでコードを記述しようと思っても、Node.jsのnpmで配布されているようなパッケージが無い、となると相当に大変な作業になってしまいます。
Oracle Database 23aiのMLEモジュールは、基本的にESモジュールです。npmのパッケージをESモジュールとして取得すれば、(原則的に)それをもとにMLEモジュールを作成できます。
CDNのjsDelivrでは、NPMパッケージを取得するURLの末尾に+esmを付加することにより、そのパッケージをESモジュールの形式で返してくれます。
今回はJavaScriptを清書するパッケージpretty-jsをデータベースにロードしてみます。
pretty-jsをESモジュールとして取得するURLは以下になります。
CDNからESモジュールを取得し、MLEモジュールとして作成するAPEXアプリケーションを作成しています。相当にやっつけ仕事ですが、何もないよりは遥かに良いです。エクスポートは以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/mle-module-manager.zip
以下のGIF動画のように操作します。
- Module Nameにpretty-jsを指定し、Add Moduleをクリックします。jsDelivrからpretty-jsをESモジュールとして取得し、MLEモジュールの作成対象として追加します。
- Resolve Onceをクリックします。pretty-jsのESモジュールのコードを読んで、importされているESモジュールを、MLEモジュールの作成対象として追加します。
- 追加されたESモジュールを再帰的に解析するようにはしていないので、ESモジュールがすべて解析されるまで、Resolve Onceを複数回クリックします。
- Create Mle Modulesをクリックし、jsDelivrから取得したESモジュールを元にMLEモジュールを作成します。
- MLE Envに指定されているMLE環境(なければ新規作成)に、作成したMLEモジュールのインポートを追加します。
動作確認のために、以下のコードを実行しています。
const { default:prettyJs } = await import("/npm/pretty-js@0.2.2/+esm");
const { fetch } = await import("mle-js-fetch");
fetch('https://cdn.jsdelivr.net/npm/pretty-js@0.2.2/+esm')
.then(response => {
return response.text();
})
.then(text => {
console.log(prettyJs(text));
});
ほとんどの処理は、記事の末尾に添付したパッケージUTL_MLE_NPMに実装しています。APEXアプリケーションのボタンをクリックすると、対応したUTL_MLE_NPMのプロシージャを呼び出します(プロセスのタイプがAPI呼出し)。
- ボタンINITだけはUTL_MLE_NPMではなく、APEX_COLLECTION.CREATE_OR_TRUNCATE_COLLECTIONを呼び出し、APEXコレクションMLE_MODULESを初期化します。
- ボタンADD_ES_MODULEは、UTL_MLE_NPM.ADD_MODULEを呼び出します。
- ボタンRESOLVE_ONCEは、UTL_MLE_NPM.RESOLVE_ONCEを呼び出します。
- ボタンCREATE_MLE_MODULESは、UTL_MLE_NPM.CREATE_MLE_MODULESを呼び出します。
- ボタンADD_IMPORTSは、UTL_MLE_NPM.ADD_IMPORTSを呼び出します。
- ボタンDROP_MLE_ENVは、drop mle env MLE環境名を実行します。
- ボタンDROP_MLE_MODULESは、UTL_MLE_NPM.DROP_MLE_MODULES_ESMを呼び出します。
ボタンに対応したプロセスが作成されています。
上記の例ではpretty-jsをMLEモジュールとして作成しましたが、元々はjimpをロードするために、このアプリケーションを作成しました。
Module Nameにjimpを入力し、Add Es Moduleをクリックします。ESモジュールは以下のURLから取得しています。
https://cdn.jsdelivr.net/npm/jimp/+esm
バージョンを指定していないため、ESモジュールの内容からバージョンを取り出しています。
レポートの列C001はモジュール名、C002はバージョンです。列C007はMLEモジュール名です。ESモジュールの名前は記号(例えば@)で始まることもあるため、MLEモジュール名は必ずESM_で開始するようにしています。また、MLEモジュールにはバージョン情報を付けることができますが、同じモジュール名でバージョンが異なるモジュールは作成できないようです。同じモジュールでもバージョンが異なるものを別のMLEモジュールとして作成できるように、MLEモジュール名にはバージョンを付加しています。
列N001は0の場合は、MLEモジュールとして未作成、1の場合は作成済み、列N002は0の場合はソースコードは未解析、1の場合は解析済み(インポートしているESモジュールがAPEXコレクションに追加済み)です。
ボタンResolve Onceをクリックします。
列C001のjimpの列N002が1になり(つまり解析済み)、@jimp/custom、@jimp/types、@jimp/pluginsが行として追加されます。これらの列N002は0で、まだ解析されていません。
再度Resolve Onceをクリックします。@jimp/custom、@jimp/types、@jimp/pluginsの内容が解析され(列N002は1になります)、インポートされていたESモジュールがAPEXコレクションに追加されます。
同じ操作(Resolve Onceのクリック)を、列N002の値がすべて1(ESモジュールの取得に失敗しているものを除く)になるまで繰り返します。
列C002(バージョン)が空白のESモジュールが2つあります。@jimp/coreとgifwrapです。
バージョンが取れないのは、jsDelivrの側でESモジュールのコード生成に失敗しているためです。生成されたコードを確認します。
https://cdn.jsdelivr.net/npm/@jimp/core/+esm
https://cdn.jsdelivr.net/npm/gifwrap/+esm
両方ともに以下のような出力になっています。どのようなNPMでも、ESモジュールにできるわけではないようです。
/**
* Failed to bundle using Rollup v2.79.1: the file imports a not supported node.js built-in module "fs".
* If you believe this to be an issue with jsDelivr, and not with the package itself, please open an issue at https://github.com/jsdelivr/jsdelivr
*/
throw new Error('Failed to bundle using Rollup v2.79.1: the file imports a not supported node.js built-in module "fs". If you believe this to be an issue with jsDelivr, and not with the package itself, please open an issue at https://github.com/jsdelivr/jsdelivr');
また、MLEモジュールとして作成できていても、インポートして使おうとするとエラーが発生する場合もあります。MLE環境に追加されたインポート名より、MLEモジュールをインポートする文を生成します。MLE環境はMYENVとしてます。
select '// const e' || rownum || ' = await import("' || import_name || '");' from user_mle_env_imports where env_name = 'MYENV'
以下のインポートを実行してみます。
const e5 = await import("/npm/@jimp/custom@0.22.12/+esm");
以下のエラーが発生します。モジュール@jimp/coreはESモジュールの生成に失敗しているため、MLEモジュールとして作成できていません。@jimp/coreのコードを修正する以外に対応方法は無いと思われます。
ORA-04161: Error: Cannot load ES module: /npm/@jimp/core@0.22.12/+esm
以下のインポートを実行してみます。
const e49 = await import("/npm/xml-parse-from-string@1.0.1/+esm");
以下のエラーが発生しました。
ORA-04161: ReferenceError: self is not defined
ORA-06512: "APEX_230200.WWV_FLOW_CODE_EXEC_MLE", 行728
ORA-04171: 場所:module:eval (WKSP_APEXDEV.ESM_XML_PARSE_FROM_STRING_1_0_1:7:16)
ESモジュールのコードを確認してみます。
https://cdn.jsdelivr.net/npm/xml-parse-from-string@1.0.1/+esm
コード中でMicrosoft.XMLDOMを参照している模様です。Oracle Database上ではエラーが発生するのは仕方がなさそうです。
/**
* Bundled by jsDelivr using Rollup v2.79.1 and Terser v5.19.2.
* Original file: /npm/xml-parse-from-string@1.0.1/index.js
*
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
*/
var e=void 0!==self.DOMParser?function(e){return(new self.DOMParser).parseFromString(e,"application/xml")}:void 0!==self.ActiveXObject&&new self.ActiveXObject("Microsoft.XMLDOM")?function(e){var r=new self.ActiveXObject("Microsoft.XMLDOM");return r.async="false",r.loadXML(e),r}:function(e){var r=document.createElement("div");return r.innerHTML=e,r};export{e as default};
//# sourceMappingURL=/sm/be5cb35a93829eb0b811add8f6983796069c4d7086c8acebcc12b0d69a3be01d.map
最終的にjimpはロードできなかったのは残念ですが、依存関係のあるNPMモジュールからMLEモジュールを作成する作業は、それなりに効率的にできるようになりました。
今回の記事は以上になります。
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完
UTL_MLE_NPMパッケージ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
create or replace package utl_mle_npm | |
as | |
/** | |
* ESモジュールのロードからMLEモジュールの作成までに取り得る状態。 | |
*/ | |
C_MODULE_NA constant varchar2(8) := 'NA'; | |
C_MODULE_LOADED constant varchar2(8) := 'LOADED'; | |
C_MODULE_RESOLVED constant varchar2(8) := 'RESOLVED'; | |
C_MODULE_VALID constant varchar2(8) := 'VALID'; | |
C_MODULE_INVALID constant varchar2(8) := 'INVALID'; | |
/** | |
* MLEモジュールとして作成する予定のESモジュールを、APEXコレクションに追加する。 | |
*/ | |
procedure add_module( | |
p_collection_name in varchar2 | |
,p_module_name in varchar2 | |
,p_module_version in varchar2 default null | |
,p_module_path in varchar2 default null | |
,p_parent_module_name in varchar2 default null | |
,p_parent_module_version in varchar2 default null | |
,p_parent_module_path in varchar2 default null | |
); | |
/** | |
* APEXコレクションに含まれているESモジュールで、そのモジュールがインポートしている | |
* ESモジュールの解析が終わっていないものを対象にして解析する。 | |
*/ | |
procedure resolve_once( | |
p_collection_name in varchar2 | |
); | |
/** | |
* APEXコレクションに追加されているESモジュールより、MLEモジュールを作成する。 | |
*/ | |
procedure create_mle_modules( | |
p_collection_name in varchar2 | |
,p_replace in boolean | |
); | |
/** | |
* MLE環境にインポートを追加する。 | |
*/ | |
procedure add_imports_to_mle_env( | |
p_collection_name in varchar2 | |
,p_mle_env in varchar2 | |
); | |
/** | |
* drop all MLE modules if the name start with 'ESM__' | |
*/ | |
procedure drop_mle_modules_esm; | |
end utl_mle_npm; | |
/ |
jsdelivr向け実装
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
create or replace package body utl_mle_npm | |
as | |
C_PROVIDER_URL constant varchar2(80) := 'https://cdn.jsdelivr.net/npm/%s/+esm'; | |
C_IMPORT_PRE constant varchar2(20) := '/npm/'; | |
C_IMPORT_POST constant varchar2(8) := '/+esm'; | |
C_ORIGINAL_FILE_LINE constant varchar2(20) := 'Original file: /npm/'; | |
C_MLE_ENV_FOR_PRETTY_PRINT constant varchar2(30) := 'MLE_ENV_FOR_PRETTY_PRINT'; | |
/** | |
* Pretty print the moudle source. | |
* | |
* Prerequisites: | |
* - An MLE module named '/npm/pretty-js@0.2.2/+esm' must exist. | |
* - An MLE Environment containing this module must be defined in the | |
* Application Setting 'MLE_ENV_FOR_PRETTY_PRINT'. | |
* | |
* Note: This functionality is currently only applicable to jsdelivr. | |
*/ | |
function make_pretty( | |
p_source in clob | |
,p_module in varchar2 default '/npm/pretty-js@0.2.2/+esm' | |
) | |
return clob | |
as | |
l_ctx dbms_mle.context_handle_t; | |
C_CODE constant clob := q'~ | |
(async() => { | |
const bindings = await import("mle-js-bindings"); | |
const { default:prettyJs } = await import("#MODULE#"); | |
const source = bindings.importValue("source"); | |
const pretty = prettyJs(source.getData()); | |
bindings.exportValue("pretty", pretty); | |
})(); | |
~'; | |
l_code clob; | |
l_pretty clob; | |
l_environment varchar2(80); | |
begin | |
l_environment := apex_app_setting.get_value( | |
p_name => C_MLE_ENV_FOR_PRETTY_PRINT | |
); | |
-- apex_debug.info('MLE Env for Pretty Print, %s', l_environment); | |
/* | |
* Do nothing without Application Setting. | |
*/ | |
if l_environment is null then | |
return p_source; | |
end if; | |
/* | |
* Do pretty print by calling pretty-js. | |
*/ | |
l_ctx := dbms_mle.create_context( | |
environment => l_environment | |
); | |
l_code := replace(C_CODE, '#MODULE#', p_module); | |
-- apex_debug.info('Code for Pretty Print, %s', l_code); | |
dbms_mle.export_to_mle(l_ctx, 'source', p_source); | |
dbms_mle.eval(l_ctx, 'JAVASCRIPT', l_code); | |
dbms_mle.import_from_mle(l_ctx, 'pretty', l_pretty); | |
dbms_mle.drop_context(l_ctx); | |
return l_pretty; | |
exception | |
when others then | |
/* preserve the orignal source when pretty-print is failed. */ | |
return p_source; | |
end make_pretty; | |
/** | |
* Retrieve module version from the source code of ES module. | |
* If version could not be retrieved, mainly because jsdelivr failed to generate ES module. | |
*/ | |
function get_version_from_source( | |
p_source clob | |
) | |
return varchar2 | |
as | |
l_start integer; | |
l_end integer; | |
l_file varchar2(80); | |
l_version varchar2(80); | |
begin | |
l_start := dbms_lob.instr( | |
lob_loc => p_source | |
,pattern => C_ORIGINAL_FILE_LINE | |
); | |
l_end := dbms_lob.instr( | |
lob_loc => p_source | |
,pattern => apex_application.LF | |
,offset => l_start | |
); | |
l_file := dbms_lob.substr( | |
lob_loc => p_source | |
,amount => (l_end - l_start - length(C_ORIGINAL_FILE_LINE)) | |
,offset => (l_start + length(C_ORIGINAL_FILE_LINE)) | |
); | |
-- dbms_output.put_line(apex_string.format('start %s end %s file %s', l_start, l_end, l_file)); | |
/* | |
* separator between module name and version is '@' but the module name | |
* could start with '@'. | |
* When module name is stared with '@', it is not treated as a separator. | |
*/ | |
if l_file like '@%' then | |
l_start := instr(l_file, '@', 1, 2); | |
else | |
l_start := instr(l_file, '@', 1, 1); | |
end if; | |
l_end := instr(l_file, '/', l_start, 1); | |
l_version := substr(l_file, (l_start + 1), (l_end - l_start - 1)); | |
return l_version; | |
end get_version_from_source; | |
/** | |
* Extracts module names, versions, and paths from import statements within ES module source code. | |
* Valid only with ES modules generated by jsDelivr. | |
*/ | |
procedure get_name_and_version_from_import( | |
p_import in varchar2 | |
,p_module_name out varchar2 | |
,p_module_version out varchar2 | |
,p_module_path out varchar2 | |
) | |
as | |
l_start integer; | |
l_end integer; | |
l_line varchar2(32767); | |
begin | |
l_start := instr(p_import, C_IMPORT_PRE); | |
if l_start = 0 then | |
p_module_name := null; | |
p_module_version := null; | |
return; | |
end if; | |
l_line := substr(p_import, (l_start + length(C_IMPORT_PRE))); | |
if l_line like '@%' then | |
l_end := instr(l_line, '@', 1, 2); | |
else | |
l_end := instr(l_line, '@', 1, 1); | |
end if; | |
if l_end = 0 then | |
p_module_name := null; | |
p_module_version := null; | |
return; | |
end if; | |
p_module_name := substr(l_line, 1, (l_end - 1)); | |
l_line := substr(l_line, (l_end + 1)); | |
l_end := instr(l_line, C_IMPORT_POST); | |
if l_end = 0 then | |
p_module_name := null; | |
p_module_version := null; | |
return; | |
end if; | |
l_line := substr(l_line, 1, (l_end - 1)); | |
l_start := instr(l_line, '/'); | |
if l_start > 0 then | |
/* version and path exists */ | |
p_module_version := substr(l_line, 1, (l_start - 1)); | |
p_module_path := substr(l_line, (l_start + 1)); | |
else | |
/* version only */ | |
p_module_version := l_line; | |
p_module_path := null; | |
end if; | |
end get_name_and_version_from_import; | |
/** | |
* Generate the name for MLE module based on the ES module name, version, and path. | |
*/ | |
function generate_mle_module_name( | |
p_module_name in varchar2 | |
,p_module_version in varchar2 | |
,p_module_path in varchar2 | |
) | |
return varchar2 | |
as | |
l_module_name varchar2(128); | |
begin | |
/* | |
* ES module name might start with '@' but MLE module name should begin with A-Z. | |
* Prepend ESM_ to all MLE module name to ensure the name begin with A-Z. | |
*/ | |
l_module_name := 'ESM_' || p_module_name || '@' || p_module_version; | |
if p_module_path is not null then | |
l_module_name := l_module_name || '_' || p_module_path; | |
end if; | |
l_module_name := upper(translate(l_module_name, '@./-', '____')); | |
return l_module_name; | |
end generate_mle_module_name; | |
/** | |
* Generates the name of an MLE module based on the ES module name, version, and path. | |
*/ | |
procedure add_module( | |
p_collection_name in varchar2 | |
,p_module_name in varchar2 | |
,p_module_version in varchar2 default null | |
,p_module_path in varchar2 default null | |
,p_parent_module_name in varchar2 default null | |
,p_parent_module_version in varchar2 default null | |
,p_parent_module_path in varchar2 default null | |
) | |
as | |
l_provider_url varchar2(200); | |
l_source clob; | |
l_module_version varchar2(80); | |
l_mle_module_name varchar2(128); | |
l_module_status varchar2(8) := C_MODULE_NA; | |
l_seq_id number; | |
begin | |
/* | |
* If no version is specified, the latest version is fetched. The version number is extracted from the source code. | |
*/ | |
if p_module_version is null then | |
l_provider_url := apex_string.format(C_PROVIDER_URL, p_module_name); | |
elsif p_module_path is null then | |
l_provider_url := apex_string.format(C_PROVIDER_URL, p_module_name || '@' || p_module_version); | |
else | |
l_provider_url := apex_string.format(C_PROVIDER_URL, p_module_name || '@' || p_module_version || '/' || p_module_path); | |
end if; | |
-- dbms_output.put_line(l_jsdelivr_url); | |
/* | |
* Get module source as ES moudle by calling jsDelivr. | |
*/ | |
apex_web_service.clear_request_headers(); | |
apex_debug.info('Request to get source: %s', l_provider_url); | |
l_source := apex_web_service.make_rest_request( | |
p_url => l_provider_url | |
,p_http_method => 'GET' | |
); | |
apex_debug.info('Response: %s', apex_web_service.g_status_code); | |
if apex_web_service.g_status_code = 200 then | |
l_module_version := get_version_from_source( | |
p_source => l_source | |
); | |
l_mle_module_name := generate_mle_module_name( | |
p_module_name => p_module_name | |
,p_module_version => l_module_version | |
,p_module_path => p_module_path | |
); | |
if l_module_version is not null then | |
l_module_status := C_MODULE_LOADED; | |
end if; | |
end if; | |
if l_module_status = C_MODULE_LOADED then | |
begin | |
select status into l_module_status from user_objects | |
where object_type = 'MLE MODULE' and object_name = l_mle_module_name; | |
exception | |
when no_data_found then | |
null; | |
end; | |
end if; | |
-- update mle module status if module is in the apex collection. | |
begin | |
select seq_id into l_seq_id from apex_collections | |
where 1=1 | |
and collection_name = p_collection_name | |
and c001 = p_module_name | |
and c002 = l_module_version | |
and ( | |
(p_module_path is null and c003 is null) | |
or | |
(c003 = p_module_path) | |
); | |
exception | |
when no_data_found then | |
l_seq_id := -1; | |
end; | |
if l_seq_id >= 0 then | |
apex_collection.update_member( | |
p_collection_name => p_collection_name | |
,p_seq => l_seq_id | |
,p_c001 => p_module_name | |
,p_c002 => l_module_version | |
,p_c003 => p_module_path | |
,p_c004 => p_parent_module_name | |
,p_c005 => p_parent_module_version | |
,p_c006 => p_parent_module_path | |
,p_c007 => l_mle_module_name | |
,p_c008 => l_module_status | |
,p_clob001 => l_source | |
); | |
else | |
apex_collection.add_member( | |
p_collection_name => p_collection_name | |
,p_c001 => p_module_name | |
,p_c002 => l_module_version | |
,p_c003 => p_module_path | |
,p_c004 => p_parent_module_name | |
,p_c005 => p_parent_module_version | |
,p_c006 => p_parent_module_path | |
,p_c007 => l_mle_module_name | |
,p_c008 => l_module_status | |
,p_clob001 => l_source | |
); | |
end if; | |
end add_module; | |
/** | |
* Extracts imported ES modules from ES module source code and adds them to an APEX collection. | |
*/ | |
procedure resolve_imported_modules( | |
p_collection_name in varchar2 | |
,p_module_name in varchar2 | |
,p_module_version in varchar2 | |
,p_module_path in varchar2 | |
) | |
as | |
l_source clob; | |
l_start integer; | |
l_end integer; | |
l_line varchar2(32767); | |
l_module_name varchar2(80); | |
l_module_version varchar2(80); | |
l_module_path varchar2(80); | |
begin | |
if p_collection_name is null then | |
/* work without APEX collection, debugging purpose only. */ | |
apex_web_service.clear_request_headers(); | |
l_source := apex_web_service.make_rest_request( | |
p_url => ( | |
case when p_module_path is null then | |
apex_string.format(C_PROVIDER_URL, p_module_name || '@' || p_module_version) | |
else | |
apex_string.format(C_PROVIDER_URL, p_module_name || '@' || p_module_version || '/' || p_module_path) | |
end) | |
,p_http_method => 'GET' | |
); | |
else | |
select clob001 into l_source | |
from apex_collections | |
where 1=1 | |
and collection_name = p_collection_name | |
and c001 = p_module_name | |
and c002 = p_module_version | |
and ( | |
(p_module_path is null and c003 is null) | |
or | |
(p_module_path = c003) | |
) | |
and c008 = C_MODULE_LOADED; | |
end if; | |
l_end := 1; | |
loop | |
l_start := dbms_lob.instr( | |
lob_loc => l_source | |
,pattern => 'import' | |
,offset => l_end | |
); | |
exit when l_start = 0; | |
l_end := dbms_lob.instr( | |
lob_loc => l_source | |
,pattern => ';' | |
,offset => l_start | |
); | |
l_line := dbms_lob.substr( | |
lob_loc => l_source | |
,amount => (l_end - l_start) | |
,offset => l_start | |
); | |
/* | |
* Extract module name, version and path from the import statement. | |
*/ | |
get_name_and_version_from_import( | |
p_import => l_line | |
,p_module_name => l_module_name | |
,p_module_version => l_module_version | |
,p_module_path => l_module_path | |
); | |
/* | |
* Add extracted module to APEX collection if both module name and version are successfully extracted. | |
*/ | |
if l_module_name is not null and l_module_version is not null then | |
add_module( | |
p_collection_name => p_collection_name | |
,p_module_name => l_module_name | |
,p_module_version => l_module_version | |
,p_module_path => l_module_path | |
,p_parent_module_name => p_module_name | |
,p_parent_module_version => p_module_version | |
,p_parent_module_path => p_module_path | |
); | |
end if; | |
l_end := l_start + 1; | |
end loop; | |
end resolve_imported_modules; | |
/** | |
* Resolve ES modules included in the APEX collection that have not yet been analyzed for their imported ES modules. | |
*/ | |
procedure resolve_once( | |
p_collection_name in varchar2 | |
) | |
as | |
begin | |
for r in ( | |
select seq_id,c001,c002,c003,c004,c005,c006,c007,c008,clob001 | |
from apex_collections | |
where collection_name = p_collection_name | |
and c008 = C_MODULE_LOADED | |
) | |
loop | |
resolve_imported_modules( | |
p_collection_name => p_collection_name | |
,p_module_name => r.c001 | |
,p_module_version => r.c002 | |
,p_module_path => r.c003 | |
); | |
apex_collection.update_member( | |
p_collection_name => p_collection_name | |
,p_seq => r.seq_id | |
,p_c001 => r.c001 | |
,p_c002 => r.c002 | |
,p_c003 => r.c003 | |
,p_c004 => r.c004 | |
,p_c005 => r.c005 | |
,p_c006 => r.c006 | |
,p_c007 => r.c007 | |
,p_c008 => C_MODULE_RESOLVED | |
,p_clob001 => r.clob001 | |
); | |
end loop; | |
end resolve_once; | |
/** | |
* Create MLE Module from ES module stored in APEX Collection. | |
*/ | |
procedure create_mle_modules( | |
p_collection_name in varchar2 | |
,p_replace in boolean | |
) | |
as | |
l_sql clob; | |
l_source clob; | |
l_module_status varchar2(8); | |
begin | |
for r in ( | |
select seq_id,c001,c002,c003,c004,c005,c006,c007,c008,clob001 | |
from apex_collections | |
where collection_name = p_collection_name | |
and c008 in (C_MODULE_RESOLVED,C_MODULE_VALID,C_MODULE_INVALID) | |
) | |
loop | |
l_source := r.clob001; | |
/* | |
* ES module from jsdelivr is minified, not human readable. | |
* if APEX application setting MLE_ENV_FOR_PRETTY_PRINT is set, do pretty print. | |
*/ | |
l_source := make_pretty(l_source); | |
/* | |
* Create MLE module from ES module. | |
*/ | |
l_sql := 'create or replace mle module ' || r.c007 || ' language javascript version ''' || r.c002 || ''' as ' || l_source || '/'; | |
-- apex_debug.info(l_sql); | |
if r.c008 = C_MODULE_RESOLVED or p_replace then -- create only if MLE module is not exist or force flag is set to true. | |
begin | |
execute immediate l_sql; | |
exception | |
when others then | |
-- module status is set from user_objects | |
null; | |
end; | |
end if; | |
/* | |
* Verify if MLE module exists and VALID. | |
*/ | |
begin | |
select status into l_module_status from user_objects | |
where object_name = r.c007 and object_type = 'MLE MODULE'; | |
exception | |
when no_data_found then | |
l_module_status := C_MODULE_NA; | |
end; | |
/* | |
* Update collection status. | |
*/ | |
apex_collection.update_member( | |
p_collection_name => p_collection_name | |
,p_seq => r.seq_id | |
,p_c001 => r.c001 | |
,p_c002 => r.c002 | |
,p_c003 => r.c003 | |
,p_c004 => r.c004 | |
,p_c005 => r.c005 | |
,p_c006 => r.c006 | |
,p_c007 => r.c007 | |
,p_c008 => l_module_status | |
,p_clob001 => l_source | |
); | |
end loop; | |
end create_mle_modules; | |
/** | |
* drop all MLE modules if the name start with 'ESM__' | |
*/ | |
procedure drop_mle_modules_esm | |
as | |
l_sql varchar2(4000); | |
begin | |
for r in ( | |
select module_name from user_mle_modules where substr(module_name, 1, 4) = 'ESM_' | |
) | |
loop | |
l_sql := 'drop mle module ' || r.module_name; | |
dbms_output.put_line(l_sql); | |
execute immediate l_sql; | |
end loop; | |
end drop_mle_modules_esm; | |
/** | |
* Add imports to MLE Environment. | |
*/ | |
procedure add_imports_to_mle_env( | |
p_collection_name in varchar2 | |
,p_mle_env in varchar2 | |
) | |
as | |
l_sql varchar2(4000); | |
l_exist number; | |
begin | |
l_sql := 'create mle env if not exists ' || p_mle_env; | |
execute immediate l_sql; | |
for r in ( | |
select | |
case when c003 is null then | |
C_IMPORT_PRE || c001 || '@' || c002 || C_IMPORT_POST | |
else | |
C_IMPORT_PRE || c001 || '@' || c002 || '/' || c003 || C_IMPORT_POST | |
end import_name | |
,c007 module_name | |
from apex_collections | |
where 1=1 | |
and collection_name = p_collection_name | |
and c008 = 'VALID' | |
and c002 is not null | |
) | |
loop | |
begin | |
select 1 into l_exist from user_mle_env_imports | |
where 1=1 | |
and import_name = r.import_name | |
and module_name = r.module_name; | |
exception | |
when no_data_found then | |
l_sql := 'alter mle env ' || p_mle_env || ' add imports(''' || r.import_name || ''' module ' || r.module_name || ')'; | |
execute immediate l_sql; | |
end; | |
end loop; | |
end add_imports_to_mle_env; | |
end utl_mle_npm; | |
/ |