From 8a9db9e49d5a756f774e0fe09e96504610422ff4 Mon Sep 17 00:00:00 2001 From: Sarah Welton Date: Thu, 30 Jan 2025 10:07:24 -0500 Subject: [PATCH 01/16] [AV-93521] Exposing UDF files to builds in prep for rewriting. --- ...r-defined-function.adoc => call-user-defined-function.adoc} | 3 --- ...-javascript-library.adoc => create-javascript-library.adoc} | 3 --- ...defined-function.adoc => create-user-defined-function.adoc} | 3 --- .../pages/{.javascript-udfs.adoc => javascript-udfs.adoc} | 3 --- modules/n1ql/partials/nav.adoc | 2 -- 5 files changed, 14 deletions(-) rename modules/guides/pages/{.call-user-defined-function.adoc => call-user-defined-function.adoc} (94%) rename modules/guides/pages/{.create-javascript-library.adoc => create-javascript-library.adoc} (97%) rename modules/guides/pages/{.create-user-defined-function.adoc => create-user-defined-function.adoc} (96%) rename modules/guides/pages/{.javascript-udfs.adoc => javascript-udfs.adoc} (94%) diff --git a/modules/guides/pages/.call-user-defined-function.adoc b/modules/guides/pages/call-user-defined-function.adoc similarity index 94% rename from modules/guides/pages/.call-user-defined-function.adoc rename to modules/guides/pages/call-user-defined-function.adoc index a92ef220a..c75d9614c 100644 --- a/modules/guides/pages/.call-user-defined-function.adoc +++ b/modules/guides/pages/call-user-defined-function.adoc @@ -1,8 +1,5 @@ = Calling a User-Defined Function :description: How to call a user-defined function from {sqlpp} statements. -ifndef::flag-devex-javascript-udfs[] -:page-embargo: EMBARGOED -endif::flag-devex-javascript-udfs[] :page-pagination: prev :page-topic-type: guide :page-toclevels: 2 diff --git a/modules/guides/pages/.create-javascript-library.adoc b/modules/guides/pages/create-javascript-library.adoc similarity index 97% rename from modules/guides/pages/.create-javascript-library.adoc rename to modules/guides/pages/create-javascript-library.adoc index d10a710f9..efa80982b 100644 --- a/modules/guides/pages/.create-javascript-library.adoc +++ b/modules/guides/pages/create-javascript-library.adoc @@ -1,8 +1,5 @@ = Creating a JavaScript Library :description: How to create a JavaScript library. -ifndef::flag-devex-javascript-udfs[] -:page-embargo: EMBARGOED -endif::flag-devex-javascript-udfs[] :page-pagination: :page-topic-type: guide :page-toclevels: 2 diff --git a/modules/guides/pages/.create-user-defined-function.adoc b/modules/guides/pages/create-user-defined-function.adoc similarity index 96% rename from modules/guides/pages/.create-user-defined-function.adoc rename to modules/guides/pages/create-user-defined-function.adoc index 4aae487e3..86a0bb84f 100644 --- a/modules/guides/pages/.create-user-defined-function.adoc +++ b/modules/guides/pages/create-user-defined-function.adoc @@ -1,8 +1,5 @@ = Creating a User-Defined Function :description: How to create a user-defined function to call external JavaScript code. -ifndef::flag-devex-javascript-udfs[] -:page-embargo: EMBARGOED -endif::flag-devex-javascript-udfs[] :page-pagination: :page-topic-type: guide :page-toclevels: 2 diff --git a/modules/guides/pages/.javascript-udfs.adoc b/modules/guides/pages/javascript-udfs.adoc similarity index 94% rename from modules/guides/pages/.javascript-udfs.adoc rename to modules/guides/pages/javascript-udfs.adoc index 012a2a00f..9fe07300d 100644 --- a/modules/guides/pages/.javascript-udfs.adoc +++ b/modules/guides/pages/javascript-udfs.adoc @@ -1,8 +1,5 @@ = User-Defined Functions with JavaScript :description: How to extend the {sqlpp} query language by adding your own functions written in JavaScript. -ifndef::flag-devex-javascript-udfs[] -:page-embargo: EMBARGOED -endif::flag-devex-javascript-udfs[] :page-pagination: next :page-topic-type: guide :page-toclevels: 2 diff --git a/modules/n1ql/partials/nav.adoc b/modules/n1ql/partials/nav.adoc index 2c0ac4549..23a27c79a 100644 --- a/modules/n1ql/partials/nav.adoc +++ b/modules/n1ql/partials/nav.adoc @@ -21,12 +21,10 @@ *** xref:guides:insert.adoc[] *** xref:guides:update.adoc[] *** xref:guides:delete.adoc[] -ifdef::flag-devex-javascript-udfs[] ** xref:guides:javascript-udfs.adoc[] *** xref:guides:create-javascript-library.adoc[] *** xref:guides:create-user-defined-function.adoc[] *** xref:guides:call-user-defined-function.adoc[] -endif::flag-devex-javascript-udfs[] ** xref:n1ql:advanced.adoc[] *** xref:n1ql:n1ql-language-reference/cost-based-optimizer.adoc[] *** xref:guides:cbo.adoc[] From 8880881ef715102c5dbb89532ea584326d416320 Mon Sep 17 00:00:00 2001 From: Sarah Emmett Date: Fri, 21 Feb 2025 16:11:01 -0500 Subject: [PATCH 02/16] [AV-93521] Starting first draft of JavaScript UDFs in Capella. Uncommenting nav entries and restoring dot files. Rewriting call a UDF and javascript-udfs intro topics. Changing dates in example files to avoid making them seem out of date. --- .../execute-javascript-function.n1ql | 2 +- .../execute-scoped-function.n1ql | 2 +- .../select-get-business-days.n1ql | 2 +- ...select-true-alias-get-business-days-cbq.sh | 5 ++ .../select-true-alias-get-business-days.n1ql | 2 +- .../pages/call-user-defined-function.adoc | 77 ++++++++++--------- .../pages/create-javascript-library.adoc | 7 +- modules/guides/pages/javascript-udfs.adoc | 22 +++--- ...adoc => calling-javascript-from-n1ql.adoc} | 3 - ...adoc => calling-n1ql-from-javascript.adoc} | 3 - ...oc => handling-errors-javascript-udf.adoc} | 3 - ... javascript-functions-with-couchbase.adoc} | 3 - modules/n1ql/partials/nav.adoc | 2 - 13 files changed, 62 insertions(+), 71 deletions(-) create mode 100644 modules/guides/examples/javascript-udfs/select-true-alias-get-business-days-cbq.sh rename modules/javascript-udfs/pages/{.calling-javascript-from-n1ql.adoc => calling-javascript-from-n1ql.adoc} (98%) rename modules/javascript-udfs/pages/{.calling-n1ql-from-javascript.adoc => calling-n1ql-from-javascript.adoc} (98%) rename modules/javascript-udfs/pages/{.handling-errors-javascript-udf.adoc => handling-errors-javascript-udf.adoc} (97%) rename modules/javascript-udfs/pages/{.javascript-functions-with-couchbase.adoc => javascript-functions-with-couchbase.adoc} (98%) diff --git a/modules/guides/examples/javascript-udfs/execute-javascript-function.n1ql b/modules/guides/examples/javascript-udfs/execute-javascript-function.n1ql index aea6b4586..d8a23f1c9 100644 --- a/modules/guides/examples/javascript-udfs/execute-javascript-function.n1ql +++ b/modules/guides/examples/javascript-udfs/execute-javascript-function.n1ql @@ -1 +1 @@ -EXECUTE FUNCTION GetBusinessDays("02/14/2022", "04/16/2022"); \ No newline at end of file +EXECUTE FUNCTION GetBusinessDays("02/14/2025", "04/16/2025"); \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/execute-scoped-function.n1ql b/modules/guides/examples/javascript-udfs/execute-scoped-function.n1ql index e7f1a0297..58d8dd163 100644 --- a/modules/guides/examples/javascript-udfs/execute-scoped-function.n1ql +++ b/modules/guides/examples/javascript-udfs/execute-scoped-function.n1ql @@ -1 +1 @@ -EXECUTE FUNCTION default:`travel-sample`.`inventory`.GetBusinessDays("03/10/2022", "05/10.2022"); \ No newline at end of file +EXECUTE FUNCTION default:`travel-sample`.`inventory`.GetBusinessDays("03/10/2025", "05/10/2025"); \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/select-get-business-days.n1ql b/modules/guides/examples/javascript-udfs/select-get-business-days.n1ql index 01e7f2f28..7dcef974c 100644 --- a/modules/guides/examples/javascript-udfs/select-get-business-days.n1ql +++ b/modules/guides/examples/javascript-udfs/select-get-business-days.n1ql @@ -1 +1 @@ -SELECT GetBusinessDays("02/14/2022", "04/16/2022"); \ No newline at end of file +SELECT GetBusinessDays("02/14/2025", "04/16/2025"); \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/select-true-alias-get-business-days-cbq.sh b/modules/guides/examples/javascript-udfs/select-true-alias-get-business-days-cbq.sh new file mode 100644 index 000000000..aca726f46 --- /dev/null +++ b/modules/guides/examples/javascript-udfs/select-true-alias-get-business-days-cbq.sh @@ -0,0 +1,5 @@ +cbq> SELECT CASE + WHEN GetBusinessDays('02/14/2025', '4/16/2025') > 44 THEN "true" + ELSE "false" + END + AS response; \ No newline at end of file diff --git a/modules/guides/examples/javascript-udfs/select-true-alias-get-business-days.n1ql b/modules/guides/examples/javascript-udfs/select-true-alias-get-business-days.n1ql index 875ecbc7e..ece198c90 100644 --- a/modules/guides/examples/javascript-udfs/select-true-alias-get-business-days.n1ql +++ b/modules/guides/examples/javascript-udfs/select-true-alias-get-business-days.n1ql @@ -1,5 +1,5 @@ SELECT CASE - WHEN GetBusinessDays('02/14/2022', '4/16/2022') > 44 THEN "true" + WHEN GetBusinessDays('02/14/2025', '4/16/2025') > 44 THEN "true" ELSE "false" END AS response; \ No newline at end of file diff --git a/modules/guides/pages/call-user-defined-function.adoc b/modules/guides/pages/call-user-defined-function.adoc index c75d9614c..8fd9e333a 100644 --- a/modules/guides/pages/call-user-defined-function.adoc +++ b/modules/guides/pages/call-user-defined-function.adoc @@ -1,81 +1,86 @@ -= Calling a User-Defined Function -:description: How to call a user-defined function from {sqlpp} statements. += Call a User-Defined Function +:description: Call a user-defined JavaScript function from the Query Tab or cbq and use it with your Capella cluster. :page-pagination: prev :page-topic-type: guide :page-toclevels: 2 :imagesdir: ../assets/images -:no-escape-hatch: +:tabs: [abstract] {description} include::ROOT:partial$component-signpost.adoc[] -== Introduction - A user-defined function can be called like any other {sqlpp} function. -== Calling the {sqlpp} User-Defined Function +== Prerequisites + +* If you want to use cbq to run your user-defined function, you must complete the prerequisites for using cbq. +For more information, see xref:n1ql:nq1l-intro/cbq.adoc#prerequisites[Prerequisites]. +* You have created a JavaScript library. +For more information, see xref:create-javascript-library.adoc[]. +* You have created a user-defined function. +For more information, see xref:created-user-defined-function.adoc[]. + +== Procedure -An {sqlpp} user-defined function can be called from anywhere that a standard {sqlpp} function can be called. +You can run user-defined functions from the Capella UI's *Query* tab or cbq. [tabs] ==== -Query Workbench:: +Query Tab:: + -- -. Access the Query Workbench UI from the Administration Console. -+ -image::javascript-udfs/select-query-tool-ui.png[,500, alt="accessing the query tool"] +To run a user-defined function from the *Query* tab: -. Set the context to match the namespace of the function you are calling. +. On the *Operational Clusters* page, select the operational cluster where you want to work with your user-defined function. +. Go to menu:Data Tools[Query]. +. Enter the {sqlpp} statement in the query editor to run your function. + -image::javascript-udfs/switch-context-to-travel-sample.png[] - -. Enter the {sqlpp} statement in the query editor to run your function: +For example, the following statement executes a function called `GetBusinessDays`, which takes 2 dates: + [source, sqlpp] ---- include::example$javascript-udfs/execute-javascript-function.n1ql[] ---- --- - -REST API:: + --- -. Open up a shell session. -. Execute a `curl` command to run the function: +You can also use a user-defined function in any {sqlpp} statement, just like a standard built-in function. +For example: + -[source, console] +[source, sqlpp] ---- -include::example$javascript-udfs/execute-scoped-function.sh[] +include::example$javascript-udfs/select-true-alias-get-business-days.n1ql[] ---- -- -{sqlpp}:: +cbq:: + -- +To run a user-defined function using the command line tool, cbq: -Run the `EXECUTE FUNCTION` function in the CBQ Shell. - +. Open a terminal window. +. Navigate to the directory where you installed cbq. +. Connect to your Capella cluster. +For more information, see xref:n1ql:nq1l-intro/cbq.adoc#cbq-connect-to-cluster[Connecting to the Cluster]. +. Run the `EXECUTE FUNCTION` command with your user-defined function. ++ +For example, the following command executes a function called `GetBusinessDays`, which takes 2 dates, on the `travel-sample`/`inventory` keyspace: ++ [source, sqlpp] ---- include::example$javascript-udfs/execute-scoped-function.n1ql[] ---- - -[NOTE] -===== -The {sqlpp} user-defined function can be used in any {sqlpp} statement in exactly the same way as a standard built-in function. - -[source, sqlpp] ++ +You can also use a user-defined function in any {sqlpp} statement, just like a standard built-in function. +For example: ++ +[source, console] ---- -include::example$javascript-udfs/select-true-alias-get-business-days.n1ql[] +include::example$javascript-udfs/select-true-alias-get-business-days-cbq.sh[] ---- -===== -- ==== - -== Related Links +== See Also include::partial$javascript-udfs/further-reading.adoc[tags="create-function;user-defined-functions"] \ No newline at end of file diff --git a/modules/guides/pages/create-javascript-library.adoc b/modules/guides/pages/create-javascript-library.adoc index efa80982b..aa34fe778 100644 --- a/modules/guides/pages/create-javascript-library.adoc +++ b/modules/guides/pages/create-javascript-library.adoc @@ -1,5 +1,5 @@ -= Creating a JavaScript Library -:description: How to create a JavaScript library. += Create a JavaScript Library +:description: Create an external library to store JavaScript functions and call them from {sqlpp}. :page-pagination: :page-topic-type: guide :page-toclevels: 2 @@ -11,9 +11,6 @@ include::ROOT:partial$component-signpost.adoc[] -== Introduction - -You can create an external library for storing JavaScript functions. When you create a new library you can add a new JavaScript function to the library at the same time. include::partial$before-you-begin.adoc[tag=body] diff --git a/modules/guides/pages/javascript-udfs.adoc b/modules/guides/pages/javascript-udfs.adoc index 9fe07300d..52d2013f8 100644 --- a/modules/guides/pages/javascript-udfs.adoc +++ b/modules/guides/pages/javascript-udfs.adoc @@ -1,5 +1,5 @@ = User-Defined Functions with JavaScript -:description: How to extend the {sqlpp} query language by adding your own functions written in JavaScript. +:description: Couchbase Capella lets you extend the {sqlpp} query language by adding your own functions written in JavaScript. :page-pagination: next :page-topic-type: guide :page-toclevels: 2 @@ -11,30 +11,28 @@ include::ROOT:partial$component-signpost.adoc[] -== Introduction +On its own, {sqlpp} includes built-in operations and functions for data manipulation. +You can use user-defined functions to create your own extensions to the language. -{sqlpp} includes a large number of built-in operations and functions that cover every aspect of data manipulation. -User-defined functions enable you to create your own extensions to the language. +With user-defined functions, you can: -Using user-defined functions, you can: - -* Create reuseable, domain-specific functions for use in your applications. +* Create reusable, domain-specific functions for use in your applications. * Execute complex logic that may be difficult to do in {sqlpp}. -* Migrate from RDBMS stored procedures. +* Migrate from Relational Database Management System (RDBMS) stored procedures. == User-Defined Functions with JavaScript -JavaScript supported in Couchbase shares the same constructs of the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript]. However, you should be aware of the restrictions and extensions that come with the Couchbase implementation. -These are covered in xref:javascript-udfs:javascript-functions-with-couchbase.adoc[] +Couchbase Capella's user-defined functions are defined with JavaScript, specifically the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript] standard, with some restrictions and extensions. +For more information, see xref:javascript-udfs:javascript-functions-with-couchbase.adoc[] == Next Steps -If you're looking to create your own JavaScript libraries, then there are a number of guides to get you started. +If you want to create your own JavaScript libraries, see: * xref:create-javascript-library.adoc[] * xref:call-user-defined-function.adoc[] -If you wish to look into the constructs and available in the language itself, then you can have a look through the following pages: +For more information about the specifics of JavaScript for user-defined functions in Capella, see: * xref:javascript-udfs:javascript-functions-with-couchbase.adoc[] * xref:javascript-udfs:calling-javascript-from-n1ql.adoc[] diff --git a/modules/javascript-udfs/pages/.calling-javascript-from-n1ql.adoc b/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc similarity index 98% rename from modules/javascript-udfs/pages/.calling-javascript-from-n1ql.adoc rename to modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc index 6ae86761b..46baad841 100644 --- a/modules/javascript-udfs/pages/.calling-javascript-from-n1ql.adoc +++ b/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc @@ -1,8 +1,5 @@ = Calling JavaScript from {sqlpp} :description: Using a {sqlpp} User-Defined Function to call JavaScript functions. -ifndef::flag-devex-javascript-udfs[] -:page-embargo: EMBARGOED -endif::flag-devex-javascript-udfs[] :page-toclevels: 2 :keywords: scopes, variadic diff --git a/modules/javascript-udfs/pages/.calling-n1ql-from-javascript.adoc b/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc similarity index 98% rename from modules/javascript-udfs/pages/.calling-n1ql-from-javascript.adoc rename to modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc index 63712b2ec..8b3e0fce4 100644 --- a/modules/javascript-udfs/pages/.calling-n1ql-from-javascript.adoc +++ b/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc @@ -1,8 +1,5 @@ = Calling {sqlpp} from JavaScript :description: Executing {sqlpp} statements from JavaScript functions. -ifndef::flag-devex-javascript-udfs[] -:page-embargo: EMBARGOED -endif::flag-devex-javascript-udfs[] :page-toclevels: 2 :stem: diff --git a/modules/javascript-udfs/pages/.handling-errors-javascript-udf.adoc b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc similarity index 97% rename from modules/javascript-udfs/pages/.handling-errors-javascript-udf.adoc rename to modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc index 8e5ce12d7..d330416cb 100644 --- a/modules/javascript-udfs/pages/.handling-errors-javascript-udf.adoc +++ b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc @@ -1,8 +1,5 @@ = Handling Errors in JavaScript Functions :description: Error handling in JavaScript user-defined functions use the same standard exception mechanism as part of the language standard. -ifndef::flag-devex-javascript-udfs[] -:page-embargo: EMBARGOED -endif::flag-devex-javascript-udfs[] :page-topic-type: reference :page-toclevels: 2 diff --git a/modules/javascript-udfs/pages/.javascript-functions-with-couchbase.adoc b/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc similarity index 98% rename from modules/javascript-udfs/pages/.javascript-functions-with-couchbase.adoc rename to modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc index 82b44b81b..3e2fab998 100644 --- a/modules/javascript-udfs/pages/.javascript-functions-with-couchbase.adoc +++ b/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc @@ -1,8 +1,5 @@ = JavaScript Functions for Query Reference :description: This reference guide describes how to write extension functions for {sqlpp} for Query using the JavaScript language. -ifndef::flag-devex-javascript-udfs[] -:page-embargo: EMBARGOED -endif::flag-devex-javascript-udfs[] :page-topic-type: reference :page-toclevels: 2 :keywords: library namespacing diff --git a/modules/n1ql/partials/nav.adoc b/modules/n1ql/partials/nav.adoc index 23a27c79a..b61a43aaf 100644 --- a/modules/n1ql/partials/nav.adoc +++ b/modules/n1ql/partials/nav.adoc @@ -157,9 +157,7 @@ *** xref:learn:services-and-indexes/indexes/early-filters-and-pagination.adoc[] *** xref:learn:services-and-indexes/indexes/index-replication.adoc[] *** xref:learn:services-and-indexes/indexes/storage-modes.adoc[] -ifdef::flag-devex-javascript-udfs[] ** xref:javascript-udfs:javascript-functions-with-couchbase.adoc[] *** xref:javascript-udfs:calling-javascript-from-n1ql.adoc[] *** xref:javascript-udfs:calling-n1ql-from-javascript.adoc[] *** xref:javascript-udfs:handling-errors-javascript-udf.adoc[] -endif::flag-devex-javascript-udfs[] From fa70e4f765d3675f36f3473551e8ed8915fc8b62 Mon Sep 17 00:00:00 2001 From: Sarah Emmett Date: Fri, 21 Mar 2025 10:16:26 -0400 Subject: [PATCH 03/16] [AV-93521] Small update to UI procedure. --- modules/guides/pages/create-user-defined-function.adoc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/guides/pages/create-user-defined-function.adoc b/modules/guides/pages/create-user-defined-function.adoc index 86a0bb84f..d236873b2 100644 --- a/modules/guides/pages/create-user-defined-function.adoc +++ b/modules/guides/pages/create-user-defined-function.adoc @@ -27,17 +27,16 @@ In this case, the JavaScript code is not stored in an external library. To create a {sqlpp} user-defined function to reference an external library, do one of the following: -* Use the xref:tools:udfs-ui.adoc[UDF UI] in the Query Workbench. +* Use the xref:tools:udfs-ui.adoc[UDF UI] in the Query Tab. * Use the {sqlpp} xref:n1ql:n1ql-language-reference/createfunction.adoc[CREATE FUNCTION] statement, and reference the external library and JavaScript function. [tabs] ==== -Query Workbench:: +Query Tab:: + -- -. Access the *UDF* screen from the administration console. -+ -image::javascript-udfs/navigate-to-udf-query.png[] +. On the *Operational Clusters* page, select the operational cluster where you want to work with your user-defined function. +. Go to menu:Data Tools[Query]. . Click on the *{plus}{nbsp}add function* link. + From 01c129ff98f4f77e78f57f42ec7b538a1a0f46fb Mon Sep 17 00:00:00 2001 From: Sarah Emmett Date: Thu, 27 Mar 2025 10:06:36 -0400 Subject: [PATCH 04/16] [AV-93521] Working commit to avoid losing work. Updating calling, creating, and overview topics for UDFs. Updating a link in the libraries-and-scopes partial. Updating links and language + permissions across the FUNCTION statements in N1QL reference. --- .../pages/call-user-defined-function.adoc | 12 +- .../pages/create-javascript-library.adoc | 121 ++++++++---------- .../pages/create-user-defined-function.adoc | 121 ++++++++++++------ modules/guides/pages/javascript-udfs.adoc | 46 ++++++- .../partials/libraries-and-scopes.adoc | 2 +- .../createfunction.adoc | 59 +-------- .../n1ql-language-reference/dropfunction.adoc | 28 +--- .../n1ql-language-reference/execfunction.adoc | 24 +--- .../explainfunction.adoc | 24 +--- 9 files changed, 192 insertions(+), 245 deletions(-) diff --git a/modules/guides/pages/call-user-defined-function.adoc b/modules/guides/pages/call-user-defined-function.adoc index 8fd9e333a..642418e47 100644 --- a/modules/guides/pages/call-user-defined-function.adoc +++ b/modules/guides/pages/call-user-defined-function.adoc @@ -17,25 +17,25 @@ A user-defined function can be called like any other {sqlpp} function. * If you want to use cbq to run your user-defined function, you must complete the prerequisites for using cbq. For more information, see xref:n1ql:nq1l-intro/cbq.adoc#prerequisites[Prerequisites]. -* You have created a JavaScript library. -For more information, see xref:create-javascript-library.adoc[]. * You have created a user-defined function. -For more information, see xref:created-user-defined-function.adoc[]. +For more information, see xref:create-user-defined-function.adoc[]. == Procedure -You can run user-defined functions from the Capella UI's *Query* tab or cbq. +You can run user-defined functions from the Query Tab or cbq. [tabs] ==== Query Tab:: + -- -To run a user-defined function from the *Query* tab: +To run a user-defined function from the Query Tab: . On the *Operational Clusters* page, select the operational cluster where you want to work with your user-defined function. . Go to menu:Data Tools[Query]. -. Enter the {sqlpp} statement in the query editor to run your function. +. Enter a {sqlpp} statement in the query editor to run your function. ++ +If you created a scoped user-defined function, make sure your xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] is set to the same bucket and scope as the namespace for your function. + For example, the following statement executes a function called `GetBusinessDays`, which takes 2 dates: + diff --git a/modules/guides/pages/create-javascript-library.adoc b/modules/guides/pages/create-javascript-library.adoc index aa34fe778..2fc6db4d6 100644 --- a/modules/guides/pages/create-javascript-library.adoc +++ b/modules/guides/pages/create-javascript-library.adoc @@ -1,5 +1,5 @@ -= Create a JavaScript Library -:description: Create an external library to store JavaScript functions and call them from {sqlpp}. += Create a User-Defined Function Library +:description: Create an user-defined function (UDF) library to store and organize your JavaScript functions. :page-pagination: :page-topic-type: guide :page-toclevels: 2 @@ -9,86 +9,71 @@ [abstract] {description} -include::ROOT:partial$component-signpost.adoc[] +To create a UDF library that you can use to xref:create-user-defined-functions.adoc[]: -When you create a new library you can add a new JavaScript function to the library at the same time. +. <> +. <> -include::partial$before-you-begin.adoc[tag=body] -include::partial$query-tools.adoc[tags=body;!thumbs] +Or, you can <>. [#creating-the-library-and-adding-your-first-function] -== Creating the Library and Adding JavaScript Code - -You can use the Query Workbench UI or the REST API to create a library. -The process for creating the library is as follows: - -include::partial$javascript-udfs/diagrams.adoc[tags=javascript-udf-library-creation-sequence] - -*(1) Create library*:: Create the library by creating the logical storage for the library. - -*(2) Add the JavaScript function to the library*:: Edit the library to add your JavaScript function. - -*(3) Create {sqlpp} User-Defined Function*:: The {sqlpp} User Defined Function is needed so that it can be called as part of {sqlpp} statements (such as `SELECT` and `EXECUTE FUNCTION`). -Creating the {sqlpp} User-Defined Function is covered in xref:create-user-defined-function.adoc[]. - -As shown in xref:create-library-udf-sequence[xrefstyle=short], the library is created and the first function is added in the same step. - -[tabs] -==== -Query Workbench:: +== Create a User-Defined Function (UDF) Library + +To create a new UDF library from the Query Tab: + +. On the *Operational Clusters* page, select the operational cluster where you want to work with user-defined functions. +. Go to menu:Data Tools[Query]. +. In the Data Insights area, to the left of the query editor, find the *Functions* section. +. Next to the *Functions* section header, click menu:Create (+)[Library]. +. In the *Library Name* field, enter a name for your new UDF library. +. Choose the access level for your UDF library: +.. Choose *Global* to allow all buckets and scopes on this cluster to use functions in this library. +.. Choose *Specific* to choose a specific bucket and scope on this cluster that can use this library. + --- +Use this bucket and scope as the namespace for xref:create-user-defined-function.adoc[your user-defined function] to use this library and its functions later. +. (Optional) Add functions to your UDF library. +See <>. +. Click btn:[Create]. -. Select btn:[Query] to access the Query Workbench, then select btn:[UDF] Query Workbench menu. -+ -image::javascript-udfs/navigate-to-udf-query.png[alt="route to the user-defined functions screen"] +[#add-functions-now] +== Add Functions to a New User-Defined Function (UDF) Library -. Click on the *{plus} add function library* link in the `JavaScript Function Libraries` table to show the `Add Library` screen. +To add functions to your new UDF library while you create your library: -. Select your `Namespace` from the drop-down lists. -In this example, the namespace has been set to the `inventory` scope inside the `travel-sample` bucket. -You also have the option of leaving the Namespace unset, which will the library accessible at the cluster level. -+ -image::javascript-udfs/add-scoped-library.png[,500] +. Do one of the following: +.. To manually define functions for your library, on the *Define Functions* tab, enter the code for each function. +.. To import a `.js` file that contains function definitions, on the *Import Library* tab, drag and drop or choose your `.js` file. + -.A Note on Namespaces -[sidebar] -**** -The `Namespace` defines the `scope` of the library within the containing bucket. -(You can read about scopes xref:clusters:data-service/scopes-collections.adoc[here].) -Setting the namespace means that functions in the library can only be called users who have their context set to the same scope. -**** +TIP: Each function should have an assigned name and follow the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript] standard. -. Enter a name for the library in the `Library Name` field. +[#add-functions-later] +== Add Functions to an Existing User-Defined Function (UDF) Library -. Add your own function to the library, for example: -+ -[source, javascript] ----- -include::example$javascript-udfs/get-business-days.js[] ----- -. Save the library by pressing the btn:[Save] button. +To add or edit functions in an existing UDF library: + +. On the *Operational Clusters* page, select the operational cluster where you want to work with user-defined functions. +. Go to menu:Data Tools[Query]. +. In the Data Insights area, to the left of the query editor, find the *Functions* section. +. Next to the user-defined library where you want to add a function, click menu:More Options (⋮)[Edit]. +. Do one of the following: +.. To manually define functions for your library, on the *Create Functions* tab, enter or edit the code for each function. +.. To import a `.js` file that contains function definitions, on the *Import Library* tab, drag and drop or choose your `.js` file. + -TIP: You can, of course, create an empty library and add functions to it later. --- +TIP: Each function should have an assigned name and follow the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript] standard. +. Click btn:[Update]. +[#delete-udf] +== Delete a User-Defined Function (UDF) Library -REST API:: -+ --- -. Start a shell session. -. Run a `curl` command to create a JavaScript library within a desired scope. -+ -[source, console] ----- -include::example$javascript-udfs/create-scoped-javascript-function-with-rest.sh[] ----- -The parameters in the URL denote that the function should reside in the `travel-sample` bucket, under the `inventory` scope within that bucket. --- -==== +To delete an existing UDF library: -When you have created an external library and added JavaScript code, you must create an {sqlpp} user-defined function to reference the JavaScript code in the library, so it can be called as part of any {sqlpp} statement. +. On the *Operational Clusters* page, select the operational cluster where you want to delete a UDF library. +. Go to menu:Data Tools[Query]. +. In the Data Insights area, to the left of the query editor, find the *Functions* section. +. Next to the user-defined library where you want to add a function, click menu:More Options (⋮)[Delete]. +. Confirm that you want to delete your UDF library. +. Click btn:[Delete Library]. -== Related Links +== Next Steps -include::partial$javascript-udfs/further-reading.adoc[tags="user-defined-functions-ui;rest-create-library-call"] +To use your JavaScript functions from {sqlpp} after you have added them to a library, see xref:create-user-defined-function.adoc[]. \ No newline at end of file diff --git a/modules/guides/pages/create-user-defined-function.adoc b/modules/guides/pages/create-user-defined-function.adoc index d236873b2..7baae5445 100644 --- a/modules/guides/pages/create-user-defined-function.adoc +++ b/modules/guides/pages/create-user-defined-function.adoc @@ -1,5 +1,5 @@ -= Creating a User-Defined Function -:description: How to create a user-defined function to call external JavaScript code. += Create a User-Defined Function +:description: Create a user-defined function (UDF) to call an inline function or JavaScript code stored in a library. :page-pagination: :page-topic-type: guide :page-toclevels: 2 @@ -10,74 +10,121 @@ [abstract] {description} -include::ROOT:partial$component-signpost.adoc[] +For more information about how to create a UDF library, see xref:create-javascript-library.adoc[]. -== Introduction +== Prerequisites -You cannot call external JavaScript code directly from a {sqlpp} query. -You must create a {sqlpp} user-defined function to reference the external JavaScript code. - -If you have created a JavaScript function in an external library (see xref:create-javascript-library.adoc[]), you must create a {sqlpp} user-defined function to reference it. - -You can also create a {sqlpp} user-defined function and the external JavaScript code in a single operation. -In this case, the JavaScript code is not stored in an external library. +* If you want to use cbq to create your user-defined function, you must complete the prerequisites for using cbq. +For more information, see xref:n1ql:nq1l-intro/cbq.adoc#prerequisites[Prerequisites]. +* If you want to use libraries to organize your user-defined functions, you need to create a UDF library and add a JavaScript function. +For more information, see xref:create-javascript-library.adoc[]. [#creating-the-n1ql-udf-function] -== Creating a {sqlpp} User-Defined Function to Reference an External Library +== Create a User-Defined Function From a UDF Library -To create a {sqlpp} user-defined function to reference an external library, do one of the following: +To create a user-defined function that references a JavaScript function from a UDF library: -* Use the xref:tools:udfs-ui.adoc[UDF UI] in the Query Tab. -* Use the {sqlpp} xref:n1ql:n1ql-language-reference/createfunction.adoc[CREATE FUNCTION] statement, and reference the external library and JavaScript function. +* Use the Query Tab. +* Use the {sqlpp} xref:n1ql:n1ql-language-reference/createfunction.adoc[CREATE FUNCTION] statement, and reference the UDF library and JavaScript function. [tabs] ==== Query Tab:: + -- -. On the *Operational Clusters* page, select the operational cluster where you want to work with your user-defined function. +. On the *Operational Clusters* page, select the operational cluster where you want to create a user-defined function from a UDF library. . Go to menu:Data Tools[Query]. -. Click on the *{plus}{nbsp}add function* link. +. In the Data Insights area, to the left of the query editor, find the *Functions* section. +. Next to the *Functions* section header, click menu:Create (+)[Function]. +. In the *Function Name* field, enter a name for your function. +. Choose the access level for your user-defined function: +.. Choose *Global* to allow all buckets and scopes on this cluster to use this function. +.. Choose *Specific* to choose a specific bucket and scope on this cluster that can use this function. + -image::javascript-udfs/my-library-list-add-function-button.png[alt="library list"] +TIP: Choose the same access level and namespace as your UDF library for your user-defined function. +Users must set this bucket and scope as their xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] to use this function later. +. In the *Parameters* field, enter a list of parameters, separated by commas (,), for any values you need to process or use in your function. + -The *Add Function* dialog is displayed. +For example, if you created a JavaScript function that has a variable named `a`, you should add a parameter `a`. +. Click the *UDF Library* tab. +. Choose the UDF library and specific JavaScript function you want to assign to this user-defined function. +. Click btn:[Create Function]. +-- + +{sqlpp}:: + -image::javascript-udfs/add-function-dialog.png[ ,400] +-- +Execute a `CREATE FUNCTION` statement in cbq to create a user-defined function: + +[source, sqlpp] +---- +include::example$javascript-udfs/create-scoped-n1ql-udf.n1ql[] +---- + +TIP: Set the same namespace as your UDF library for your user-defined function. +Users must set this bucket and scope as their xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] to use this function later. + +For more information on the `CREATE FUNCTION` statement, see xref:n1ql:n1ql-language-reference/createfunction.adoc[CREATE FUNCTION]. +-- +==== -. Use the *Namespace* drop-down lists to select the bucket and scope where your JavaScript function resides. +[#create-inline] +== Create an Inline User-Defined Function -. Fill in the *Function Name* of your {sqlpp} user-defined function. +To create a user-defined function that uses inline JavaScript or {sqlpp}: -. Specify *Parameters* for the function. +* Use the Query Tab. +* Use the {sqlpp} xref:n1ql:n1ql-language-reference/createfunction.adoc[CREATE FUNCTION] statement. + +[tabs] +==== +Query Tab:: + -NOTE: The `...` in the parameters box denotes a variable length list of parameters. +-- +. On the *Operational Clusters* page, select the operational cluster where you want to create a user-defined function. +. Go to menu:Data Tools[Query]. -. Select *JavaScript* for the function type. -A field appears in the dialog with a list of available libraries in the namespace you selected. +. In the Data Insights area, to the left of the query editor, find the *Functions* section. +. Next to the *Functions* section header, click menu:Create (+)[Function]. +. In the *Function Name* field, enter a name for your function. +. Choose the access level for your user-defined function: +.. Choose *Global* to allow all buckets and scopes on this cluster to use this function. +.. Choose *Specific* to choose a specific bucket and scope on this cluster that can use this function. + -image::javascript-udfs/add-function-dialog-switch-to-javascript.png[] +TIP: Users must set this bucket and scope as their xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] to use this function later. +. In the *Parameters* field, enter a list of parameters, separated by commas (,), for any values you need to process or use in your function. + -From this list select the library containing your function. - -. Enter the name of the JavaScript function in the `Library Function Name` field. +For example, if you created a JavaScript function that has a variable named `a`, you should add a parameter `a`. +. Click the *Inline {sqlpp}* or *Inline JavaScript* tab. +. Enter a {sqlpp} expression or JavaScript function. +. Click btn:[Create Function]. -- {sqlpp}:: + -- -Execute the `CREATE FUNCTION` in the CBQ Shell to create the {sqlpp} user-defined function: +Execute a `CREATE FUNCTION` statement in cbq to create an inline user-defined function: -[source, sqlpp] +.Inline JavaScript +[source,sqlpp] ---- -include::example$javascript-udfs/create-scoped-n1ql-udf.n1ql[] +CREATE FUNCTION celsius(...) LANGUAGE INLINE AS (args[0] - 32) * 5/9; +---- + +.Inline {sqlpp} +[source,sqlpp] ---- +CREATE FUNCTION locations(vActivity) { ( + SELECT id, name, address, city + FROM landmark + WHERE activity = vActivity) }; +---- + +For more information about the `CREATE FUNCTION` statement, see xref:n1ql:n1ql-language-reference/createfunction.adoc[CREATE FUNCTION]. -- ==== -NOTE: The {sqlpp} user-defined function will take the same scope as the JavaScript UDF it is referencing. - -== Related Links +== Next Steps -* To create a {sqlpp} user-defined function and the external JavaScript code in a single operation, see xref:n1ql:n1ql-language-reference/createfunction.adoc[CREATE FUNCTION]. +* To use your new user-defined function from {sqlpp}, see xref:call-user-defined-function.adoc[]. diff --git a/modules/guides/pages/javascript-udfs.adoc b/modules/guides/pages/javascript-udfs.adoc index 52d2013f8..d83e6da05 100644 --- a/modules/guides/pages/javascript-udfs.adoc +++ b/modules/guides/pages/javascript-udfs.adoc @@ -20,17 +20,49 @@ With user-defined functions, you can: * Execute complex logic that may be difficult to do in {sqlpp}. * Migrate from Relational Database Management System (RDBMS) stored procedures. -== User-Defined Functions with JavaScript - Couchbase Capella's user-defined functions are defined with JavaScript, specifically the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript] standard, with some restrictions and extensions. -For more information, see xref:javascript-udfs:javascript-functions-with-couchbase.adoc[] +For more information, see xref:javascript-udfs:javascript-functions-with-couchbase.adoc[]. + +== Using User-Defined Functions in Capella + +You cannot call JavaScript code directly from a {sqlpp} query. +Create a user-defined function to call JavaScript code in your queries. + +You can create 2 types of user-defined functions: + +* <>. +* <>. + +Creating a UDF library is optional, but simplifies organization and access control for your functions. + +After you have created your user-defined functions, you can xref:call-user-defined-function.adoc[] like any other {sqlpp} function. + +[#inline-functions] +=== Inline {sqlpp} Functions + +You can create a user-defined function that executes inline {sqlpp} commands or inline JavaScript. + +If you create a user-defined function this way, you cannot group related functions or change cluster access restrictions for multiple related functions at once. + +You do not need to create a library before you can create and use inline functions. + +For more information about how to create inline functions, see xref:create-user-defined-function.adoc#create-inline[Create an Inline User-Defined Function]. + +[#library-functions] +=== Functions From User-Defined Function (UDF) Libraries + +A UDF library is a collection of JavaScript functions. +Libraries keep your JavaScript functions organized and allow you to set access controls across multiple functions at once. + +You can define functions xref:create-javascript-library.adoc#add-functions-now[while creating a library] or xref:create-javascript-library.adoc#add-functions-later[add them to an existing library]. + +After you have xref:create-javascript-library.adoc[created a UDF library], you must create user-defined functions to use the JavaScript functions in that library. == Next Steps -If you want to create your own JavaScript libraries, see: - -* xref:create-javascript-library.adoc[] -* xref:call-user-defined-function.adoc[] +* To get started with a UDF library, see xref:create-javascript-library.adoc[]. +* To create inline functions, see xref:create-user-defined-function.adoc[]. +* To start using your functions in the Query Tab, see xref:call-user-defined-function.adoc[]. For more information about the specifics of JavaScript for user-defined functions in Capella, see: diff --git a/modules/javascript-udfs/partials/libraries-and-scopes.adoc b/modules/javascript-udfs/partials/libraries-and-scopes.adoc index b6bba3717..fd6621dd0 100644 --- a/modules/javascript-udfs/partials/libraries-and-scopes.adoc +++ b/modules/javascript-udfs/partials/libraries-and-scopes.adoc @@ -11,7 +11,7 @@ You can store JavaScript functions in [.term]#external libraries#. This enables you to share external function code for use in more than one {sqlpp} user-defined function. A library can contain one or more JavaScript functions. -You must create the external library and the external function code using the xref:tools:udfs-ui.adoc[Query Workbench] or the {sqlpp} xref:n1ql-rest-functions:index.adoc[Functions REST API]. +For more information about how to create a user-defined function library, see xref:guides:create-javascript-library.adoc[]. // This line left blank intentionally // end::extract[] diff --git a/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc index 0c0fab15f..5db7e40d2 100644 --- a/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc @@ -42,52 +42,13 @@ If you want to call a user-defined function outside of the current query context Finally, it is important to note that a global function is _not_ the same as a scoped function stored in the default scope in a bucket. -ifdef::flag-devex-javascript-udfs[] include::javascript-udfs:partial$libraries-and-scopes.adoc[tags=extract] -endif::flag-devex-javascript-udfs[] include::javascript-udfs:partial$sqlpp-managed-udfs.adoc[] == Prerequisites -[cols="2,3"] -|=== -| To manage ... | You must have ... - -| Global inline functions -| *Manage Global Functions* role. - -| Scoped inline functions -| *Manage Scope Functions* role, with permissions on the specified bucket and scope. - -| Global external functions -| *Manage Global External Functions* role. - -| Scoped external functions -| *Manage Scope External Functions* role, with permissions on the specified bucket and scope. -|=== - -Users with the *Manage Scope External Functions* role also have read-only access to any global external library. - -[cols="2,3"] -|=== -| To execute ... | You must have ... - -| Global inline functions -| *Execute Global Functions* role. - -| Scoped inline functions -| *Execute Scope Functions* role, with permissions on the specified bucket and scope. - -| Global external functions -| *Execute Global External Functions* role. - -| Scoped external functions -| *Execute Scope External Functions* role, with permissions on the specified bucket and scope. -|=== - -For more details about user roles, see -xref:server:learn:security/authorization-overview.adoc[Authorization]. +* To manage user-defined functions on your cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. == Syntax @@ -202,9 +163,7 @@ If you need to return multiple values, construct an array. :section: external === External Functions -ifdef::flag-devex-javascript-udfs[] There are two alternative syntaxes for defining an external function: one where the function code is stored in an external library, and one for creating a {sqlpp} managed user-defined function. -endif::flag-devex-javascript-udfs[] [source,ebnf] ---- @@ -231,31 +190,19 @@ include::createfunction.adoc[tag=arguments] [Optional] Use this parameter where the function code is stored in an external library. -ifndef::flag-devex-javascript-udfs[] -Note that Capella does not currently support a way to create or manage an external library. -endif::flag-devex-javascript-udfs[] - -ifdef::flag-devex-javascript-udfs[] The name of the JavaScript function that you want to use for the user-defined function. This parameter is a string and must be wrapped in quotes. -endif::flag-devex-javascript-udfs[] [[external-library]] ==== External Library [Optional] Use this parameter where the function code is stored in an external library. -ifndef::flag-devex-javascript-udfs[] -Note that Capella does not currently support a way to create or manage an external library. -endif::flag-devex-javascript-udfs[] - -ifdef::flag-devex-javascript-udfs[] The name of the JavaScript library that contains the JavaScript function you want to use. This parameter is a string and must be wrapped in quotes. The name of a scoped external library must include the bucket name, the scope name, and the library name, separated by slashes. For example, to refer to a scoped library called `my-library` located in the `inventory` scope within the `travel-sample` bucket, you would specify the library name as `travel-sample/inventory/my-library`. -endif::flag-devex-javascript-udfs[] [[javascript]] ==== Function Body @@ -639,9 +586,7 @@ endif::flag-devex-javascript-udfs[] == Related Links -ifdef::flag-devex-javascript-udfs[] -* To manage external libraries and external functions, see xref:n1ql-rest-functions:index.adoc[]. -endif::flag-devex-javascript-udfs[] +* To manage external libraries and external functions, see xref:guides:create-javascript-library.adoc[]. * To execute a user-defined function, see xref:n1ql-language-reference/execfunction.adoc[]. * To see the execution plan for a user-defined function, see xref:n1ql-language-reference/explainfunction.adoc[]. * To include a user-defined function in an expression, see xref:n1ql-language-reference/userfun.adoc[]. diff --git a/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc index 685b28972..d044bf59d 100644 --- a/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc @@ -12,25 +12,7 @@ include::partial$n1ql-language-reference/horizontal-style.adoc[] == Prerequisites -[cols="2,3"] -|=== -| To manage ... | You must have ... - -| Global inline functions -| *Manage Global Functions* role. - -| Scoped inline functions -| *Manage Scope Functions* role, with permissions on the specified bucket and scope. - -| Global external functions -| *Manage Global External Functions* role. - -| Scoped external functions -| *Manage Scope External Functions* role, with permissions on the specified bucket and scope. -|=== - -For more details about user roles, see -xref:server:learn:security/authorization-overview.adoc[Authorization]. +* To manage user-defined functions on your cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. == Syntax @@ -80,12 +62,10 @@ footnote:context[That is, you are dropping a global function, and the function d == Usage -ifdef::flag-devex-javascript-udfs[] When you drop a user-defined function whose definition is stored in an external library, the external library and function on which the user-defined function depended are not deleted. This enables you to create a new user-defined function with a different name, or a different number of parameters, using the same JavaScript library and function. -To change or delete an external library or the external function code, you must use the {sqlpp} xref:n1ql-rest-functions:index.adoc[Functions REST API]. -endif::flag-devex-javascript-udfs[] +To change or delete an external library or the external function code, see xref:guides:create-javascript-library.adoc#delete-udf[Delete a User-Defined Function Library]. When you drop a {sqlpp} managed user-defined function, the associated external function code is deleted also. @@ -154,9 +134,7 @@ endif::flag-devex-javascript-udfs[] == Related Links * To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. -ifdef::flag-devex-javascript-udfs[] -* To manage external libraries and external functions, see xref:n1ql-rest-functions:index.adoc[]. -endif::flag-devex-javascript-udfs[] +* To manage external libraries and external functions, see xref:guides:create-javascript-library.adoc[]. * To execute a user-defined function, see xref:n1ql-language-reference/execfunction.adoc[]. * To see the execution plan for a user-defined function, see xref:n1ql-language-reference/explainfunction.adoc[]. * To include a user-defined function in an expression, see xref:n1ql-language-reference/userfun.adoc[]. diff --git a/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc index eef2abdd2..752463c21 100644 --- a/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc @@ -21,25 +21,7 @@ If you do this, error `10101: Function not found` is generated. == Prerequisites -[cols="2,3"] -|=== -| To execute ... | You must have ... - -| Global inline functions -| *Execute Global Functions* role. - -| Scoped inline functions -| *Execute Scope Functions* role, with permissions on the specified bucket and scope. - -| Global external functions -| *Execute Global External Functions* role. - -| Scoped external functions -| *Execute Scope External Functions* role, with permissions on the specified bucket and scope. -|=== - -For more details about user roles, see -xref:server:learn:security/authorization-overview.adoc[Authorization]. +* To manage user-defined functions on your cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. == Syntax @@ -92,9 +74,7 @@ For examples, refer to xref:n1ql-language-reference/createfunction.adoc#examples == Related Links * To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. -ifdef::flag-devex-rest-api[] -* To manage external libraries and external functions, see xref:n1ql-rest-functions:index.adoc[]. -endif::flag-devex-rest-api[] +* To manage external libraries and external functions, see xref:guides:create-javascript-library.adoc[]. * To see the execution plan for a user-defined function, see xref:n1ql-language-reference/explainfunction.adoc[]. * To include a user-defined function in an expression, see xref:n1ql-language-reference/userfun.adoc[]. * To monitor user-defined functions, see xref:n1ql:n1ql-intro/sysinfo.adoc#sys-functions[Monitor Functions]. diff --git a/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc index 8ce6cdbe8..077d2ff97 100644 --- a/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc @@ -30,28 +30,10 @@ The following constraints apply: == Prerequisites -[cols="2,3"] -|=== -| To execute EXPLAIN FUNCTION on ... | You must have ... - -| Global inline functions -| *Execute Global Functions* role. - -| Scoped inline functions -| *Execute Scope Functions* role, with permissions on the specified bucket and scope. - -| Global external functions -| *Execute Global External Functions* role. - -| Scoped external functions -| *Execute Scope External Functions* role, with permissions on the specified bucket and scope. -|=== +* To manage user-defined functions on your cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. You must also have the necessary privileges required for the {sqlpp} statements inside the function. -For more information about user roles, see -xref:server:learn:security/authorization-overview.adoc[Authorization]. - == Syntax [source,ebnf] @@ -137,9 +119,7 @@ include::n1ql:example$utility/explainfunctionjs.jsonc[] == Related Links * To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. -ifdef::flag-devex-rest-api[] -* To manage external libraries and external functions, see xref:n1ql-rest-functions:index.adoc[]. -endif::flag-devex-rest-api[] +* To manage external libraries and external functions, see xref:guides:create-javascript-library.adoc[]. * To execute a user-defined function, see xref:n1ql-language-reference/execfunction.adoc[]. * To include a user-defined function in an expression, see xref:n1ql-language-reference/userfun.adoc[]. * To monitor user-defined functions, see xref:n1ql:n1ql-intro/sysinfo.adoc#sys-functions[Monitor Functions]. From 0d0ad7bf113f996d3d2832384045e6cecbc5149a Mon Sep 17 00:00:00 2001 From: Sarah Emmett Date: Fri, 28 Mar 2025 15:19:25 -0400 Subject: [PATCH 05/16] [AV-93521] Continuing to update UDFs docs. Removing code callouts from example files. Updating pages in the JavaScript for Query reference. Making other adjustments in JavaScript UDFs Guide to support said changes and bring everything in line. --- .../pages/create-javascript-library.adoc | 9 +++ .../pages/create-user-defined-function.adoc | 11 ++++ modules/guides/pages/javascript-udfs.adoc | 2 +- .../create-globally-scoped-n1ql-udf.n1ql | 2 +- .../create-relatively-scoped-n1ql-udf.n1ql | 2 +- .../examples/select-airline-inline.js | 10 ++- .../pages/calling-javascript-from-n1ql.adoc | 66 ++++++++++--------- .../javascript-functions-with-couchbase.adoc | 40 +++++------ .../partials/javascript-udf-introduction.adoc | 8 +-- .../partials/libraries-and-scopes.adoc | 25 ++++--- .../partials/sqlpp-managed-udfs.adoc | 6 +- 11 files changed, 106 insertions(+), 75 deletions(-) diff --git a/modules/guides/pages/create-javascript-library.adoc b/modules/guides/pages/create-javascript-library.adoc index 2fc6db4d6..d311917b3 100644 --- a/modules/guides/pages/create-javascript-library.adoc +++ b/modules/guides/pages/create-javascript-library.adoc @@ -46,6 +46,15 @@ To add functions to your new UDF library while you create your library: + TIP: Each function should have an assigned name and follow the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript] standard. +=== Creating Functions with Variable Length Parameter Lists + +If you want to create a function that can take a variable length list of parameters, rather than a set number of parameters, add a variable that starts with `...` to your function - such as `... args`. + +If you define your JavaScript function with all named variables and add a `...` parameter to your user-defined function later, your function will accept an array of values as a parameter. +It assigns each value it receives to the named variables in your function. + +For more information and examples, see xref:javascript-udfs:calling-javascript-from-n1ql.adoc#variadic-parameters[Variadic Parameters]. + [#add-functions-later] == Add Functions to an Existing User-Defined Function (UDF) Library diff --git a/modules/guides/pages/create-user-defined-function.adoc b/modules/guides/pages/create-user-defined-function.adoc index 7baae5445..7bab55d8f 100644 --- a/modules/guides/pages/create-user-defined-function.adoc +++ b/modules/guides/pages/create-user-defined-function.adoc @@ -47,6 +47,9 @@ Users must set this bucket and scope as their xref:n1ql:n1ql-intro/queriesandres . In the *Parameters* field, enter a list of parameters, separated by commas (,), for any values you need to process or use in your function. + For example, if you created a JavaScript function that has a variable named `a`, you should add a parameter `a`. ++ +TIP: If you want to create a user-defined function that can take a variable length list of parameters, rather than a comma separated list of parameters, add `...` as a parameter. +Your function will accept an array of values as a parameter, and assign each value it receives to the named variables in your function. . Click the *UDF Library* tab. . Choose the UDF library and specific JavaScript function you want to assign to this user-defined function. . Click btn:[Create Function]. @@ -96,6 +99,14 @@ TIP: Users must set this bucket and scope as their xref:n1ql:n1ql-intro/queriesa . In the *Parameters* field, enter a list of parameters, separated by commas (,), for any values you need to process or use in your function. + For example, if you created a JavaScript function that has a variable named `a`, you should add a parameter `a`. ++ +[TIP] +==== +If you want to create a user-defined function that can take a variable length list of parameters, rather than a comma separated list of parameters, add `...` as a parameter. +Your function will accept an array of values as a parameter, and assign each value it receives to the named variables in your function. + +You can also define your function with a variable length parameter list, by adding a variable to your function definition that starts with `...` - such as `... args`. +==== . Click the *Inline {sqlpp}* or *Inline JavaScript* tab. . Enter a {sqlpp} expression or JavaScript function. . Click btn:[Create Function]. diff --git a/modules/guides/pages/javascript-udfs.adoc b/modules/guides/pages/javascript-udfs.adoc index d83e6da05..50351e801 100644 --- a/modules/guides/pages/javascript-udfs.adoc +++ b/modules/guides/pages/javascript-udfs.adoc @@ -38,7 +38,7 @@ Creating a UDF library is optional, but simplifies organization and access contr After you have created your user-defined functions, you can xref:call-user-defined-function.adoc[] like any other {sqlpp} function. [#inline-functions] -=== Inline {sqlpp} Functions +=== Inline Functions You can create a user-defined function that executes inline {sqlpp} commands or inline JavaScript. diff --git a/modules/javascript-udfs/examples/create-globally-scoped-n1ql-udf.n1ql b/modules/javascript-udfs/examples/create-globally-scoped-n1ql-udf.n1ql index c64379d58..87a72fdda 100644 --- a/modules/javascript-udfs/examples/create-globally-scoped-n1ql-udf.n1ql +++ b/modules/javascript-udfs/examples/create-globally-scoped-n1ql-udf.n1ql @@ -1,3 +1,3 @@ CREATE FUNCTION GetBusinessDays(startDate, endDate) LANGUAGE JAVASCRIPT as "getBusinessDays" -AT "my-library"; -- <.> \ No newline at end of file +AT "my-library"; \ No newline at end of file diff --git a/modules/javascript-udfs/examples/create-relatively-scoped-n1ql-udf.n1ql b/modules/javascript-udfs/examples/create-relatively-scoped-n1ql-udf.n1ql index eee12a215..a6476af8d 100644 --- a/modules/javascript-udfs/examples/create-relatively-scoped-n1ql-udf.n1ql +++ b/modules/javascript-udfs/examples/create-relatively-scoped-n1ql-udf.n1ql @@ -1,3 +1,3 @@ CREATE FUNCTION GetBusinessDays(startDate, endDate) LANGUAGE JAVASCRIPT as "getBusinessDays" -AT "./my-library"; -- <.> \ No newline at end of file +AT "./my-library"; \ No newline at end of file diff --git a/modules/javascript-udfs/examples/select-airline-inline.js b/modules/javascript-udfs/examples/select-airline-inline.js index 499e1bc4a..162fcb537 100644 --- a/modules/javascript-udfs/examples/select-airline-inline.js +++ b/modules/javascript-udfs/examples/select-airline-inline.js @@ -1,16 +1,20 @@ function selectAirline(country) { + // SQL++ is written directly into the JavaScript code without the need + // for a function call. var q = SELECT name as airline_name, callsign as airline_callsign FROM `travel-sample`.`inventory`.`airline` - WHERE country = $country; //<1> + WHERE country = $country; var res = []; for (const doc of q) { var airline = {} - airline.name = doc.airline_name // <2> - airline.callsign = doc.airline_callsign // <2> + // Use a standard JavaScript iterator to access the values + // from the SQL++ statement + airline.name = doc.airline_name + airline.callsign = doc.airline_callsign res.push(airline); } diff --git a/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc b/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc index 46baad841..235e982c6 100644 --- a/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc +++ b/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc @@ -1,65 +1,68 @@ -= Calling JavaScript from {sqlpp} -:description: Using a {sqlpp} User-Defined Function to call JavaScript functions. += Call JavaScript from {sqlpp} +:description: You can use user-defined functions (UDFs) to call JavaScript code from the Query Tab. :page-toclevels: 2 :keywords: scopes, variadic [abstract] {description} -== Introduction +== Prerequisites -Before you can call a JavaScript function, you must first create a {sqlpp} User-Defined Function to call it. -The process to do this is explained in the xref:guides:create-user-defined-function.adoc#creating-the-n1ql-udf-function[Creating the {sqlpp} User-Defined Function] section of the xref:guides:javascript-udfs.adoc[] guide. +* To call a JavaScript function from {sqlpp}, you need to xref:guides:create-user-defined-function.adoc[create a user-defined function]. ++ +For more information about user-defined functions in Capella, see xref:guides:javascript-udfs.adoc[]. -If you are unfamiliar with creating User-Defined Functions to call JavaScript, then the xref:guides:javascript-udfs.adoc[guide] is the best place to start. +== Create a Scoped User-Defined Function with {sqlpp} -In this section, you're going to take a closer look at concepts around {sqlpp} User-Defined Functions, such as variadic parameter lists. - -== Scopes and {sqlpp} User-Defined Functions - -A JavaScript function can be xref:guides:create-javascript-library.adoc#creating-the-library-and-adding-your-first-function[created through the WorkBench or through the REST API]. +For example, the following JavaScript function calculates the number of business days between a given start date and end date: [source, javascript, role="no-callouts"] ---- include::example$get-business-days.js[] ---- -And the corresponding {sqlpp} User-Defined Function can be created through the xref:guides:create-user-defined-function.adoc#creating-the-n1ql-udf-function[Query Workbench] or by executing a {sqlpp} statement: +You could define this JavaScript function as part of a xref:guides:create-javascript-library.adoc[UDF library] or as an xref:create-user-defined-function.adoc#create-inline[inline user-defined function]. + +If the JavaScript is already defined in a UDF library, you can create the user-defined function from the Query tab or by running a {sqlpp} statement. + +The following {sqlpp} statement creates the `GetBusinessDays` function inside the `travel-sample`.`inventory` namespace. +It references the `GetBusinessDays` function stored inside the `my-library` UDF library, also stored in `travel-sample`.`inventory`. +`GetBusinessDays` becomes a *Scoped* function: [source, sqlpp] ---- include::example$create-scoped-n1ql-udf.n1ql[] ---- -<.> The new {sqlpp} User-Defined Function is called `GetBusinessDays` and takes the `inventory` scope inside the `travel-sample` bucket. -As well as providing a logical separation between JavaScript libraries, using scopes provides a means of securing access to the library: a user must have a context that matches the scope of the library in order to access it. -<.> This function will reference the `getBusinessDays` JavaScript function … -<.> … in a library called `my-library` which is set to the `inventory` scope within the `travel-sample` bucket. -=== Global Library Path +=== Create a Global User-Defined Function with {sqlpp} -Of course, you can define the library at the cluster level, where it will be accessible to anyone who has access rights to the cluster. -Functions in the global library are accessible across the cluster. +You can also define *Global* user-defined functions from the Query Tab using {sqlpp}. +Any function added globally will be accessible across your cluster: -.Creating a {sqlpp} User-Defined Function to access the JavaScript function in the global library +.Creating a Global user-defined function using {sqlpp} [source, sqlpp] ---- include::example$create-globally-scoped-n1ql-udf.n1ql[] ---- -<.> There is no prefix path before `my-library` which means the library is a globally accessible library defined at the cluster level. +If you do not add a prefix before the library name in your {sqlpp} statement, the user-defined function will be created as a *Global* function. -=== Relative Library Path +=== Create a User-Defined Function with {sqlpp} and A Relative Library Path -You can also use relative paths for the library location: +You can also use {sqlpp} and define a relative path for your UDF library location. +If you use a relative path, the library location will resolve based on the current xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context]. + +For example, the following {sqlpp} statement creates the user-defined function in `my-library`, relative to the current query context: [source, sqlpp] ---- include::example$create-relatively-scoped-n1ql-udf.n1ql[] ---- -<.> In this case, the User-Defined Function will be created for the JavaScript function under the current xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context]. -== Calling the Function +== Call a User-Defined Function with {sqlpp} + +After you create your user-defined function, you can call it like any built-in {sqlpp} function. -Once the {sqlpp} User-Defined Function is defined, it can be called as if it were a built-in {sqlpp} function: +For example, you could use the following to call the `GetBusinessDays` function: .Query [source, sqlpp] @@ -67,7 +70,7 @@ Once the {sqlpp} User-Defined Function is defined, it can be called as if it wer include::example$select-get-business-days.n1ql[] ---- -which will return the following result: +The function would return the following result, in JSON format: .Result [source, json] @@ -82,7 +85,7 @@ You can also use the `EXECUTE FUNCTION` statement to execute the function: include::example$execute-javascript-function.n1ql[] ---- -or as part of a complex statement: +Or, you can call a function as part of a complex statement: [source, n1ql, role=no-callouts] ---- @@ -92,13 +95,16 @@ include::example$select-true-alias-get-business-days.n1ql[] [#variadic-parameters] == Variadic Parameters -You can define a {sqlpp} User-Defined Function with a variadic parameter, which means that the parameter will accept a list of values which it will pass to the JavaScript function it references. -You can create the `GetBusinessDays` function using a variadic parameter rather than the `startDate` and `endDate` parameters: +You can define user-defined functions with a *variadic parameter*. +Variadic parameters accept a list of values, which they pass to the defined JavaScript function. + +For example, you could define the `GetBusinessDays` function to use a variadic parameter, instead of setting both the `startDate` and `endDate` parameters: [source, sqlpp] ---- include::example$create-variadic-n1ql-udf.n1ql[] ---- +// Start here! Note that the statement used three dots (...) rather than a list of parameter list. This indicates a variable length parameter list. The underlying JavaScript function will reference the parameter list as named variables: diff --git a/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc b/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc index 3e2fab998..70f3fe42b 100644 --- a/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc +++ b/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc @@ -1,5 +1,5 @@ = JavaScript Functions for Query Reference -:description: This reference guide describes how to write extension functions for {sqlpp} for Query using the JavaScript language. +:description: You can write extension functions for {sqlpp} for Query in Couchbase Capella, using the JavaScript programming language. :page-topic-type: reference :page-toclevels: 2 :keywords: library namespacing @@ -7,26 +7,24 @@ [abstract] {description} -== Introduction +== About User-Defined Functions in {sqlpp} for Query include::partial$javascript-udf-introduction.adoc[] -This reference includes details of external functions using JavaScript. - include::partial$libraries-and-scopes.adoc[] include::partial$sqlpp-managed-udfs.adoc[] -== Added Constructs +== Added Language Constructs -JavaScript functions in {sqlpp} for Query support most of the language constructs available in https://en.wikipedia.org/wiki/ECMAScript[ECMAScript], though there are a number of restrictions related to the Couchbase environment. -There are also additions that have been made to the language for working specifically with Couchbase. +User-defined functions in {sqlpp} for Query support most of the language constructs available in https://en.wikipedia.org/wiki/ECMAScript[ECMAScript^]. +Couchbase's implementation makes specific changes to support working with JavaScript through {sqlpp}. === {sqlpp} Embedded Statements -Top level {sqlpp} keywords, such as SELECT, UPDATE, INSERT and DELETE, are available as inline keywords in functions. -Operations that return values such as SELECT are accessible through a returned iterable handle. -{sqlpp} Query results, via a SELECT, are streamed in batches to the iterable handle as the iteration progresses through the result set. +Top level {sqlpp} keywords, such as `SELECT`, `UPDATE`, `INSERT` and `DELETE`, are available as inline keywords in functions. +Operations that return values such as `SELECT` are accessible through a returned iterable handle. +{sqlpp} Query results, through `SELECT`, are streamed in batches to the iterable handle as the iteration progresses through the result set. .JavaScript code with embedded {sqlpp} statements ==== @@ -34,25 +32,24 @@ Operations that return values such as SELECT are accessible through a returned i ---- include::example$select-airline-inline.js[] ---- - -<1> The {sqlpp} is written directly into the JavaScript code without having to be used as part of a function call. -You can even provide parameters that can be used in the {sqlpp} statement. -<2> A standard JavaScript iterator is used to access the values returned from the {sqlpp} statement. +You can even provide parameters in your JavaScript code that can be used in the {sqlpp} statement. ==== -For more details, see xref:calling-n1ql-from-javascript.adoc[]. +For more information, see xref:calling-n1ql-from-javascript.adoc[]. -== Unsupported Features +== Unsupported JavaScript Features The following features are not supported in JavaScript functions for Query. === Browser Extensions -Because JavaScript functions in {sqlpp} for Query do not execute in the context of a browser, the extensions that browsers add to the core language, such as window methods, DOM events, and so on, are not available. +JavaScript functions in {sqlpp} for Query do not execute in the context of a browser. +The extensions that browsers add to the core language, such as window methods, DOM events, and so on, are not available. === Global State -All variables must be local to the function; global state is not permitted. +All variables must be local to the function. +Global state is not permitted. .JavaScript code with global variable ==== @@ -62,14 +59,14 @@ include::example$illegal-global-variable.js[] ---- ==== -Along with global state, global https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions[arrow functions] are not supported. +Along with global state, global https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions[arrow functions^] are not supported. Arrow functions local to individual JavaScript functions are supported. === Logging Logging using the `console.log(..)` function is not supported. -== Restricted Features +== Restricted JavaScript Features [.status]#Couchbase Server 7.6.2# @@ -166,8 +163,7 @@ function sleep(milliseconds) { * xref:n1ql:n1ql-language-reference/userfun.adoc[] .External Libraries -* xref:tools:udfs-ui.adoc[] -* xref:n1ql-rest-functions:index.adoc[] +* xref:guides:create-javascript-library.adoc[] .JavaScript Functions * xref:calling-javascript-from-n1ql.adoc[] diff --git a/modules/javascript-udfs/partials/javascript-udf-introduction.adoc b/modules/javascript-udfs/partials/javascript-udf-introduction.adoc index d7f473006..0501448a2 100644 --- a/modules/javascript-udfs/partials/javascript-udf-introduction.adoc +++ b/modules/javascript-udfs/partials/javascript-udf-introduction.adoc @@ -1,8 +1,8 @@ -There are two types of user-defined function in {sqlpp} for Query: +Capella supports 2 types of user-defined function in {sqlpp} for Query: * [.term]#Inline functions# are defined using {sqlpp} expressions. -They enable you to name and reuse complex or repetitive expressions, including subqueries, in order to simplify your queries. +Use an inline function to reuse complex or repetitive expressions, including subqueries, and simplify your {sqlpp} queries. * [.term]#External functions# are defined using an external language. -They enable you to create functions that may be difficult or impossible to define using built-in {sqlpp} expressions. -The only supported language is JavaScript. \ No newline at end of file +Capella supports defining external functions using JavaScript. +Write a JavaScript function to run expressions or queries that may be difficult or impossible to define using built-in {sqlpp} expressions. \ No newline at end of file diff --git a/modules/javascript-udfs/partials/libraries-and-scopes.adoc b/modules/javascript-udfs/partials/libraries-and-scopes.adoc index fd6621dd0..889b0e9a6 100644 --- a/modules/javascript-udfs/partials/libraries-and-scopes.adoc +++ b/modules/javascript-udfs/partials/libraries-and-scopes.adoc @@ -9,19 +9,24 @@ The libraries and scope section can be reused in the SQL++ reference (((library namespacing))) You can store JavaScript functions in [.term]#external libraries#. This enables you to share external function code for use in more than one {sqlpp} user-defined function. -A library can contain one or more JavaScript functions. +A library can contain 1 or more JavaScript functions. For more information about how to create a user-defined function library, see xref:guides:create-javascript-library.adoc[]. // This line left blank intentionally // end::extract[] -You do not call the external function code directly from {sqlpp}. -Instead, when you have created an external library and added a JavaScript function to it, you must define a {sqlpp} user-defined function to call the JavaScript function. +You cannot call external function code directly from {sqlpp}. +If you want to manage your external function code with a library, you must: + +* xref:guides:create-javascript-library.adoc[Create a UDF library] and add a JavaScript function or functions to that library. +* xref:guides:create-user-defined-function.adoc[Create a user-defined function] to call a specific JavaScript function from that library. + +You can also xref:guides:create-user-defined-function.adoc#create-inline[create a user-defined function with an inline JavaScript expression]. // tag::extract[] -External libraries, like {sqlpp} user-defined functions, may be scoped or global. -This enables you to keep the code for external functions separate where required. +UDF libraries, like {sqlpp} user-defined functions, may be scoped or global. +Set a UDF library or user-defined function as *Scoped* to keep the code for external functions separate. // This line left blank intentionally // end::extract[] @@ -36,14 +41,14 @@ include::partial$diagrams/javascript-scopes.puml[] * A [.term]#scoped library# is created within a xref:n1ql:n1ql-intro/queriesandresults.adoc#logical-hierarchy[scope], at the same level as the collections within a scope. -You can apply access restrictions to scopes, so that only certain groups of users will be able to access collections and libraries within that scope. +//You can apply access restrictions to scopes, so that only certain groups of users will be able to access collections and libraries within that scope. // tag::extract[] -Code which is stored in a scoped library is private to users of that scope, and is not visible or available to users of another scope. -Code which is stored in a global library is available to users of all scopes. +//Code which is stored in a scoped library is private to users of that scope, and is not visible or available to users of another scope. +Any code that you store in a global library is available to all users with read and write permissions on your cluster. A global library may have the same name as a scoped library, and scoped libraries may have the same name as each other. -For example, you may have a global `math` library, and a `math` library in each scope. +For example, you can have a global `math` library, and a `math` library in each scope. // end::extract[] .Calling a function in a scoped external library @@ -52,4 +57,4 @@ For example, you may have a global `math` library, and a `math` library in each include::partial$diagrams/udf-scopes-diagram.puml[] .... -In order to use a {sqlpp} user-defined function which calls external JavaScript code in a scoped library, you must set the xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] to the same bucket and scope as the scoped library. +When you want to use a *Scoped* user-defined function from the Query Tab, you must set your xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] to the same bucket and scope as the library. diff --git a/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc b/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc index a42f091b6..76900a8ce 100644 --- a/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc +++ b/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc @@ -2,8 +2,8 @@ [.status]#Couchbase Server 7.6# -In clusters using Couchbase Server 7.6 and later, you can create the code for an external function and the corresponding {sqlpp} user-defined function in a single operation. -This means that you don't have to specify an external library and create the code for the external function, before creating the {sqlpp} user-defined function. +For clusters using Couchbase Server 7.6 and later, you can create the code for an external function and the corresponding {sqlpp} user-defined function in a single operation in the Query Tab or cbq. +You do not have to create a UDF library before creating a {sqlpp} user-defined function. With a {sqlpp} managed user-defined function, the external function code is stored inline, along with the {sqlpp} user-defined function. -You cannot share this external function code with other user-defined functions, or access it from any external libraries. +You cannot share this external function code with other user-defined functions, or access it from a UDF library. From c073f2cd40aa221903e7bdf7c963ff04faeb91b8 Mon Sep 17 00:00:00 2001 From: Sarah Emmett Date: Wed, 2 Apr 2025 17:01:59 -0400 Subject: [PATCH 06/16] [AV-93521] Working commit, continuing to update related documentation, partials, and examples to follow style and improve throughline on UDF topics --- .../pages/call-user-defined-function.adoc | 2 +- .../pages/create-javascript-library.adoc | 10 +- .../pages/create-user-defined-function.adoc | 19 ++- modules/guides/pages/javascript-udfs.adoc | 16 +-- .../examples/add-airline-check-parse.js | 2 +- .../examples/add-airline-parse-check-2.js | 4 +- .../examples/do-recursion-response.jsonc | 3 +- .../examples/select-hotels-inline.js | 8 +- .../javascript-udfs/examples/variadic-sum.js | 4 +- .../pages/calling-javascript-from-n1ql.adoc | 31 +++-- .../pages/calling-n1ql-from-javascript.adoc | 113 ++++++++++-------- .../pages/handling-errors-javascript-udf.adoc | 63 ++++++---- .../javascript-functions-with-couchbase.adoc | 11 +- .../partials/javascript-udf-introduction.adoc | 8 +- .../partials/libraries-and-scopes.adoc | 6 +- .../partials/sqlpp-managed-udfs.adoc | 6 +- .../createfunction.adoc | 10 +- .../n1ql-language-reference/dropfunction.adoc | 24 ++-- .../n1ql-language-reference/execfunction.adoc | 6 +- .../explainfunction.adoc | 4 +- .../n1ql-language-reference/userfun.adoc | 26 +--- 21 files changed, 198 insertions(+), 178 deletions(-) diff --git a/modules/guides/pages/call-user-defined-function.adoc b/modules/guides/pages/call-user-defined-function.adoc index 642418e47..8b3cce300 100644 --- a/modules/guides/pages/call-user-defined-function.adoc +++ b/modules/guides/pages/call-user-defined-function.adoc @@ -16,7 +16,7 @@ A user-defined function can be called like any other {sqlpp} function. == Prerequisites * If you want to use cbq to run your user-defined function, you must complete the prerequisites for using cbq. -For more information, see xref:n1ql:nq1l-intro/cbq.adoc#prerequisites[Prerequisites]. +For more information, see xref:n1ql:n1ql-intro/cbq.adoc#prerequisites[Prerequisites]. * You have created a user-defined function. For more information, see xref:create-user-defined-function.adoc[]. diff --git a/modules/guides/pages/create-javascript-library.adoc b/modules/guides/pages/create-javascript-library.adoc index d311917b3..19d1e8682 100644 --- a/modules/guides/pages/create-javascript-library.adoc +++ b/modules/guides/pages/create-javascript-library.adoc @@ -9,7 +9,7 @@ [abstract] {description} -To create a UDF library that you can use to xref:create-user-defined-functions.adoc[]: +To create a UDF library that you can use to xref:create-user-defined-function.adoc[]: . <> . <> @@ -24,7 +24,7 @@ To create a new UDF library from the Query Tab: . On the *Operational Clusters* page, select the operational cluster where you want to work with user-defined functions. . Go to menu:Data Tools[Query]. . In the Data Insights area, to the left of the query editor, find the *Functions* section. -. Next to the *Functions* section header, click menu:Create (+)[Library]. +. Next to the *Functions* section header, go to menu:Create (+)[Library]. . In the *Library Name* field, enter a name for your new UDF library. . Choose the access level for your UDF library: .. Choose *Global* to allow all buckets and scopes on this cluster to use functions in this library. @@ -44,7 +44,7 @@ To add functions to your new UDF library while you create your library: .. To manually define functions for your library, on the *Define Functions* tab, enter the code for each function. .. To import a `.js` file that contains function definitions, on the *Import Library* tab, drag and drop or choose your `.js` file. + -TIP: Each function should have an assigned name and follow the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript] standard. +TIP: Each function should have an assigned name and follow the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript^] standard. === Creating Functions with Variable Length Parameter Lists @@ -63,7 +63,7 @@ To add or edit functions in an existing UDF library: . On the *Operational Clusters* page, select the operational cluster where you want to work with user-defined functions. . Go to menu:Data Tools[Query]. . In the Data Insights area, to the left of the query editor, find the *Functions* section. -. Next to the user-defined library where you want to add a function, click menu:More Options (⋮)[Edit]. +. Next to the user-defined library where you want to add a function, go to menu:More Options (⋮)[Edit]. . Do one of the following: .. To manually define functions for your library, on the *Create Functions* tab, enter or edit the code for each function. .. To import a `.js` file that contains function definitions, on the *Import Library* tab, drag and drop or choose your `.js` file. @@ -79,7 +79,7 @@ To delete an existing UDF library: . On the *Operational Clusters* page, select the operational cluster where you want to delete a UDF library. . Go to menu:Data Tools[Query]. . In the Data Insights area, to the left of the query editor, find the *Functions* section. -. Next to the user-defined library where you want to add a function, click menu:More Options (⋮)[Delete]. +. Next to the user-defined library where you want to add a function, go to menu:More Options (⋮)[Delete]. . Confirm that you want to delete your UDF library. . Click btn:[Delete Library]. diff --git a/modules/guides/pages/create-user-defined-function.adoc b/modules/guides/pages/create-user-defined-function.adoc index 7bab55d8f..03a530185 100644 --- a/modules/guides/pages/create-user-defined-function.adoc +++ b/modules/guides/pages/create-user-defined-function.adoc @@ -1,5 +1,5 @@ = Create a User-Defined Function -:description: Create a user-defined function (UDF) to call an inline function or JavaScript code stored in a library. +:description: Create a user-defined function (UDF) to call an inline function or a specific JavaScript function stored in a library. :page-pagination: :page-topic-type: guide :page-toclevels: 2 @@ -15,7 +15,7 @@ For more information about how to create a UDF library, see xref:create-javascri == Prerequisites * If you want to use cbq to create your user-defined function, you must complete the prerequisites for using cbq. -For more information, see xref:n1ql:nq1l-intro/cbq.adoc#prerequisites[Prerequisites]. +For more information, see xref:n1ql:n1ql-intro/cbq.adoc#prerequisites[Prerequisites]. * If you want to use libraries to organize your user-defined functions, you need to create a UDF library and add a JavaScript function. For more information, see xref:create-javascript-library.adoc[]. @@ -36,7 +36,7 @@ Query Tab:: . Go to menu:Data Tools[Query]. . In the Data Insights area, to the left of the query editor, find the *Functions* section. -. Next to the *Functions* section header, click menu:Create (+)[Function]. +. Next to the *Functions* section header, go to menu:Create (+)[Function]. . In the *Function Name* field, enter a name for your function. . Choose the access level for your user-defined function: .. Choose *Global* to allow all buckets and scopes on this cluster to use this function. @@ -44,7 +44,7 @@ Query Tab:: + TIP: Choose the same access level and namespace as your UDF library for your user-defined function. Users must set this bucket and scope as their xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] to use this function later. -. In the *Parameters* field, enter a list of parameters, separated by commas (,), for any values you need to process or use in your function. +. In the *Parameters* field, enter a list of parameters, separated by commas (`,`) for any values you need to process or use in your function. + For example, if you created a JavaScript function that has a variable named `a`, you should add a parameter `a`. + @@ -89,24 +89,21 @@ Query Tab:: . Go to menu:Data Tools[Query]. . In the Data Insights area, to the left of the query editor, find the *Functions* section. -. Next to the *Functions* section header, click menu:Create (+)[Function]. +. Next to the *Functions* section header, go to menu:Create (+)[Function]. . In the *Function Name* field, enter a name for your function. . Choose the access level for your user-defined function: .. Choose *Global* to allow all buckets and scopes on this cluster to use this function. .. Choose *Specific* to choose a specific bucket and scope on this cluster that can use this function. + TIP: Users must set this bucket and scope as their xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] to use this function later. -. In the *Parameters* field, enter a list of parameters, separated by commas (,), for any values you need to process or use in your function. +. In the *Parameters* field, enter a list of parameters, separated by commas (`,`) for any values you need to process or use in your function. + For example, if you created a JavaScript function that has a variable named `a`, you should add a parameter `a`. + -[TIP] -==== -If you want to create a user-defined function that can take a variable length list of parameters, rather than a comma separated list of parameters, add `...` as a parameter. +TIP: If you want to create a user-defined function that can take a variable length list of parameters, rather than a comma separated list of parameters, add `...` as a parameter. Your function will accept an array of values as a parameter, and assign each value it receives to the named variables in your function. - You can also define your function with a variable length parameter list, by adding a variable to your function definition that starts with `...` - such as `... args`. -==== + . Click the *Inline {sqlpp}* or *Inline JavaScript* tab. . Enter a {sqlpp} expression or JavaScript function. . Click btn:[Create Function]. diff --git a/modules/guides/pages/javascript-udfs.adoc b/modules/guides/pages/javascript-udfs.adoc index 50351e801..568ee0c2c 100644 --- a/modules/guides/pages/javascript-udfs.adoc +++ b/modules/guides/pages/javascript-udfs.adoc @@ -20,20 +20,20 @@ With user-defined functions, you can: * Execute complex logic that may be difficult to do in {sqlpp}. * Migrate from Relational Database Management System (RDBMS) stored procedures. -Couchbase Capella's user-defined functions are defined with JavaScript, specifically the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript] standard, with some restrictions and extensions. +Couchbase Capella's user-defined functions are defined with JavaScript, specifically the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript^] standard, with some restrictions and extensions. For more information, see xref:javascript-udfs:javascript-functions-with-couchbase.adoc[]. == Using User-Defined Functions in Capella You cannot call JavaScript code directly from a {sqlpp} query. -Create a user-defined function to call JavaScript code in your queries. +You must create a user-defined function to call JavaScript code in your queries. You can create 2 types of user-defined functions: -* <>. -* <>. +* <>. +* <>. -Creating a UDF library is optional, but simplifies organization and access control for your functions. +Creating a UDF library for your JavaScript functions is optional, but simplifies organization and access control for user-defined functions. After you have created your user-defined functions, you can xref:call-user-defined-function.adoc[] like any other {sqlpp} function. @@ -44,7 +44,7 @@ You can create a user-defined function that executes inline {sqlpp} commands or If you create a user-defined function this way, you cannot group related functions or change cluster access restrictions for multiple related functions at once. -You do not need to create a library before you can create and use inline functions. +You do not need to create a UDF library before you can create and use inline functions. For more information about how to create inline functions, see xref:create-user-defined-function.adoc#create-inline[Create an Inline User-Defined Function]. @@ -56,7 +56,9 @@ Libraries keep your JavaScript functions organized and allow you to set access c You can define functions xref:create-javascript-library.adoc#add-functions-now[while creating a library] or xref:create-javascript-library.adoc#add-functions-later[add them to an existing library]. -After you have xref:create-javascript-library.adoc[created a UDF library], you must create user-defined functions to use the JavaScript functions in that library. +After you have xref:create-javascript-library.adoc[created a UDF library], you must xref:create-user-defined-function.adoc[create user-defined functions] to use the JavaScript functions in that library. + +The user-defined function creates a link between the JavaScript function in your library and {sqlpp}, letting you call your JavaScript code. == Next Steps diff --git a/modules/javascript-udfs/examples/add-airline-check-parse.js b/modules/javascript-udfs/examples/add-airline-check-parse.js index 1b6645e6d..84c2ab2d1 100644 --- a/modules/javascript-udfs/examples/add-airline-check-parse.js +++ b/modules/javascript-udfs/examples/add-airline-check-parse.js @@ -19,7 +19,7 @@ function addAirlineWithCheck(id, name, callsign, country) { return "success" } catch (error) { - const message = JSON.parse(error.message) // <.> + const message = JSON.parse(error.message) return message } diff --git a/modules/javascript-udfs/examples/add-airline-parse-check-2.js b/modules/javascript-udfs/examples/add-airline-parse-check-2.js index fd77d7e49..21c2a352a 100644 --- a/modules/javascript-udfs/examples/add-airline-parse-check-2.js +++ b/modules/javascript-udfs/examples/add-airline-parse-check-2.js @@ -25,11 +25,11 @@ function addAirlineWithCheck(id, name, callsign, country) { const message = JSON.parse(error.message) - if (message.cause.key == 'dml.statement.duplicatekey') { // <.> + if (message.cause.key == 'dml.statement.duplicatekey') { var myErrorObject = {} myErrorObject.error_type = 'duplicate key' - myErrorObject.key_used = message.cause.message.replace('Duplicate Key: ', '') // <.> + myErrorObject.key_used = message.cause.message.replace('Duplicate Key: ', '') return myErrorObject } else { diff --git a/modules/javascript-udfs/examples/do-recursion-response.jsonc b/modules/javascript-udfs/examples/do-recursion-response.jsonc index 54fc55718..26fc96f7f 100644 --- a/modules/javascript-udfs/examples/do-recursion-response.jsonc +++ b/modules/javascript-udfs/examples/do-recursion-response.jsonc @@ -9,7 +9,8 @@ "caller": "javascript:133", "code": 10112, "key": "function.nested.error", - "message": "Error executing function 'doRecursion': {number-of-calls} nested javascript calls" // <.> + // The function returns an error because of {number-of-calls} nested calls + "message": "Error executing function 'doRecursion': {number-of-calls} nested javascript calls" }, "Location": "functions/my-library.js:30", "Stack": " at doRecursion (functions/my-library.js:30:13)" diff --git a/modules/javascript-udfs/examples/select-hotels-inline.js b/modules/javascript-udfs/examples/select-hotels-inline.js index 0f41eb020..9d8b5fcf5 100644 --- a/modules/javascript-udfs/examples/select-hotels-inline.js +++ b/modules/javascript-udfs/examples/select-hotels-inline.js @@ -1,14 +1,14 @@ function selectHotels() { - var q = SELECT * FROM `travel-sample`.`inventory`.`hotel`; // <.> + var q = SELECT * FROM `travel-sample`.`inventory`.`hotel`; var res = []; - for (const doc of q) { // <.> + for (const doc of q) { - res.push(doc); // <.> + res.push(doc); } - return res; // <.> + return res; } \ No newline at end of file diff --git a/modules/javascript-udfs/examples/variadic-sum.js b/modules/javascript-udfs/examples/variadic-sum.js index fb83d1b9e..bfe1b8e5a 100644 --- a/modules/javascript-udfs/examples/variadic-sum.js +++ b/modules/javascript-udfs/examples/variadic-sum.js @@ -1,8 +1,8 @@ -function sumListOfNumbers(... args) { // <.> +function sumListOfNumbers(... args) { var sum = 0; - args.forEach(value => sum = sum + value); // <.> + args.forEach(value => sum = sum + value); return sum; diff --git a/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc b/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc index 235e982c6..31f955b15 100644 --- a/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc +++ b/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc @@ -1,15 +1,12 @@ = Call JavaScript from {sqlpp} :description: You can use user-defined functions (UDFs) to call JavaScript code from the Query Tab. +:page-topic-type: guide :page-toclevels: 2 :keywords: scopes, variadic [abstract] {description} -== Prerequisites - -* To call a JavaScript function from {sqlpp}, you need to xref:guides:create-user-defined-function.adoc[create a user-defined function]. -+ For more information about user-defined functions in Capella, see xref:guides:javascript-udfs.adoc[]. == Create a Scoped User-Defined Function with {sqlpp} @@ -23,9 +20,10 @@ include::example$get-business-days.js[] You could define this JavaScript function as part of a xref:guides:create-javascript-library.adoc[UDF library] or as an xref:create-user-defined-function.adoc#create-inline[inline user-defined function]. -If the JavaScript is already defined in a UDF library, you can create the user-defined function from the Query tab or by running a {sqlpp} statement. +If the JavaScript is already defined in a UDF library, you can xref:guides:create-user-defined-function.adoc[create the user-defined function] from the Query tab or by running a {sqlpp} statement. The following {sqlpp} statement creates the `GetBusinessDays` function inside the `travel-sample`.`inventory` namespace. + It references the `GetBusinessDays` function stored inside the `my-library` UDF library, also stored in `travel-sample`.`inventory`. `GetBusinessDays` becomes a *Scoped* function: @@ -39,7 +37,6 @@ include::example$create-scoped-n1ql-udf.n1ql[] You can also define *Global* user-defined functions from the Query Tab using {sqlpp}. Any function added globally will be accessible across your cluster: -.Creating a Global user-defined function using {sqlpp} [source, sqlpp] ---- include::example$create-globally-scoped-n1ql-udf.n1ql[] @@ -93,10 +90,10 @@ include::example$select-true-alias-get-business-days.n1ql[] ---- [#variadic-parameters] -== Variadic Parameters +== Create and Call Functions with a Variadic Parameter You can define user-defined functions with a *variadic parameter*. -Variadic parameters accept a list of values, which they pass to the defined JavaScript function. +Variadic parameters accept a list of values, which they pass to your defined JavaScript function. For example, you could define the `GetBusinessDays` function to use a variadic parameter, instead of setting both the `startDate` and `endDate` parameters: @@ -104,32 +101,34 @@ For example, you could define the `GetBusinessDays` function to use a variadic p ---- include::example$create-variadic-n1ql-udf.n1ql[] ---- -// Start here! -Note that the statement used three dots (...) rather than a list of parameter list. This indicates a variable length parameter list. -The underlying JavaScript function will reference the parameter list as named variables: + +You can add a variadic parameter to any user-defined function by using 3 periods (...) instead of a list of parameters. +The 3 periods indicate a variable length parameter list. + +If you use a user-defined function that has a variadic parameter list, but the original JavaScript function has named variables, the JavaScript function still references the variadic parameter list as named variables: [source, javascript, role=no-callouts] ---- include::example$get-business-days-no-ops.js[] ---- -You can also use a variable length parameter list in the JavaScript function itself: +When you define your JavaScript function, you can also use a variable length parameter list. + +For example, the following function iterates through a variadic parameter list, and returns the sum of all the numbers it contains: [source, javascript] ---- include::example$variadic-sum.js[] ---- -<.> JavaScript uses three dots (...) followed by a parameter name to denote a parameter that is an array of values. -<.> Scans through the variadic parameter list, summing all the numbers it contains. -A {sqlpp} User-Defined Function can now be created that takes a variable length list of numbers as an argument: +Then, you can create a user-defined function that takes a variable length list of numbers as an argument: [source, sqlpp] ---- include::example$create-sum-function.n1ql[] ---- -which can then be called with a variable length list of numbers as a parameter +You can then call the user-defined function in a query, with a variable length list of numbers as a parameter: .Query [source, sqlpp] diff --git a/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc b/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc index 8b3e0fce4..842c0dd3f 100644 --- a/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc +++ b/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc @@ -1,14 +1,15 @@ = Calling {sqlpp} from JavaScript -:description: Executing {sqlpp} statements from JavaScript functions. +:description: You can run {sqlpp} statements from inside the JavaScript code you use for a user-defined function. +:page-topic-type: guide :page-toclevels: 2 :stem: [abstract] {description} -== Introduction +User-defined functions support calling JavaScript and executing {sqlpp} statements together. -As well as being able to call JavaScript functions from {sqlpp}, you can also call {sqlpp} statements from inside your JavaScript functions. +For more information about user-defined functions in Capella, see xref:guides:javascript-udfs.adoc[]. [#calling-statements-inline] == Calling {sqlpp} Statements Inline @@ -22,53 +23,59 @@ include::example$add-airline-inline-call.js[] == Executing {sqlpp} Statements Using the N1QL() Call -In addition, you can also execute a {sqlpp} statement by calling it from the `N1QL(…)` function. +You can also execute a {sqlpp} statement by calling it from the `N1QL(…)` function. + [source, javascript] ---- include::example$add-airline-n1ql-call.js[] ---- -NOTE: Behind the scenes, the inline call method will generate the equivalent `{sqlpp}` call, so whichever you choose to use will come down to personal preference. +NOTE: The `N1QL()` function generates the equivalent {sqlpp} call. +You can choose to use either method and get the same results. +The `N1QL()` function changes your available parameter support. +See <>. == Side Effects -Functions executed as part of expressions cannot have side effects that will change data stored by the Couchbase engine. -For example, this statement: +If you choose to use a {sqlpp} statement inside a JavaScript function, that function cannot have side effects that change data stored by Capella. + +For example, in this {sqlpp} statement, the `AddAirline()` function attempts to alter data, which may be an unintended side effect. +The statement returns an error: [source, sqlpp] ---- include::example$add-airline-with-side-effect.n1ql[] ---- -will generate an error because the `AddAirline()` function will attempt to alter data, which the caller may be unaware of. - IMPORTANT: Functions that change data must be called using the `EXECUTE FUNCTION` statement. == Returning Values from {sqlpp} Statements -As shown in the <>, embedded {sqlpp} statements return values which can be used later on in your code. +An embedded {sqlpp} statement can return values that you can use later in your JavaScript code for a user-defined function. -The values returned from the statement calls are JavaScript https://www.w3schools.com/js/js_object_iterables.asp[iterators^]: lists of values or documents returned from the database. -In the next example, you're going to retrieve a list of the hotels stored in the `travel-sample` database: +The values returned from statement calls are JavaScript https://www.w3schools.com/js/js_object_iterables.asp[iterators^]. +Iterators are lists of values or documents returned from your cluster. + +In the following example, the function `selectHotels()` retrieves a list of hotels stored in the `travel-sample`.`inventory`.`hotel` collection. +It returns the list of hotels as an iterator. +The iterator is stored in the variable, `q`. +The function then iterates through each item in `q` to create and return a new result array, `res`: [source, javascript] ---- include::example$select-hotels-inline.js[] ---- -<.> The {sqlpp} statement returns an iterator containing the items retrieved by the query. -<.> Using the standard JavaScript iterator pattern to loop through the items returned in `q`. -<.> Add the current document from the iterator to the result array `res`. -<.> Once all the items have been retrieved, return the result array. - [IMPORTANT] ==== -If an inline statement/{sqlpp} call does not return a value, then the associated {sqlpp} statement is executed as part of a synchronous operation. i.e. the runtime will wait until the statement completes before moving on to the next line of JavaScript. +If an inline statement or {sqlpp} call does not return a value, then the associated {sqlpp} statement is executed as part of a synchronous operation. +This means the runtime will wait until the statement completes before moving on to the next line of JavaScript. -If the inline statement/{sqlpp} call returns a value then it is executed _asynchronously_: execution continues before the iterator is returned. -Each document is fetched from the bucket as it requested by the iterator. +If the inline statement or {sqlpp} call returns a value, then it's executed asynchronously. +Execution of the JavaScript continues before the iterator is returned. +Each document is fetched from the bucket as it's requested by the iterator. [plantuml,inline-call-sequence,svg,subs=attributes] .... @@ -76,12 +83,14 @@ include::partial$diagrams/inline-call-sequence.puml[] .... ==== +[#pass-parameters] == Passing Parameters to {sqlpp} Statements -You can pass parameters from your JavaScript to your {sqlpp} statements. -Parameters can either be _positional_ or _named_. +You can pass parameters from your JavaScript code to your {sqlpp} statements. +Parameters can either be *positional* or *named*. Positional:: The parameters are applied to the statement in the order they appear in the list. +For example, in the following `addAirlineWithPositionalParameters` function, the `id` would be set as `1600`, type as `airline`, `name` to the supplied value of the `name` variable, and so on: + [source, javascript] ---- @@ -89,42 +98,41 @@ include::example$add-airline-positional-pararamers.js[] ---- Named:: The parameters are given a mnemonic name attached to the value, so they can be included directly in the {sqlpp} statement. +For example, in the following `addAirlineWithNamedParameters` function, the names of the parameters passed into the JavaScript function are used in the {sqlpp} statement, without needing to assign the parameters in a separate step. +The parameters are assigned by prefixing the parameter names with a `$`: + [source, javascript] ---- include::example$add-airline-named-parameters.js[] ---- -+ -NOTE: The names of the parameters passed into the JavaScript function are used in the {sqlpp} statement without any need to assign the parameters in a separate step. -[sidebar] -**** -{sqlpp} calls support both _named_ and _positional_ parameters. -Inline calls only support named parameters. +Calling {sqlpp} from the `N1QL()` function supports both *named* and *positional* parameters. +Calling a {sqlpp} statement or expression inline supports only *named* parameters. [cols="^,^,^"] |=== |Call |Named Parameters |Positional Parameters -|{sqlpp} calls +|Calling {sqlpp} using `N1QL()` +| ✔️ | ✔️ -| ✔ |Inline Calls | ✔️ | ❌ |=== -**** == Transactions Transactions are supported from {sqlpp} statements called from JavaScript functions. -* The function can run statements in a transaction that was started before the function was executed. -* The function can run a statement that starts the transaction. -* The function can run a statement that rolls back a transaction. +Functions can: + +* Run statements in a transaction that was started before the function was executed. +* Run a statement that starts the transaction. +* Run a statement that rolls back a transaction. [NOTE] ==== @@ -137,47 +145,56 @@ include::partial$diagrams/transactions-and-iterators.puml[] .... ==== -== Role-Based Access Control +== Role-Based Access Control and Functions + +To execute a {sqlpp} statement from a JavaScript function, you must have the correct permissions on your account to perform actions on any objects referenced in the {sqlpp} statement. + +For more information about roles that control data access in Capella, see xref:projects:project-roles.adoc[]. + +== Executing {sqlpp} Statements That Call Functions -In order to execute {sqlpp} statements as part of a JavaScript function, the user executing the function must have the appropriate privileges to perform the action on any objects referenced in the {sqlpp} statement. +You can also create a JavaScript function that calls a {sqlpp} statement, which then calls another JavaScript function. -== Executing {sqlpp} Statements that Call Functions +Be careful when nesting calls to multiple JavaScript functions. +Each function call executed from a parent call uses a new JavaScript worker process to run. +The deeper you nest your calls, the fewer JavaScript workers you will have available to execute those calls. +Your calling chain will eventually fail and throw an error. -It is often the case that JavaScript function will call a {sqlpp} statement that may itself call another JavaScript function. -However, it is important to be aware that each JavaScript function call executed from a parent call will use a new JavaScript worker process to run. -The deeper the calls are nested, the fewer JavaScript workers are available to run, so the calling chain will eventually fail and throw an error. -This can be demonstrated using a recursive call sequence as shown below: +For example, if you used the following user-defined function, `doRecursion()`: [source, javascript] ---- include::example$do-recursion.js[] ---- -Then executing the function: +Executing the function with the `EXECUTE FUNCTION` call would start an infinite recursion: [source, sqlpp] ---- include::example$execute-do-recursion.n1ql[] ---- -returns the following result: +The function call would eventually return the following result, stopping the call after too many nested function calls exhausted the JavaScript workers: :number-of-calls: 10 [source, json, subs="+attributes"] ---- include::example$do-recursion-response.jsonc[] ---- -<.> The call failed after {number-of-calls} nested call, which exhausted the number of JavaScript workers available during the call sequence. [NOTE] ==== -The JavaScript workers are created when the Couchbase server is started up. +JavaScript workers are created on your Capella cluster based on the following formula: asciimath:["Number of JavaScript Workers" = 4 xx "Number of CPUs"] -The service will automatically prevent recursive calls if there are fewer than 50% JavaScript workers available. +Capella will automatically prevent recursive calls if there are fewer than 50% of the total JavaScript workers available. ==== -== Further Reading +== See Also -include::guides:partial$javascript-udfs/further-reading.adoc[tags="select;execute-function;transactions;rbac"] +* xref:calling-javascript-from-n1ql.adoc[] +* xref:handling-errors-javascript-udf.adoc[] +* xref:n1ql:n1ql-language-reference/execfunction.adoc[] +* xref:n1ql:n1ql-language-reference/index.adoc[] +* xref:guides:transactions.adoc[] diff --git a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc index d330416cb..fa12ad593 100644 --- a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc +++ b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc @@ -1,14 +1,21 @@ = Handling Errors in JavaScript Functions -:description: Error handling in JavaScript user-defined functions use the same standard exception mechanism as part of the language standard. +:description: You can handle errors in JavaScript user-defined functions with the same standard exception mechanism you would use in any JavaScript code. :page-topic-type: reference :page-toclevels: 2 [abstract] {description} +For more information about user-defined functions in Capella, see xref:guides:javascript-udfs.adoc[]. + +You can also choose to handle errors <> or <>. + +[#runtime] == Handle Errors with the Runtime -Errors that occur during the execution of a {sqlpp} statement are usually handled by the runtime, which will return a JSON object giving details of the error. +If you run into an error during the execution of a {sqlpp} statement, you can handle those errors with the runtime. + +The runtime returns a JSON object with the details of the error that occurred. For example, if you execute a record insertion function with a key that already exists: [source, sqlpp] @@ -23,88 +30,96 @@ then an error object is returned: include::example$duplicate-key-error.json5[] ---- +[#function] == Handle Errors with the Function -In most cases, it's a lot better if the JavaScript function itself can handle errors that are likely to occur. -This gives the developer the option of responding with a more user-friendly message, or taking an alternative course of action. +In most cases, it's better to use your JavaScript function to handle likely errors. +You can provide a more user-friendly message or take an alternative course of action. -The following function will add an airline record, but will return an `failure` message if the attempt isn't successful. +For example, the following function will add an airline record, but will return a `failure` message if the `try` {sqlpp} statement fails: [source, javascript] ---- include::example$add-airline-with-check-return.js[] ---- -If the record key already exists, then calling this method with `EXECUTE FUNCTION` will produce the following result: +If the document with the given `id` value already exists in the `travel-sample`.`inventory`.`airline` collection, then the function would return the following: [source, json] ---- include::example$add-airline-with-check-failure-return-response.jsonc[] ---- -Alternatively, you can simply throw the error, rather than returning it as a string: +You can also choose to throw the error, rather than returning it as a string: [source, javascript] ---- include::example$add-airline-with-check-throw.js[] ---- -which will produce the following result: +Running the preceding function with an `id` value that already exists would return the following: [source,javascript] ---- include::example$add-airline-with-check-failure-throw-response.jsonc[] ---- -As well as wrapping the expection in a detailed JSON object, there is another fundamental difference between throwing an error or returning it. +When you throw the error, the exception is returned as a detailed JSON object. -=== Throw vs Return +=== Throwing or Returning Errors -Aside from the data returned, throwing an error or returning a value/error will affect how subsequent {sqlpp} operations are processed. +The data the JavaScript engine returns is different on a throw vs. a return. +Throw and return also affect how subsequent {sqlpp} operations are processed in a function. -*Returning an error*:: If the JavaScript function _returns_ any value, then the {sqlpp} runtime will assume that the function completed successfully, and the caller will continue to run subsequent statements. +*Returning an error*:: If the JavaScript function returns any value, including an error, then the {sqlpp} runtime will assume that the function completed successfully, and the caller will continue to run subsequent statements. -*Throwing an error*:: If an error is _thrown_ then this is treated as an error condition, so further statements in the request will not be run. +*Throwing an error*:: If an error is thrown, then this is treated as an error condition. +Further statements in the request will not run. -You can, of course, throw the error object itself, rather than just a string. +You can also choose to throw the error object, rather than just the string. +For example, the following function throws the entire error object, rather than just a string: [source, javascript] ---- include::example$add-airline-with-check-throw-object.js[] ---- -which deliver a lot more useful information than just posting back a string: +Throwing the error object returns more useful information than just returning a string. +For example, the following response makes it clear that the function failed to run because of a duplicate key value: [source, json] ---- include::example$add-airline-with-check-failure-throw-object-response.jsonc[] ---- -=== Parse the Error +=== Parsing Errors + +You can also choose to parse the error with the `JSON.parse()` function and return the resulting object. -Another approach is to parse the error using the `JSON.parse()` function and return the resulting object: +For example, the following function takes the object from `error.message` and returns that if an error occurs: [source, javascript] ---- include::example$add-airline-check-parse.js[] ---- -<.> The `error` object contains a JSON string (`message`) detailing the nature of the error. -It is much easier to interrogate the message if it's converted back into a JSON object on its own. -This code will send back the entire message structure. + +If you ran the function on an `id` value that already exists in your cluster, the function would return a JSON object like the following: [source, json] ---- include::example$parsed-error-in-full.json5[] ---- -=== Carry Out Alternative Actions +=== Complex Error Handling + +Using the structure of the error message returned by `catch (error)`, you can also use `JSON.parse()` to add more complex error handling to your JavaScript function. + +You could parse out the specific cause of an error, and display a more user-friendly error message that tells the user of your function how to resolve their error, or other, more complex logic. -Once you know the structure of the error message, there's no reason why you can't carry out alternative actions depending on the type of error encountered: +For example, in this function, if the error returned has a `message.cause.key` value of `dml.statement.duplicatekey`, the function returns only the duplicate key, without the `Duplicate Key:` part of the message: [source, javascript] ---- include::example$add-airline-parse-check-2.js[] ---- -<.> Check to see if this is a message that can be handled by the function itself. -<.> Strips out the `"Duplicate Key: "` part of the message, leaving just the duplicate key. diff --git a/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc b/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc index 70f3fe42b..b891f2744 100644 --- a/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc +++ b/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc @@ -39,7 +39,11 @@ For more information, see xref:calling-n1ql-from-javascript.adoc[]. == Unsupported JavaScript Features -The following features are not supported in JavaScript functions for Query. +The following features are not supported in JavaScript functions for Query: + +* <> +* <> +* <> === Browser Extensions @@ -70,7 +74,10 @@ Logging using the `console.log(..)` function is not supported. [.status]#Couchbase Server 7.6.2# -The following features are restricted in JavaScript functions for Query in Couchbase Server 7.6.2 and later. +The following features are restricted in JavaScript functions for Query in Couchbase Server 7.6.2 and later: + +* <> +* <> === Code Injection diff --git a/modules/javascript-udfs/partials/javascript-udf-introduction.adoc b/modules/javascript-udfs/partials/javascript-udf-introduction.adoc index 0501448a2..d9e9e0021 100644 --- a/modules/javascript-udfs/partials/javascript-udf-introduction.adoc +++ b/modules/javascript-udfs/partials/javascript-udf-introduction.adoc @@ -1,8 +1,10 @@ Capella supports 2 types of user-defined function in {sqlpp} for Query: -* [.term]#Inline functions# are defined using {sqlpp} expressions. +* [.term]#Inline functions# are defined using {sqlpp} or JavaScript expressions. Use an inline function to reuse complex or repetitive expressions, including subqueries, and simplify your {sqlpp} queries. -* [.term]#External functions# are defined using an external language. +* [.term]#External functions# are defined using an external language and stored in a user-defined function (UDF) library. +External functions can be collectively managed through their UDF library. Capella supports defining external functions using JavaScript. -Write a JavaScript function to run expressions or queries that may be difficult or impossible to define using built-in {sqlpp} expressions. \ No newline at end of file + +You can use inline or external JavaScript functions to run expressions or queries that may be difficult or impossible to define using built-in {sqlpp} expressions. \ No newline at end of file diff --git a/modules/javascript-udfs/partials/libraries-and-scopes.adoc b/modules/javascript-udfs/partials/libraries-and-scopes.adoc index 889b0e9a6..7545fff68 100644 --- a/modules/javascript-udfs/partials/libraries-and-scopes.adoc +++ b/modules/javascript-udfs/partials/libraries-and-scopes.adoc @@ -7,11 +7,11 @@ The libraries and scope section can be reused in the SQL++ reference === External Libraries (((library namespacing))) -You can store JavaScript functions in [.term]#external libraries#. +You can store JavaScript functions in a [.term]#user-defined function (UDF) library#. This enables you to share external function code for use in more than one {sqlpp} user-defined function. A library can contain 1 or more JavaScript functions. -For more information about how to create a user-defined function library, see xref:guides:create-javascript-library.adoc[]. +For more information about how to create a UDF library, see xref:guides:create-javascript-library.adoc[]. // This line left blank intentionally // end::extract[] @@ -22,8 +22,6 @@ If you want to manage your external function code with a library, you must: * xref:guides:create-javascript-library.adoc[Create a UDF library] and add a JavaScript function or functions to that library. * xref:guides:create-user-defined-function.adoc[Create a user-defined function] to call a specific JavaScript function from that library. -You can also xref:guides:create-user-defined-function.adoc#create-inline[create a user-defined function with an inline JavaScript expression]. - // tag::extract[] UDF libraries, like {sqlpp} user-defined functions, may be scoped or global. Set a UDF library or user-defined function as *Scoped* to keep the code for external functions separate. diff --git a/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc b/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc index 76900a8ce..77955b480 100644 --- a/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc +++ b/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc @@ -2,8 +2,8 @@ [.status]#Couchbase Server 7.6# -For clusters using Couchbase Server 7.6 and later, you can create the code for an external function and the corresponding {sqlpp} user-defined function in a single operation in the Query Tab or cbq. +For clusters using Couchbase Server 7.6 and later, you can create the code for a JavaScript function and the corresponding {sqlpp} user-defined function in a single operation in the Query Tab or cbq. You do not have to create a UDF library before creating a {sqlpp} user-defined function. -With a {sqlpp} managed user-defined function, the external function code is stored inline, along with the {sqlpp} user-defined function. -You cannot share this external function code with other user-defined functions, or access it from a UDF library. +With a {sqlpp} managed user-defined function, the JavaScript function code is stored inline, along with the {sqlpp} user-defined function. +You cannot share this JavaScript function code with other user-defined functions, or access it from a UDF library. diff --git a/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc index 5db7e40d2..b7610e0c8 100644 --- a/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc @@ -16,7 +16,7 @@ include::partial$n1ql-language-reference/horizontal-style.adoc[] include::javascript-udfs:partial$javascript-udf-introduction.adoc[] -External functions in {sqlpp} support most of the language constructs available in ECMAScript. +JavaScript functions in {sqlpp} support most of the language constructs available in ECMAScript. For more information about the restrictions and extensions that come with the Couchbase implementation, see xref:javascript-udfs:javascript-functions-with-couchbase.adoc[]. [[context]] @@ -161,9 +161,9 @@ If you need to return multiple values, construct an array. [[create-function-external]] :section: external -=== External Functions +=== JavaScript Functions -There are two alternative syntaxes for defining an external function: one where the function code is stored in an external library, and one for creating a {sqlpp} managed user-defined function. +There are two alternative syntaxes for defining a JavaScript function: one where the function code is stored in an external library, and one for creating a {sqlpp} managed user-defined function. [source,ebnf] ---- @@ -439,7 +439,7 @@ EXECUTE FUNCTION add100(100); ifdef::flag-devex-javascript-udfs[] [[ex-external]] -.External functions +.JavaScript functions ==== The following command registers two JavaScript functions called `encodeGeoHash` and `calculateAdjacent` in a library called `geohash-js`. footnote:[Credit: https://github.com/davetroy/geohash-js] @@ -586,7 +586,7 @@ endif::flag-devex-javascript-udfs[] == Related Links -* To manage external libraries and external functions, see xref:guides:create-javascript-library.adoc[]. +* To manage UDF libraries and JavaScript functions, see xref:guides:create-javascript-library.adoc[]. * To execute a user-defined function, see xref:n1ql-language-reference/execfunction.adoc[]. * To see the execution plan for a user-defined function, see xref:n1ql-language-reference/explainfunction.adoc[]. * To include a user-defined function in an expression, see xref:n1ql-language-reference/userfun.adoc[]. diff --git a/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc index d044bf59d..149b4d280 100644 --- a/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc @@ -62,12 +62,12 @@ footnote:context[That is, you are dropping a global function, and the function d == Usage -When you drop a user-defined function whose definition is stored in an external library, the external library and function on which the user-defined function depended are not deleted. -This enables you to create a new user-defined function with a different name, or a different number of parameters, using the same JavaScript library and function. +When you drop a user-defined function whose definition is stored in a UDF library, the library and function on which the user-defined function depended are not deleted. +This enables you to create a new user-defined function with a different name, or a different number of parameters, using the same UDF library and JavaScript function. -To change or delete an external library or the external function code, see xref:guides:create-javascript-library.adoc#delete-udf[Delete a User-Defined Function Library]. +To change or delete a UDF library or the JavaScript function code, see xref:guides:create-javascript-library.adoc#delete-udf[Delete a User-Defined Function Library]. -When you drop a {sqlpp} managed user-defined function, the associated external function code is deleted also. +When you drop an inline {sqlpp} user-defined function, the associated JavaScript function code is deleted also. == Examples @@ -90,7 +90,7 @@ SELECT * FROM system:functions; .Drop a {sqlpp} managed user-defined function ==== -This statement deletes a {sqlpp} managed user-defined function called `add100`. +This statement deletes an inline {sqlpp} user-defined function called `add100`. [source,sqlpp] ---- @@ -105,10 +105,9 @@ SELECT * FROM system:functions; ---- ==== -ifdef::flag-devex-javascript-udfs[] -.Drop an external function +.Drop a UDF library function ==== -These statements delete two external functions: +These statements delete two UDF library functions: . A function called `geohash`, which depends on the JavaScript `encodeGeoHash` function in the `geohash-js` library; . A function called `adjacent`, which depends on the JavaScript `calculateAdjacent` function in the `geohash-js` library. @@ -120,7 +119,8 @@ DROP FUNCTION geohash; DROP FUNCTION adjacent; ---- -You can run the following command to check that the JavaScript `geohash-js` library and the `encodeGeoHash` and `calculateAdjacent` functions are still available. +//// +You can run the following command to check that the `geohash-js` library and the `encodeGeoHash` and `calculateAdjacent` functions are still available. [source,sh] ---- @@ -128,12 +128,12 @@ curl -v -X GET \ http://localhost:8093/evaluator/v1/libraries/geohash-js \ -u Administrator:password ---- -==== -endif::flag-devex-javascript-udfs[] +==== +//// == Related Links -* To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. +* To create user-defined functions, see xref:n1ql-language-reference/createfunction.adoc[]. * To manage external libraries and external functions, see xref:guides:create-javascript-library.adoc[]. * To execute a user-defined function, see xref:n1ql-language-reference/execfunction.adoc[]. * To see the execution plan for a user-defined function, see xref:n1ql-language-reference/explainfunction.adoc[]. diff --git a/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc index 752463c21..d9d7f0c87 100644 --- a/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc @@ -69,12 +69,12 @@ include::partial$n1ql-language-reference/udf-output.adoc[] == Examples -For examples, refer to xref:n1ql-language-reference/createfunction.adoc#examples[CREATE FUNCTION]. +For examples, see xref:n1ql-language-reference/createfunction.adoc#examples[CREATE FUNCTION]. == Related Links -* To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. -* To manage external libraries and external functions, see xref:guides:create-javascript-library.adoc[]. +* To create user-defined functions, see xref:n1ql-language-reference/createfunction.adoc[]. +* To manage UDF libraries and JavaScript functions, see xref:guides:create-javascript-library.adoc[]. * To see the execution plan for a user-defined function, see xref:n1ql-language-reference/explainfunction.adoc[]. * To include a user-defined function in an expression, see xref:n1ql-language-reference/userfun.adoc[]. * To monitor user-defined functions, see xref:n1ql:n1ql-intro/sysinfo.adoc#sys-functions[Monitor Functions]. diff --git a/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc index 077d2ff97..3e667e990 100644 --- a/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc @@ -118,8 +118,8 @@ include::n1ql:example$utility/explainfunctionjs.jsonc[] == Related Links -* To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. -* To manage external libraries and external functions, see xref:guides:create-javascript-library.adoc[]. +* To create user-defined functions, see xref:n1ql-language-reference/createfunction.adoc[]. +* To manage UDF libraries and JavaScript functions, see xref:guides:create-javascript-library.adoc[]. * To execute a user-defined function, see xref:n1ql-language-reference/execfunction.adoc[]. * To include a user-defined function in an expression, see xref:n1ql-language-reference/userfun.adoc[]. * To monitor user-defined functions, see xref:n1ql:n1ql-intro/sysinfo.adoc#sys-functions[Monitor Functions]. diff --git a/modules/n1ql/pages/n1ql-language-reference/userfun.adoc b/modules/n1ql/pages/n1ql-language-reference/userfun.adoc index c8f4e4341..85fd01bf4 100644 --- a/modules/n1ql/pages/n1ql-language-reference/userfun.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/userfun.adoc @@ -27,25 +27,7 @@ When you do this, an error is generated. == Prerequisites -[cols="2,3"] -|=== -| To execute ... | You must have ... - -| Global inline functions -| *Execute Global Functions* role. - -| Scoped inline functions -| *Execute Scope Functions* role, with permissions on the specified bucket and scope. - -| Global external functions -| *Execute Global External Functions* role. - -| Scoped external functions -| *Execute Scope External Functions* role, with permissions on the specified bucket and scope. -|=== - -For more details about user roles, see -xref:server:learn:security/authorization-overview.adoc[Authorization]. +* To manage user-defined functions on your cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. == Arguments @@ -142,7 +124,7 @@ include::example$n1ql-language-reference/udf-locations-query.jsonc[] .External functions ==== -For this example, it is assumed that you have created two external functions: +For this example, it is assumed that you have created two JavaScript functions in a UDF library: . A function called `geohash`, which depends on the JavaScript `encodeGeoHash` function in the `geohash-js` library; . A function called `adjacent`, which depends on the JavaScript `calculateAdjacent` function in the `geohash-js` library. @@ -185,9 +167,9 @@ At the latitude of the selected hotel, each geohash represents an area of approx == Related Links -* To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. +* To create user-defined functions, see xref:n1ql-language-reference/createfunction.adoc[]. ifdef::flag-devex-rest-api[] -* To manage external libraries and external functions, see xref:n1ql-rest-functions:index.adoc[]. +* To manage UDF libraries and JavaScript functions, see xref:n1ql-rest-functions:index.adoc[]. endif::flag-devex-rest-api[] * To execute a user-defined function, see xref:n1ql-language-reference/execfunction.adoc[]. * To see the execution plan for a user-defined function, see xref:n1ql-language-reference/explainfunction.adoc[]. From 0a7c0614ec94b79b46519f9b820f31b38d3ac73f Mon Sep 17 00:00:00 2001 From: Sarah Emmett Date: Thu, 3 Apr 2025 15:47:32 -0400 Subject: [PATCH 07/16] [AV-93521] Final tweaks for first draft of UDFs documentation. --- .../pages/call-user-defined-function.adoc | 4 ++- .../pages/create-javascript-library.adoc | 27 ++++++++++++------- modules/guides/pages/javascript-udfs.adoc | 8 +++--- .../examples/create-scoped-n1ql-udf.n1ql | 6 ++--- .../pages/handling-errors-javascript-udf.adoc | 2 ++ .../partials/javascript-udf-introduction.adoc | 4 +-- 6 files changed, 31 insertions(+), 20 deletions(-) diff --git a/modules/guides/pages/call-user-defined-function.adoc b/modules/guides/pages/call-user-defined-function.adoc index 8b3cce300..9d0d06adf 100644 --- a/modules/guides/pages/call-user-defined-function.adoc +++ b/modules/guides/pages/call-user-defined-function.adoc @@ -83,4 +83,6 @@ include::example$javascript-udfs/select-true-alias-get-business-days-cbq.sh[] == See Also -include::partial$javascript-udfs/further-reading.adoc[tags="create-function;user-defined-functions"] \ No newline at end of file +include::partial$javascript-udfs/further-reading.adoc[tags="create-function;user-defined-functions"] +* xref:n1ql:n1ql-language-reference/execfunction.adoc[] +* xref:javascript-udfs:javacript-functions-with-couchbase.adoc[] \ No newline at end of file diff --git a/modules/guides/pages/create-javascript-library.adoc b/modules/guides/pages/create-javascript-library.adoc index 19d1e8682..a18f87f98 100644 --- a/modules/guides/pages/create-javascript-library.adoc +++ b/modules/guides/pages/create-javascript-library.adoc @@ -46,15 +46,6 @@ To add functions to your new UDF library while you create your library: + TIP: Each function should have an assigned name and follow the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript^] standard. -=== Creating Functions with Variable Length Parameter Lists - -If you want to create a function that can take a variable length list of parameters, rather than a set number of parameters, add a variable that starts with `...` to your function - such as `... args`. - -If you define your JavaScript function with all named variables and add a `...` parameter to your user-defined function later, your function will accept an array of values as a parameter. -It assigns each value it receives to the named variables in your function. - -For more information and examples, see xref:javascript-udfs:calling-javascript-from-n1ql.adoc#variadic-parameters[Variadic Parameters]. - [#add-functions-later] == Add Functions to an Existing User-Defined Function (UDF) Library @@ -71,6 +62,24 @@ To add or edit functions in an existing UDF library: TIP: Each function should have an assigned name and follow the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript] standard. . Click btn:[Update]. +== Creating Functions with Variable Length Parameter Lists + +If you want to create a JavaScript function that can take a variable length list of parameters, rather than a fixed number of parameters: + +. Add a variable that starts with `...` to your function - such as `... args`. +. Define your user-defined function with a `...` parameter. + +You can then pass a variable length list of parameters from your user-defined function to your JavaScript function. + +If you define your JavaScript function with all named variables but still want to use a variable length of parameters in your user-defined function: + +. Define your user-defined function with a `...` parameter. + +Your user-defined function will accept an array of values as a parameter. +The user-defined function assigns each value it receives to the named variables in your JavaScript function. + +For more information and examples, see xref:javascript-udfs:calling-javascript-from-n1ql.adoc#variadic-parameters[Variadic Parameters]. + [#delete-udf] == Delete a User-Defined Function (UDF) Library diff --git a/modules/guides/pages/javascript-udfs.adoc b/modules/guides/pages/javascript-udfs.adoc index 568ee0c2c..ff493683f 100644 --- a/modules/guides/pages/javascript-udfs.adoc +++ b/modules/guides/pages/javascript-udfs.adoc @@ -40,24 +40,22 @@ After you have created your user-defined functions, you can xref:call-user-defin [#inline-functions] === Inline Functions -You can create a user-defined function that executes inline {sqlpp} commands or inline JavaScript. +You can create a user-defined function that executes inline {sqlpp} commands or inline JavaScript. +You do not need to create a UDF library before you can create and use inline functions. If you create a user-defined function this way, you cannot group related functions or change cluster access restrictions for multiple related functions at once. -You do not need to create a UDF library before you can create and use inline functions. - For more information about how to create inline functions, see xref:create-user-defined-function.adoc#create-inline[Create an Inline User-Defined Function]. [#library-functions] === Functions From User-Defined Function (UDF) Libraries A UDF library is a collection of JavaScript functions. -Libraries keep your JavaScript functions organized and allow you to set access controls across multiple functions at once. +UDF libraries keep your JavaScript functions organized and allow you to set access controls across multiple functions at once. You can define functions xref:create-javascript-library.adoc#add-functions-now[while creating a library] or xref:create-javascript-library.adoc#add-functions-later[add them to an existing library]. After you have xref:create-javascript-library.adoc[created a UDF library], you must xref:create-user-defined-function.adoc[create user-defined functions] to use the JavaScript functions in that library. - The user-defined function creates a link between the JavaScript function in your library and {sqlpp}, letting you call your JavaScript code. == Next Steps diff --git a/modules/javascript-udfs/examples/create-scoped-n1ql-udf.n1ql b/modules/javascript-udfs/examples/create-scoped-n1ql-udf.n1ql index 63d1e001f..d66e8fe0f 100644 --- a/modules/javascript-udfs/examples/create-scoped-n1ql-udf.n1ql +++ b/modules/javascript-udfs/examples/create-scoped-n1ql-udf.n1ql @@ -1,3 +1,3 @@ -CREATE FUNCTION default:`travel-sample`.`inventory`.GetBusinessDays(startDate, endDate) -- <.> -LANGUAGE JAVASCRIPT as "getBusinessDays" -- <.> -AT "travel-sample/inventory/my-library"; -- <.> \ No newline at end of file +CREATE FUNCTION default:`travel-sample`.`inventory`.GetBusinessDays(startDate, endDate) +LANGUAGE JAVASCRIPT as "getBusinessDays" +AT "travel-sample/inventory/my-library"; \ No newline at end of file diff --git a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc index fa12ad593..fbbf3899c 100644 --- a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc +++ b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc @@ -10,6 +10,8 @@ For more information about user-defined functions in Capella, see xref:guides:ja You can also choose to handle errors <> or <>. +{sqlpp} also supports using the xref:n1ql:n1ql-language-reference/metafun.adoc#abort[ABORT()] function inside a query or a user-defined function to return an error. + [#runtime] == Handle Errors with the Runtime diff --git a/modules/javascript-udfs/partials/javascript-udf-introduction.adoc b/modules/javascript-udfs/partials/javascript-udf-introduction.adoc index d9e9e0021..d3b504cfd 100644 --- a/modules/javascript-udfs/partials/javascript-udf-introduction.adoc +++ b/modules/javascript-udfs/partials/javascript-udf-introduction.adoc @@ -1,9 +1,9 @@ Capella supports 2 types of user-defined function in {sqlpp} for Query: -* [.term]#Inline functions# are defined using {sqlpp} or JavaScript expressions. +* [.term]#*Inline functions*# are defined using {sqlpp} or JavaScript expressions. Use an inline function to reuse complex or repetitive expressions, including subqueries, and simplify your {sqlpp} queries. -* [.term]#External functions# are defined using an external language and stored in a user-defined function (UDF) library. +* [.term]#*External functions*# are defined using an external language and stored in a user-defined function (UDF) library. External functions can be collectively managed through their UDF library. Capella supports defining external functions using JavaScript. From a3fc597a59ec2573b8ce0e99cb39ad75afffa797 Mon Sep 17 00:00:00 2001 From: Sarah Emmett Date: Wed, 16 Apr 2025 12:39:34 -0400 Subject: [PATCH 08/16] [AV-93521] Fix broken links --- modules/guides/pages/call-user-defined-function.adoc | 2 +- modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/guides/pages/call-user-defined-function.adoc b/modules/guides/pages/call-user-defined-function.adoc index 9d0d06adf..150ba3377 100644 --- a/modules/guides/pages/call-user-defined-function.adoc +++ b/modules/guides/pages/call-user-defined-function.adoc @@ -85,4 +85,4 @@ include::example$javascript-udfs/select-true-alias-get-business-days-cbq.sh[] include::partial$javascript-udfs/further-reading.adoc[tags="create-function;user-defined-functions"] * xref:n1ql:n1ql-language-reference/execfunction.adoc[] -* xref:javascript-udfs:javacript-functions-with-couchbase.adoc[] \ No newline at end of file +* xref:javascript-udfs:javascript-functions-with-couchbase.adoc[] \ No newline at end of file diff --git a/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc b/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc index 31f955b15..7134e01c7 100644 --- a/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc +++ b/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc @@ -18,7 +18,7 @@ For example, the following JavaScript function calculates the number of business include::example$get-business-days.js[] ---- -You could define this JavaScript function as part of a xref:guides:create-javascript-library.adoc[UDF library] or as an xref:create-user-defined-function.adoc#create-inline[inline user-defined function]. +You could define this JavaScript function as part of a xref:guides:create-javascript-library.adoc[UDF library] or as an xref:guides:create-user-defined-function.adoc#create-inline[inline user-defined function]. If the JavaScript is already defined in a UDF library, you can xref:guides:create-user-defined-function.adoc[create the user-defined function] from the Query tab or by running a {sqlpp} statement. From decb9e11a230dc75bd7acc20097e2edb64cf59ca Mon Sep 17 00:00:00 2001 From: Sarah Emmett Date: Wed, 16 Apr 2025 13:13:19 -0400 Subject: [PATCH 09/16] [AV-93521] One more broken link --- modules/guides/pages/call-user-defined-function.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/guides/pages/call-user-defined-function.adoc b/modules/guides/pages/call-user-defined-function.adoc index 150ba3377..3f0751a5a 100644 --- a/modules/guides/pages/call-user-defined-function.adoc +++ b/modules/guides/pages/call-user-defined-function.adoc @@ -61,7 +61,7 @@ To run a user-defined function using the command line tool, cbq: . Open a terminal window. . Navigate to the directory where you installed cbq. . Connect to your Capella cluster. -For more information, see xref:n1ql:nq1l-intro/cbq.adoc#cbq-connect-to-cluster[Connecting to the Cluster]. +For more information, see xref:n1ql:n1ql-intro/cbq.adoc#cbq-connect-to-cluster[Connecting to the Cluster]. . Run the `EXECUTE FUNCTION` command with your user-defined function. + For example, the following command executes a function called `GetBusinessDays`, which takes 2 dates, on the `travel-sample`/`inventory` keyspace: From fd90264b76111d53e15138a1530158dd954aa2dd Mon Sep 17 00:00:00 2001 From: sarahlwelton <110928505+sarahlwelton@users.noreply.github.com> Date: Tue, 17 Jun 2025 11:47:19 -0400 Subject: [PATCH 10/16] Update modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc Co-authored-by: Rebecca Martinez <167447972+Rebecca-Martinez007@users.noreply.github.com> --- .../javascript-udfs/pages/handling-errors-javascript-udf.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc index fbbf3899c..b2c6d9df6 100644 --- a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc +++ b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc @@ -73,7 +73,7 @@ When you throw the error, the exception is returned as a detailed JSON object. The data the JavaScript engine returns is different on a throw vs. a return. Throw and return also affect how subsequent {sqlpp} operations are processed in a function. -*Returning an error*:: If the JavaScript function returns any value, including an error, then the {sqlpp} runtime will assume that the function completed successfully, and the caller will continue to run subsequent statements. +*Returning an error*:: If the JavaScript function returns any value, including an error, then the {sqlpp} runtime will assume that the function completed successfully, and the caller will continue to run subsequent statements. *Throwing an error*:: If an error is thrown, then this is treated as an error condition. Further statements in the request will not run. From d15c40ee07870c7e77e73884a842a96f11914aee Mon Sep 17 00:00:00 2001 From: sarahlwelton <110928505+sarahlwelton@users.noreply.github.com> Date: Tue, 17 Jun 2025 11:47:31 -0400 Subject: [PATCH 11/16] Update modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc Co-authored-by: Rebecca Martinez <167447972+Rebecca-Martinez007@users.noreply.github.com> --- .../javascript-udfs/pages/handling-errors-javascript-udf.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc index b2c6d9df6..1165948d9 100644 --- a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc +++ b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc @@ -75,7 +75,7 @@ Throw and return also affect how subsequent {sqlpp} operations are processed in *Returning an error*:: If the JavaScript function returns any value, including an error, then the {sqlpp} runtime will assume that the function completed successfully, and the caller will continue to run subsequent statements. -*Throwing an error*:: If an error is thrown, then this is treated as an error condition. +*Throwing an error*:: If an error is thrown, then this is treated as an error condition. Further statements in the request will not run. You can also choose to throw the error object, rather than just the string. From e7c3a3d58e2ea01383df14848cc7c671e791e280 Mon Sep 17 00:00:00 2001 From: sarahlwelton <110928505+sarahlwelton@users.noreply.github.com> Date: Tue, 17 Jun 2025 11:47:41 -0400 Subject: [PATCH 12/16] Update modules/guides/pages/call-user-defined-function.adoc Co-authored-by: Rebecca Martinez <167447972+Rebecca-Martinez007@users.noreply.github.com> --- modules/guides/pages/call-user-defined-function.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/guides/pages/call-user-defined-function.adoc b/modules/guides/pages/call-user-defined-function.adoc index 3f0751a5a..5b15052fc 100644 --- a/modules/guides/pages/call-user-defined-function.adoc +++ b/modules/guides/pages/call-user-defined-function.adoc @@ -60,7 +60,7 @@ To run a user-defined function using the command line tool, cbq: . Open a terminal window. . Navigate to the directory where you installed cbq. -. Connect to your Capella cluster. +. Connect to your Capella operational cluster. For more information, see xref:n1ql:n1ql-intro/cbq.adoc#cbq-connect-to-cluster[Connecting to the Cluster]. . Run the `EXECUTE FUNCTION` command with your user-defined function. + From d7dc38015ce85b96c2d7a928488d5074a2da7e94 Mon Sep 17 00:00:00 2001 From: sarahlwelton <110928505+sarahlwelton@users.noreply.github.com> Date: Tue, 17 Jun 2025 11:47:51 -0400 Subject: [PATCH 13/16] Update modules/guides/pages/call-user-defined-function.adoc Co-authored-by: Rebecca Martinez <167447972+Rebecca-Martinez007@users.noreply.github.com> --- modules/guides/pages/call-user-defined-function.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/guides/pages/call-user-defined-function.adoc b/modules/guides/pages/call-user-defined-function.adoc index 5b15052fc..e21b38ced 100644 --- a/modules/guides/pages/call-user-defined-function.adoc +++ b/modules/guides/pages/call-user-defined-function.adoc @@ -1,5 +1,5 @@ = Call a User-Defined Function -:description: Call a user-defined JavaScript function from the Query Tab or cbq and use it with your Capella cluster. +:description: Call a user-defined JavaScript function from the Query Tab or cbq and use it with your Capella operational cluster. :page-pagination: prev :page-topic-type: guide :page-toclevels: 2 From 2e4366b195d3e2ddb89330944d9b6c408520b025 Mon Sep 17 00:00:00 2001 From: sarahlwelton <110928505+sarahlwelton@users.noreply.github.com> Date: Tue, 17 Jun 2025 11:47:56 -0400 Subject: [PATCH 14/16] Update modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc Co-authored-by: Rebecca Martinez <167447972+Rebecca-Martinez007@users.noreply.github.com> --- modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc b/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc index 842c0dd3f..7f464dfcb 100644 --- a/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc +++ b/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc @@ -184,7 +184,7 @@ include::example$do-recursion-response.jsonc[] [NOTE] ==== -JavaScript workers are created on your Capella cluster based on the following formula: +JavaScript workers are created on your Capella operational cluster based on the following formula: asciimath:["Number of JavaScript Workers" = 4 xx "Number of CPUs"] From 202ae5c0d393c267b6d5565b488ac1c89386c516 Mon Sep 17 00:00:00 2001 From: Sarah Emmett Date: Tue, 17 Jun 2025 11:59:50 -0400 Subject: [PATCH 15/16] [AV-93521] Cluster -> Operational Cluster, for consistency --- modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc | 2 +- modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc | 2 +- .../javascript-udfs/pages/handling-errors-javascript-udf.adoc | 2 +- modules/javascript-udfs/partials/libraries-and-scopes.adoc | 2 +- modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc | 2 +- modules/n1ql/pages/n1ql-language-reference/createfunction.adoc | 2 +- modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc | 2 +- modules/n1ql/pages/n1ql-language-reference/execfunction.adoc | 2 +- modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc | 2 +- modules/n1ql/pages/n1ql-language-reference/userfun.adoc | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc b/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc index 7134e01c7..07114b1bf 100644 --- a/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc +++ b/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc @@ -35,7 +35,7 @@ include::example$create-scoped-n1ql-udf.n1ql[] === Create a Global User-Defined Function with {sqlpp} You can also define *Global* user-defined functions from the Query Tab using {sqlpp}. -Any function added globally will be accessible across your cluster: +Any function added globally will be accessible across your operational cluster: [source, sqlpp] ---- diff --git a/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc b/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc index 7f464dfcb..567af07f2 100644 --- a/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc +++ b/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc @@ -56,7 +56,7 @@ IMPORTANT: Functions that change data must be called using the `EXECUTE FUNCTION An embedded {sqlpp} statement can return values that you can use later in your JavaScript code for a user-defined function. The values returned from statement calls are JavaScript https://www.w3schools.com/js/js_object_iterables.asp[iterators^]. -Iterators are lists of values or documents returned from your cluster. +Iterators are lists of values or documents returned from your operational cluster. In the following example, the function `selectHotels()` retrieves a list of hotels stored in the `travel-sample`.`inventory`.`hotel` collection. It returns the list of hotels as an iterator. diff --git a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc index 1165948d9..e887c64f4 100644 --- a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc +++ b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc @@ -105,7 +105,7 @@ For example, the following function takes the object from `error.message` and re include::example$add-airline-check-parse.js[] ---- -If you ran the function on an `id` value that already exists in your cluster, the function would return a JSON object like the following: +If you ran the function on an `id` value that already exists in your operational cluster, the function would return a JSON object like the following: [source, json] ---- diff --git a/modules/javascript-udfs/partials/libraries-and-scopes.adoc b/modules/javascript-udfs/partials/libraries-and-scopes.adoc index 7545fff68..6e330ce4d 100644 --- a/modules/javascript-udfs/partials/libraries-and-scopes.adoc +++ b/modules/javascript-udfs/partials/libraries-and-scopes.adoc @@ -43,7 +43,7 @@ include::partial$diagrams/javascript-scopes.puml[] // tag::extract[] //Code which is stored in a scoped library is private to users of that scope, and is not visible or available to users of another scope. -Any code that you store in a global library is available to all users with read and write permissions on your cluster. +Any code that you store in a global library is available to all users with read and write permissions on your operational cluster. A global library may have the same name as a scoped library, and scoped libraries may have the same name as each other. For example, you can have a global `math` library, and a `math` library in each scope. diff --git a/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc b/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc index 77955b480..02937261d 100644 --- a/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc +++ b/modules/javascript-udfs/partials/sqlpp-managed-udfs.adoc @@ -2,7 +2,7 @@ [.status]#Couchbase Server 7.6# -For clusters using Couchbase Server 7.6 and later, you can create the code for a JavaScript function and the corresponding {sqlpp} user-defined function in a single operation in the Query Tab or cbq. +For operational clusters using Couchbase Server 7.6 and later, you can create the code for a JavaScript function and the corresponding {sqlpp} user-defined function in a single operation in the Query Tab or cbq. You do not have to create a UDF library before creating a {sqlpp} user-defined function. With a {sqlpp} managed user-defined function, the JavaScript function code is stored inline, along with the {sqlpp} user-defined function. diff --git a/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc index b7610e0c8..34acaffcc 100644 --- a/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc @@ -48,7 +48,7 @@ include::javascript-udfs:partial$sqlpp-managed-udfs.adoc[] == Prerequisites -* To manage user-defined functions on your cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. +* To manage user-defined functions on your operational cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. == Syntax diff --git a/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc index 149b4d280..8d7400454 100644 --- a/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc @@ -12,7 +12,7 @@ include::partial$n1ql-language-reference/horizontal-style.adoc[] == Prerequisites -* To manage user-defined functions on your cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. +* To manage user-defined functions on your operational cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. == Syntax diff --git a/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc index d9d7f0c87..401f159f8 100644 --- a/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc @@ -21,7 +21,7 @@ If you do this, error `10101: Function not found` is generated. == Prerequisites -* To manage user-defined functions on your cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. +* To manage user-defined functions on your operational cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. == Syntax diff --git a/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc index 3e667e990..9995e556e 100644 --- a/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc @@ -30,7 +30,7 @@ The following constraints apply: == Prerequisites -* To manage user-defined functions on your cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. +* To manage user-defined functions on your operational cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. You must also have the necessary privileges required for the {sqlpp} statements inside the function. diff --git a/modules/n1ql/pages/n1ql-language-reference/userfun.adoc b/modules/n1ql/pages/n1ql-language-reference/userfun.adoc index 85fd01bf4..dea0c05e2 100644 --- a/modules/n1ql/pages/n1ql-language-reference/userfun.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/userfun.adoc @@ -27,7 +27,7 @@ When you do this, an error is generated. == Prerequisites -* To manage user-defined functions on your cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. +* To manage user-defined functions on your operational cluster, you must have the xref:projects:project-roles.adoc#project-owner-role[`Project Owner`] or the xref:projects:project-roles.adoc#project-cluster-data-reader-writer[`Cluster Data Reader/Writer`] role. == Arguments From 400dfcb487ed8fa5566e762e4a582b170d1e53fe Mon Sep 17 00:00:00 2001 From: Sarah Emmett Date: Thu, 19 Jun 2025 10:27:21 -0400 Subject: [PATCH 16/16] [AV-93521] Add clarification on name + scoping behavior for functions --- modules/guides/pages/create-javascript-library.adoc | 7 +++++-- modules/guides/pages/create-user-defined-function.adoc | 7 ++++++- .../pages/calling-javascript-from-n1ql.adoc | 6 ++++++ .../n1ql/pages/n1ql-language-reference/createfunction.adoc | 7 +++++++ .../n1ql/pages/n1ql-language-reference/dropfunction.adoc | 3 +++ .../n1ql/pages/n1ql-language-reference/execfunction.adoc | 3 +++ .../pages/n1ql-language-reference/explainfunction.adoc | 3 +++ modules/n1ql/pages/n1ql-language-reference/userfun.adoc | 3 +++ 8 files changed, 36 insertions(+), 3 deletions(-) diff --git a/modules/guides/pages/create-javascript-library.adoc b/modules/guides/pages/create-javascript-library.adoc index a18f87f98..b7c921eba 100644 --- a/modules/guides/pages/create-javascript-library.adoc +++ b/modules/guides/pages/create-javascript-library.adoc @@ -32,6 +32,9 @@ To create a new UDF library from the Query Tab: + Use this bucket and scope as the namespace for xref:create-user-defined-function.adoc[your user-defined function] to use this library and its functions later. . (Optional) Add functions to your UDF library. ++ +TIP: Function names must be unique within your selected scope. +You cannot have 2 functions with the same name inside your library. See <>. . Click btn:[Create]. @@ -44,7 +47,7 @@ To add functions to your new UDF library while you create your library: .. To manually define functions for your library, on the *Define Functions* tab, enter the code for each function. .. To import a `.js` file that contains function definitions, on the *Import Library* tab, drag and drop or choose your `.js` file. + -TIP: Each function should have an assigned name and follow the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript^] standard. +TIP: Each function should have a unique assigned name inside your library's chosen scope and follow the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript^] standard. [#add-functions-later] == Add Functions to an Existing User-Defined Function (UDF) Library @@ -59,7 +62,7 @@ To add or edit functions in an existing UDF library: .. To manually define functions for your library, on the *Create Functions* tab, enter or edit the code for each function. .. To import a `.js` file that contains function definitions, on the *Import Library* tab, drag and drop or choose your `.js` file. + -TIP: Each function should have an assigned name and follow the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript] standard. +TIP: Each function should have aunique assigned name inside your library's chosen scope and follow the https://en.wikipedia.org/wiki/ECMAScript[ECMAScript] standard. . Click btn:[Update]. == Creating Functions with Variable Length Parameter Lists diff --git a/modules/guides/pages/create-user-defined-function.adoc b/modules/guides/pages/create-user-defined-function.adoc index 03a530185..8ce71c0be 100644 --- a/modules/guides/pages/create-user-defined-function.adoc +++ b/modules/guides/pages/create-user-defined-function.adoc @@ -43,6 +43,7 @@ Query Tab:: .. Choose *Specific* to choose a specific bucket and scope on this cluster that can use this function. + TIP: Choose the same access level and namespace as your UDF library for your user-defined function. +Your function name must be unique in your selected namespace. Users must set this bucket and scope as their xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] to use this function later. . In the *Parameters* field, enter a list of parameters, separated by commas (`,`) for any values you need to process or use in your function. + @@ -66,6 +67,7 @@ include::example$javascript-udfs/create-scoped-n1ql-udf.n1ql[] ---- TIP: Set the same namespace as your UDF library for your user-defined function. +Your function name must be unique in your selected namespace. Users must set this bucket and scope as their xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] to use this function later. For more information on the `CREATE FUNCTION` statement, see xref:n1ql:n1ql-language-reference/createfunction.adoc[CREATE FUNCTION]. @@ -95,7 +97,8 @@ Query Tab:: .. Choose *Global* to allow all buckets and scopes on this cluster to use this function. .. Choose *Specific* to choose a specific bucket and scope on this cluster that can use this function. + -TIP: Users must set this bucket and scope as their xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] to use this function later. +TIP: Your function name must be unique in your selected namespace. +Users must set this bucket and scope as their xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context] to use this function later. . In the *Parameters* field, enter a list of parameters, separated by commas (`,`) for any values you need to process or use in your function. + For example, if you created a JavaScript function that has a variable named `a`, you should add a parameter `a`. @@ -129,6 +132,8 @@ CREATE FUNCTION locations(vActivity) { ( WHERE activity = vActivity) }; ---- +You cannot create 2 functions with the same name inside the same namespace. + For more information about the `CREATE FUNCTION` statement, see xref:n1ql:n1ql-language-reference/createfunction.adoc[CREATE FUNCTION]. -- ==== diff --git a/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc b/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc index 07114b1bf..aea8e2edd 100644 --- a/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc +++ b/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc @@ -32,6 +32,8 @@ It references the `GetBusinessDays` function stored inside the `my-library` UDF include::example$create-scoped-n1ql-udf.n1ql[] ---- +If you created this function, you cannot create another function called `GetBusinessDays` inside the `travel-sample`.`inventory`.`my-library` scope. + === Create a Global User-Defined Function with {sqlpp} You can also define *Global* user-defined functions from the Query Tab using {sqlpp}. @@ -41,7 +43,9 @@ Any function added globally will be accessible across your operational cluster: ---- include::example$create-globally-scoped-n1ql-udf.n1ql[] ---- + If you do not add a prefix before the library name in your {sqlpp} statement, the user-defined function will be created as a *Global* function. +You cannot create another global function called `GetBusinessDays` on your cluster, but you can create a scoped function called `GetBusinessDays`. === Create a User-Defined Function with {sqlpp} and A Relative Library Path @@ -55,6 +59,8 @@ For example, the following {sqlpp} statement creates the user-defined function i include::example$create-relatively-scoped-n1ql-udf.n1ql[] ---- +Based on the current query context, you would not be able to create another function called `GetBusinessDays` in that scope. + == Call a User-Defined Function with {sqlpp} After you create your user-defined function, you can call it like any built-in {sqlpp} function. diff --git a/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc index 34acaffcc..5156244fc 100644 --- a/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc @@ -42,6 +42,9 @@ If you want to call a user-defined function outside of the current query context Finally, it is important to note that a global function is _not_ the same as a scoped function stored in the default scope in a bucket. +You cannot create 2 functions that have the same name inside the same scope. +You can create 2 functions with the same name inside different scopes. + include::javascript-udfs:partial$libraries-and-scopes.adoc[tags=extract] include::javascript-udfs:partial$sqlpp-managed-udfs.adoc[] @@ -124,6 +127,10 @@ Similarly, to create a scoped function in a particular scope, the function name If the function name is an unqualified identifier, it may not be the same as a reserved keyword. A function name with a specified namespace or scope may have the same name as a reserved keyword. +Your function name must be unique inside your specified scope. +You cannot have 2 functions with the same name inside the same scope. +You can have 2 functions with the same name across different scopes. + [id='{section}-parameter'] ==== Function Parameters diff --git a/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc index 8d7400454..b81c34db7 100644 --- a/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc @@ -46,6 +46,9 @@ To delete a global function in a particular namespace, the function name must be Similarly, to delete a scoped function in a particular scope, the function name must be a qualified identifier with the full path to a scope, such as `default:{backtick}travel-sample{backtick}.inventory.func1`. Refer to xref:n1ql-language-reference/createfunction.adoc#context[Global Functions and Scoped Functions] for more information. +You cannot have 2 functions with the same name in the same scope. +You can have 2 functions in the same name across different scopes. + NOTE: The name of a user-defined function _is_ case-sensitive, unlike that of a built-in function. You must delete the user-defined function using the same case that was used when it was created. diff --git a/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc index 401f159f8..aaa8f22b1 100644 --- a/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc @@ -54,6 +54,9 @@ To execute a global function in a particular namespace, the function name must b Similarly, to execute a scoped function in a particular scope, the function name must be a qualified identifier with the full path to a scope, such as `default:{backtick}travel-sample{backtick}.inventory.func1`. Refer to xref:n1ql-language-reference/createfunction.adoc#context[Global Functions and Scoped Functions] for more information. +You cannot have 2 functions with the same name in the same scope. +You can have 2 functions in the same name across different scopes. + NOTE: The name of a user-defined function _is_ case-sensitive, unlike that of a built-in function. You must execute the user-defined function using the same case that was used when it was created. diff --git a/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc index 9995e556e..e4eac8ff8 100644 --- a/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc @@ -64,6 +64,9 @@ To get the plan for a global function in a particular namespace, the function na Similarly, to get the plan for a scoped function in a particular scope, the function name must be a qualified identifier with the full path to a scope, such as `default:{backtick}travel-sample{backtick}.inventory.func1`. Refer to xref:n1ql-language-reference/createfunction.adoc#context[Global Functions and Scoped Functions] for more information. +You cannot have 2 functions with the same name in the same scope. +You can have 2 functions in the same name across different scopes. + NOTE: The name of a user-defined function _is_ case-sensitive, unlike that of a built-in function. You must get the plan for the user-defined function using the same case that was used when it was created. diff --git a/modules/n1ql/pages/n1ql-language-reference/userfun.adoc b/modules/n1ql/pages/n1ql-language-reference/userfun.adoc index dea0c05e2..7a5a71436 100644 --- a/modules/n1ql/pages/n1ql-language-reference/userfun.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/userfun.adoc @@ -19,6 +19,9 @@ To call a global function in a particular namespace, the function name must be a Similarly, to call a scoped function in a particular scope, the function name must be a qualified identifier with the full path to a scope, such as `default:{backtick}travel-sample{backtick}.inventory.func1`. Refer to xref:n1ql-language-reference/createfunction.adoc#context[Global Functions and Scoped Functions] for more details. +You cannot have 2 functions with the same name in the same scope. +You can have 2 functions in the same name across different scopes. + NOTE: The name of a user-defined function _is_ case-sensitive, unlike that of a built-in function. You must call the user-defined function using the same case that was used when it was created.