From e7ca43458800fa7601bd4c043f619bfb5bfb1a43 Mon Sep 17 00:00:00 2001 From: martin bach Date: Mon, 22 May 2023 09:52:39 +0200 Subject: [PATCH 1/5] add javascript category page --- docs/modules/categories/pages/javascript/index.adoc | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 docs/modules/categories/pages/javascript/index.adoc diff --git a/docs/modules/categories/pages/javascript/index.adoc b/docs/modules/categories/pages/javascript/index.adoc new file mode 100644 index 0000000..4dab782 --- /dev/null +++ b/docs/modules/categories/pages/javascript/index.adoc @@ -0,0 +1,3 @@ += Javascript + +Oracle Database supports a rich set of languages for writing user-defined functions and stored procedures, including PL/SQL, Java, and C. With Oracle Database Multilingual Engine (MLE), developers have the option to run JavaScript code through dynamic execution or with persistent MLE modules stored directly in the database. \ No newline at end of file From f9c6f6e317e37afd7a9bc806924fe6bb113a3fab Mon Sep 17 00:00:00 2001 From: martin bach Date: Mon, 22 May 2023 09:53:40 +0200 Subject: [PATCH 2/5] add Javascript to the list of categories --- docs/modules/categories/pages/index.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/modules/categories/pages/index.adoc b/docs/modules/categories/pages/index.adoc index d56baa1..74591ac 100644 --- a/docs/modules/categories/pages/index.adoc +++ b/docs/modules/categories/pages/index.adoc @@ -1,4 +1,5 @@ = Categories +* xref:javascript/index.adoc[] * xref:plsql/index.adoc[] * xref:sql/index.adoc[] From 9dedf3fcb79716bacf8065fba6a718bd1646d697 Mon Sep 17 00:00:00 2001 From: martin bach Date: Mon, 22 May 2023 16:03:20 +0200 Subject: [PATCH 3/5] add javascript category --- .../categories/pages/javascript/index.adoc | 2 +- features/inline-javascript.adoc | 71 ++++++++ features/javascript-call-specifications.adoc | 90 ++++++++++ features/javascript-environments.adoc | 137 ++++++++++++++++ features/javascript-modules.adoc | 155 ++++++++++++++++++ 5 files changed, 454 insertions(+), 1 deletion(-) create mode 100644 features/inline-javascript.adoc create mode 100644 features/javascript-call-specifications.adoc create mode 100644 features/javascript-environments.adoc create mode 100644 features/javascript-modules.adoc diff --git a/docs/modules/categories/pages/javascript/index.adoc b/docs/modules/categories/pages/javascript/index.adoc index 4dab782..209d0cb 100644 --- a/docs/modules/categories/pages/javascript/index.adoc +++ b/docs/modules/categories/pages/javascript/index.adoc @@ -1,3 +1,3 @@ = Javascript -Oracle Database supports a rich set of languages for writing user-defined functions and stored procedures, including PL/SQL, Java, and C. With Oracle Database Multilingual Engine (MLE), developers have the option to run JavaScript code through dynamic execution or with persistent MLE modules stored directly in the database. \ No newline at end of file +Oracle Database supports a rich set of languages for writing user-defined functions and stored procedures, including PL/SQL, Java, and C. With Oracle Database Multilingual Engine (MLE), developers have the additional option to run JavaScript code in Oracle Database 23c Free-Developer Release on Linux x86-64. \ No newline at end of file diff --git a/features/inline-javascript.adoc b/features/inline-javascript.adoc new file mode 100644 index 0000000..ad24a79 --- /dev/null +++ b/features/inline-javascript.adoc @@ -0,0 +1,71 @@ += Inline JavaScript Procedures +:database-version: 23.2.0 +:database-category: javascript + +[[feature_summary]] + +Inlined JavaScript procedures allow you to embed JavaScript code directly in the `CREATE FUNCTION` and `CREATE PROCEDURE` statements without the need of creating a link:javascript-modules.html[module] first. + +If you want to implement a less complex JavaScript feature quickly, inlined procedures and functions are a good choice. The following example coverts seconds-since-epoch to an Oracle Date. + +[source,sql] +[subs="verbatim"] +---- +create or replace function epoch_to_Date ( + P_EPOCH number +) return date +as mle language javascript +q'~ + let d = new Date(0); + d.setUTCSeconds(P_EPOCH); + + return d; +~'; +/ + +select + to_char( + epoch_to_date(1684758614), + 'yyyy-mm-dd hh24:mi:ss' + ) the_date; + +---- + +.Result +[source,sql] +[subs="verbatim"] +---- +SQL> create or replace function epoch_to_date ( + 2 P_EPOCH number + 3 ) return date + 4 as mle language javascript + 5 q'~ + 6 let d = new Date(0); + 7 d.setUTCSeconds(P_EPOCH); + 8 + 9 return d; + 10 ~'; + 11 / + +Function created. + +SQL> +SQL> select + 2 to_char( + 3 epoch_to_date(1684758614), + 4 'yyyy-mm-dd hh24:mi:ss' + 5 ) the_date; + +THE_DATE +------------------- +2023-05-22 12:30:14 +---- + +== Benefits + +Inline JavaScript functions and procedures are a convenient way of exposing functionality in JavaScript to SQL and PL/SQL. You aren't limited to using built-in JavaScript objects, you are free to perform any manipulation you like. If more complex processing, including importing 3rd party JavaScript modules is required you should use modules and environments instead. + +== Further information + +* Availability: All Offerings +* https://docs.oracle.com/en/database/oracle/oracle-database/23/mlejs/calling-mle-js-functions.html#GUID-B0BBB967-2C4E-43D0-8D38-F4962AD23FE2[Documentation] diff --git a/features/javascript-call-specifications.adoc b/features/javascript-call-specifications.adoc new file mode 100644 index 0000000..52bc9aa --- /dev/null +++ b/features/javascript-call-specifications.adoc @@ -0,0 +1,90 @@ += JavaScript Call Specifications +:database-version: 23.2.0 +:database-category: javascript + +[[feature_summary]] + +Writing JavaScript link:javascript-modules.html[modules] and link:javascript-environments.html[environments] are the first steps towards the creation of your application. Once the JavaScript code is ready you can expose it to SQL and PL/SQL thanks to a so-called link:https://docs.oracle.com/en/database/oracle/oracle-database/23/lnpls/call-specification.html#GUID-C5F117AE-E9A2-499B-BA6A-35D072575BAD[call specification]. A JavaScript call specification consists of the following: + +* the link:javascript-modules.html[module] name +* an (optional) reference to a link:javascript-environments.html[environment] +* the (simplified) JavaScript function's signature as per the link:javascript-modules.html[module] code + +All client code, regardless whether it's written in Java, Python, or even with `node-oracledb`, can access JavaScript stored procedures in the database. + +The following example demonstrates + +. The creation of a JavaScript module (`hello_module`) in the current user's schema featuring a single function named `hello()` +. The addition of a call specification `f_hello()` exposing the JavaScript function to SQL and PL/SQL +. A sample invocation of the previously defined function + +[source,sql] +[subs="verbatim"] +---- +create or replace mle module hello_module +language javascript as + +// JavaScript code to follow from here +/** + * return a friendly greeting + * @param {string} who - who should be greeted? + * @returns {string} + */ +export function hello(who) { + return 'hello ' + who; +} +/ + +create or replace function f_hello( + p_who varchar2) +return varchar2 +as mle module hello_module +signature 'hello'; +/ + +select + f_hello('JavaScript'); +---- + +.Result +[source,sql] +[subs="verbatim"] +---- +SQL> create or replace mle module hello_module + 2 language javascript as + 3 + 4 export function hello(who) { + 5 + 6 return 'hello ' + who; + 7 } + 8 / + +MLE module created. + +SQL> create or replace function f_hello( + 2 p_who varchar2) + 3 return varchar2 + 4 as mle module hello_module + 5 signature 'hello'; + 6 / + +Function created. + +SQL> select + 2 hello('JavaScript'); + +HELLO('JAVASCRIPT') +------------------------------------------------------------------------------- +hello JavaScript +---- + +== Benefits + +JavaScript Call Specifications expose JavaScript code to SQL and PL/SQL allowing any programming language with a SQL driver to make use of it. In addition to standalone functions and procedures packages can be used to create a container for call specifications originating from the same JavaScript module. + +== Further information + +* Availability: All Offerings +* link:https://docs.oracle.com/en/database/oracle/oracle-database/23/mlejs/calling-mle-js-functions.html#GUID-55400971-3660-47D7-B60C-D2F76EE0FD42[Documentation] +* https://blogs.oracle.com/developers/post/using-javascript-community-modules-in-oracle-database-23c-free-developer-release[Example] +* https://blogs.oracle.com/developers/post/introduction-javascript-oracle-database-23c-free-developer-release[Introductory Blog Post] \ No newline at end of file diff --git a/features/javascript-environments.adoc b/features/javascript-environments.adoc new file mode 100644 index 0000000..71884a2 --- /dev/null +++ b/features/javascript-environments.adoc @@ -0,0 +1,137 @@ += JavaScript Environments +:database-version: 23.2.0 +:database-category: javascript + +[[feature_summary]] + +JavaScript Environments, just like JavaScript modules, are schema objects persisted in the database. They perform a vital function in applications involving multiple JavaScript modules. Unlike `node.js` or `deno` projects JavaScript modules aren't persisted on the file system, they are stored in the database. Developers cannot simply import modules based on their location in the file system, they need to use environments instead. + +The following example demonstrates the use of environments. + + +[source,javascript] +[subs="verbatim"] +---- +create or replace MLE module module_one +language javascript as + +// this function is exported and will be called by +// module_2's greeting() function +export function hello(who) { + + return 'hello ' + who; +} +/ + +create or replace MLE module module_two +language javascript as + +// before module_1's hello() function can be imported a +// so-called import name must be defined by means of creating +// a JavaScript environment. The module name does not have to +// match the import name +import { hello } from 'module1' + +export function greeting() { + + const who = 'JavaScript'; + return hello(who); +} +/ + +// the mapping between import name and module name is defined +// in an environment +create or replace mle env example_env +imports ( + 'module1' module module_one +); + +// with the module in place it is possible to invoke module_2's +// greeting function. Refer to the section about call specifications +// for more details about invoking JavaScript code in SQL and PL/SQL +create or replace function f_greeting +return varchar2 as +mle module module_two +env example_env +signature 'greeting'; +/ + +select + f_greeting; + +---- + +.Result +[source] +[subs="verbatim"] +---- +SQL> create or replace MLE module module_one + 2 language javascript as + 3 + 4 // this function is exported and will be called by + 5 // module_2's greeting() function + 6 export function hello(who) { + 7 + 8 return 'hello ' + who; + 9 } + 10 / + +MLE module created. + +SQL> create or replace MLE module module_two + 2 language javascript as + 3 + 4 // before module_1's hello() function can be imported a + 5 // so-called import name must be defined by means of creating + 6 // a JavaScript environment. The module name does not have to + 7 // match the import name + 8 import { hello } from 'module1' + 9 + 10 export function greeting() { + 11 + 12 const who = 'JavaScript'; + 13 return hello(who); + 14 } + 15 / + +MLE module created. + +SQL> -- the mapping between import name and module name is defined +SQL> -- in an environment +SQL> create or replace mle env example_env + 2 imports ( + 3 'module1' module module_one + 4 ); + +MLE env created. + +SQL> -- with the module in place it is possible to invoke module_2's +SQL> -- greeting function. Refer to the section about call specifications +SQL> -- for more details about invoking JavaScript code in SQL and PL/SQL +SQL> create or replace function f_greeting + 2 return varchar2 as + 3 mle module module_two + 4 env example_env + 5 signature 'greeting'; + 6 / + +Function created. + +SQL> -- call the function +SQL> select + 2 f_greeting; + +F_GREETING +------------------------------------------------------------------------------- +hello JavaScript +---- + +== Benefits + +JavaScript Environments play a crucial role during the development of JavaScript stored procedures. They are most useful providing means to map an import name as used in a JavaScript module to the actual module itself. Furthermore they are essential entities for the definition of link:javascript-call-specifications.html[call specifications. ] + +== Further information + +* Availability: All Offerings +* https://docs.oracle.com/en/database/oracle/oracle-database/23/mlejs/mle-js-modules-and-environments.html#GUID-EB682328-BA26-4422-9304-62D412D28B2F[Documentation] +* https://blogs.oracle.com/developers/post/using-javascript-community-modules-in-oracle-database-23c-free-developer-release[Blog post] diff --git a/features/javascript-modules.adoc b/features/javascript-modules.adoc new file mode 100644 index 0000000..fc3cb0d --- /dev/null +++ b/features/javascript-modules.adoc @@ -0,0 +1,155 @@ += JavaScript Modules +:database-version: 23.2.0 +:database-category: javascript + +[[feature_summary]] + +A JavaScript module is the equivalent of an ECMAScript module commonly found in `node.js` and `deno` projects, but instead of storing it in a file in a file system it is persisted as a schema object in the database. + +JavaScript modules can either be provided by the community, or they can consist of specific, custom application code. JavaScript modules can reference functionality from other JavaScript modules allowing you to build complex applications that are easier to maintain. + +Just as Java stored procedures JavaScript code can be made available to SQL and PL/SQL by means of a link:javascript-call-specifications.html[call specification]. + +The following example demonstrates the creation of a JavaScript module with the code provided inline with the module definition. + +[source,javascript] +[subs="verbatim"] +---- +create or replace mle module example_module +language javascript as +// this is where the JavaScript code section begins +/** + * convert a delimited string into key-value pairs and return JSON + * @param {string} inputString - the input string to be converted + * @returns {JSON} + */ +function string2obj(inputString) { + if ( inputString === undefined ) { + throw `string must comply with a form of key1=value1;...;keyN=valueN`; + } + let myObject = {}; + if ( inputString.length === 0 ) { + return myObject; + } + const kvPairs = inputString.split(";"); + kvPairs.forEach( pair => { + const tuple = pair.split("="); + if ( tuple.length === 1 ) { + tuple[1] = false; + } else if ( tuple.length != 2 ) { + throw "parse error: you need to use exactly one '=' between " + + "key and value and not use '=' in either key or value"; + } + myObject[tuple[0]] = tuple[1]; + }); + return myObject; +} + +/** + * convert a JavaScript object to a string + * @param {object} inputObject - the object to transform to a string + * @returns {string} + */ +function obj2String(inputObject) { + if ( typeof inputObject != 'object' ) { + throw "inputObject isn't an object"; + } + return JSON.stringify(inputObject); +} + +export { string2obj, obj2String } +/ +---- + +.Result + +When executing the above statement in `sqlplus` or `sqlcl` you will get a message that the MLE module has been successfully created. + +Verify the module has been created as follows: + +[source,sql] +[subs="verbatim"] +---- +select + module_name, + language_name +from + user_mle_modules +where + module_name = 'EXAMPLE_MODULE' + +MODULE_NAME LANGUAGE_NAME +------------------------------ ------------------------------ +EXAMPLE_MODULE JAVASCRIPT +---- + + +You can also view the source code of the JavaScript module: + +[source] +[subs="verbatim"] +---- +select + text +from + user_source +where + name = 'EXAMPLE_MODULE' +order by + line; + +TEXT +-------------------------------------------------------------------------------- +// this is where the JavaScript code section begins +/** + * convert a delimited string into key-value pairs and return JSON + * @param {string} inputString - the input string to be converted + * @returns {JSON} + */ +function string2obj(inputString) { + if ( inputString === undefined ) { + throw `string must comply with a form of key1=value1;...;keyN=valueN`; + } + let myObject = {}; + if ( inputString.length === 0 ) { + return myObject; + } + const kvPairs = inputString.split(";"); + kvPairs.forEach( pair => { + const tuple = pair.split("="); + if ( tuple.length === 1 ) { + tuple[1] = false; + } else if ( tuple.length != 2 ) { + throw "parse error: you need to use exactly one '=' between " + + "key and value and not use '=' in either key or value"; + } + myObject[tuple[0]] = tuple[1]; + }); + return myObject; +} + +/** + * convert a JavaScript object to a string + * @param {object} inputObject - the object to transform to a string + * @returns {string} + */ +function obj2String(inputObject) { + if ( typeof inputObject != 'object' ) { + throw "inputObject isn't an object"; + } + return JSON.stringify(inputObject); +} + +export { string2obj, obj2String } +---- + +== Benefits + +Storing processing logic _inside_ the database rather than in the middle-tier provides numerous advantages especially when it comes to latency, security, auditing, data integrity, and many more. It also helps developers realise the complete database feature set. + +== Further information + +* Availability: All Offerings +* https://docs.oracle.com/en/database/oracle/oracle-database/23/mlejs/index.html[Documentation] +* https://blogs.oracle.com/developers/post/using-javascript-community-modules-in-oracle-database-23c-free-developer-release[Example] +* https://blogs.oracle.com/developers/post/introduction-javascript-oracle-database-23c-free-developer-release[Feature Introduction] \ No newline at end of file From c587c926531b466a5d76d2c89a620ae0e06fd933 Mon Sep 17 00:00:00 2001 From: martin bach Date: Mon, 22 May 2023 16:03:52 +0200 Subject: [PATCH 4/5] local antora invocation to avoid a global install --- generate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generate.sh b/generate.sh index d615705..0bbb6d5 100755 --- a/generate.sh +++ b/generate.sh @@ -6,4 +6,4 @@ java .github/scripts/generate_navigation.java "$(pwd)" echo "" echo "🛠️ Building site" echo "Please wait..." -antora local-playbook.yml +npx antora local-playbook.yml From 4204bc2836dce8e41354652220f8a8c2109262fa Mon Sep 17 00:00:00 2001 From: Gerald Venzl Date: Tue, 23 May 2023 08:30:13 -0700 Subject: [PATCH 5/5] User proper case for JS, don't specify current release status Signed-off-by: Gerald Venzl --- docs/modules/categories/pages/javascript/index.adoc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/modules/categories/pages/javascript/index.adoc b/docs/modules/categories/pages/javascript/index.adoc index 209d0cb..7c31cec 100644 --- a/docs/modules/categories/pages/javascript/index.adoc +++ b/docs/modules/categories/pages/javascript/index.adoc @@ -1,3 +1,4 @@ -= Javascript += JavaScript -Oracle Database supports a rich set of languages for writing user-defined functions and stored procedures, including PL/SQL, Java, and C. With Oracle Database Multilingual Engine (MLE), developers have the additional option to run JavaScript code in Oracle Database 23c Free-Developer Release on Linux x86-64. \ No newline at end of file +Oracle Database supports a rich set of languages for writing user-defined functions and stored procedures, including PL/SQL, Java, and C. +With Oracle Database Multilingual Engine (MLE), developers have the additional option to run JavaScript code starting with Oracle Database 23c.