Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions modules/guides/pages/call-user-defined-function.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
:page-edition: Enterprise Edition
:page-topic-type: guide
:page-toclevels: 2
:imagesdir: ../assets/images
:flag-devex-escape-hatch!:

[abstract]
Expand All @@ -14,12 +15,11 @@ include::partial$other-guide.adoc[]

== Introduction

A User-Defined Function can be called like any other {sqlpp} function.
The Javascript is not called directly; it is called through the {sqlpp} User-Defined Function.
A user-defined function can be called like any other {sqlpp} function.

== Calling the {sqlpp} User-Defined Function

An {sqlpp} User-Defined Function can be called from anywhere that a standard {sqlpp} function can be called.
An {sqlpp} user-defined function can be called from anywhere that a standard {sqlpp} function can be called.

[tabs]
====
Expand Down Expand Up @@ -67,7 +67,7 @@ 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.
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]
----
Expand All @@ -78,6 +78,6 @@ include::example$javascript-udfs/select-true-alias-get-business-days.n1ql[]
====


== Further Reading
== Related Links

include::partial$javascript-udfs/further-reading.adoc[tags="create-function;user-defined-functions"]
16 changes: 7 additions & 9 deletions modules/guides/pages/create-javascript-library.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
:page-edition: Enterprise Edition
:page-topic-type: guide
:page-toclevels: 2
:imagesdir: ../assets/images
:flag-devex-escape-hatch!:

[abstract]
Expand All @@ -14,13 +15,14 @@ include::partial$other-guide.adoc[]

== Introduction

In this guide you will learn how to create a library for storing JavaScript functions, and how to add a new function to the library.
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]
include::partial$query-tools.adoc[tags=body;!thumbs]

[#creating-the-library-and-adding-your-first-function]
== 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:
Expand All @@ -46,7 +48,7 @@ Query Workbench::
+
image::javascript-udfs/navigate-to-udf-query.png[alt="route to the user-defined functions screen"]

. Click on the *{plus} add function library* link in the `Javascript Function Libraries` table to show the `Add Library` screen.
. Click on the *{plus} add function library* link in the `JavaScript Function Libraries` table to show the `Add Library` screen.

. 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.
Expand Down Expand Up @@ -90,12 +92,8 @@ The parameters in the URL denote that the function should reside in the `travel-
--
====

You have now created your JavaScript library.
In the xref:create-user-defined-function.adoc[next step], you'll create an {sqlpp} User-Defined function that references your library function, so it can be called as part of any {sqlpp} statement.
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.



== Further Reading
== Related Links

include::partial$javascript-udfs/further-reading.adoc[tags="user-defined-functions-ui;rest-create-library-call"]

63 changes: 30 additions & 33 deletions modules/guides/pages/create-user-defined-function.adoc
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
= Creating a User-Defined Function
:description: How to create a user-defined function to call your JavaScript function.
:description: How to create a user-defined function to call external JavaScript code.
:page-pagination:
:page-edition: Enterprise Edition
:page-topic-type: guide
:page-toclevels: 2
:keywords: N1QL, UDF, user-defined function, SQL++
:imagesdir: ../assets/images
:flag-devex-escape-hatch!:

[abstract]
Expand All @@ -12,70 +14,63 @@
include::partial$other-guide.adoc[]
--

[#creating-the-n1ql-udf-function]
== Creating the {sqlpp} User-Defined Function
== Introduction

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.

Before you can run the JavaScript function you have created (see xref:create-javascript-library.adoc[]), you will need to create a {sqlpp} User-Defined Function to reference it.
You can create a {sqlpp} User-Defined Function by using:
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.

* the xref:tools:udfs-ui.adoc[UDF UI] in the Query Workbench.
* the xref:n1ql:n1ql-language-reference/createfunction.adoc[standard {sqlpp} `CREATE FUNCTION` DDL], using the _External Functions_ option to reference the Javascript function.
* the REST-API to execute a xref:n1ql:n1ql-language-reference/createfunction.adoc[`CREATE FUNCTION`] call.
[#creating-the-n1ql-udf-function]
== Creating a {sqlpp} User-Defined Function to Reference an External Library

For more information on {sqlpp} User Defined Functions in general, read xref:n1ql:n1ql-language-reference/userfun.adoc[].
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 {sqlpp} xref:n1ql:n1ql-language-reference/createfunction.adoc[CREATE FUNCTION] statement, and reference the external library and JavaScript function.

[tabs]
====
Query Workbench::
+
--
. Access the `UDF` screen from the administration console.
. Access the *UDF* screen from the administration console.
+
image::javascript-udfs/navigate-to-udf-query.png[]

. Click on the `{plus}{nbsp}add function` link from the `UDFs` screen.
. Click on the *{plus}{nbsp}add function* link.
+
image::javascript-udfs/my-library-list-add-function-button.png[alt="library list"]
+
which will display the `Add Function` screen.
The *Add Function* dialog is displayed.
+
image::javascript-udfs/add-function-dialog.png[ ,400]

. Use the `Namespace` drop-down lists to select the bucket and scope where your Javascript function resides.
. Use the *Namespace* drop-down lists to select the bucket and scope where your JavaScript function resides.

. Fill in the `Function Name` of your {sqlpp} User-Defined Function.
. Fill in the *Function Name* of your {sqlpp} user-defined function.

. Leave the `Parameters` as they are.
. Specify *Parameters* for the function.
+
NOTE: The `...` in the parameters box denotes a variable length list of parameters.
This is why you don't have to fill in this field.

. Select `Javascript` for the function type.
A field will appear in the dialog with a list of available libraries in the namespace you selected.
. Select *JavaScript* for the function type.
A field appears in the dialog with a list of available libraries in the namespace you selected.
+
image::javascript-udfs/add-function-dialog-switch-to-javascript.png[]
+
From this list select the library containing your function.
From this list select the library containing your function.

. Enter the name of the JavaScript function in the `Library Function Name` field.
--

REST API::
+
--
Run a `curl` command from the shell to add a {sqlpp} User-Defined Function that calls your Javascript function.

[source, console]
----
include::example$javascript-udfs/create-scoped-n1ql-udf-with-rest.sh[]
----
--

{sqlpp}::
+
--
Execute the `CREATE FUNCTION` in the CBQ Shell to create the {sqlpp} User-Defined Function:
Execute the `CREATE FUNCTION` in the CBQ Shell to create the {sqlpp} user-defined function:

[source, sqlpp]
----
Expand All @@ -84,6 +79,8 @@ include::example$javascript-udfs/create-scoped-n1ql-udf.n1ql[]
--
====

NOTE: The {sqlpp} User-Defined Function will take the same scope as the JavaScript UDF it is referencing.
NOTE: The {sqlpp} user-defined function will take the same scope as the JavaScript UDF it is referencing.

== Related Links

Having created your {sqlpp} User-Defined Function, the xref:call-user-defined-function.adoc[next step] is to use a {sqlpp} statement to call the function.
* 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].
16 changes: 1 addition & 15 deletions modules/guides/pages/javascript-udfs.adoc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
= User-defined Functions with JavaScript
= User-Defined Functions with JavaScript
:description: How to extend the {sqlpp} query language by adding your own functions written in JavaScript.
:page-pagination: next
:page-edition: Enterprise Edition
Expand Down Expand Up @@ -35,17 +35,3 @@ If you wish to look into the constructs and available in the language itself, th
* xref:javascript-udfs:calling-javascript-from-n1ql.adoc[]
* xref:javascript-udfs:calling-n1ql-from-javascript.adoc[]
* xref:javascript-udfs:handling-errors-javascript-udf.adoc[]














Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
== Introduction

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 our xref:guides:javascript-udfs.adoc[] guide.
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.

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.

In this section, we're going to take a closer look at concepts around {sqlpp} User-Defined Functions, such as variadic parameter lists.
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

Expand Down Expand Up @@ -94,7 +94,7 @@ include::example$select-true-alias-get-business-days.n1ql[]
== 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.
We can create the `GetBusinessDays` function using a variadic parameter rather than the `startDate` and `endDate` parameters:
You can create the `GetBusinessDays` function using a variadic parameter rather than the `startDate` and `endDate` parameters:

[source, sqlpp]
----
Expand Down
43 changes: 21 additions & 22 deletions modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
= Calling {sqlpp} from JavaScript
:description: Executing {sqlpp} statements from Javascript functions.
:description: Executing {sqlpp} statements from JavaScript functions.
:page-edition: Enterprise Edition
:page-toclevels: 2
:stem:
Expand All @@ -9,19 +9,19 @@

== Introduction

As well as being able to call JavaScript functions from {sqlpp}, you can also call {sqlpp} statements from inside your Javascript functions.
As well as being able to call JavaScript functions from {sqlpp}, you can also call {sqlpp} statements from inside your JavaScript functions.

[#calling-statements-inline]
== Calling {sqlpp} statements inline
== Calling {sqlpp} Statements Inline

You can embed a {sqlpp} statement directly in your Javascript code:
You can embed a {sqlpp} statement directly in your JavaScript code:

[source,javascript]
----
include::example$add-airline-inline-call.js[]
----

== Executing {sqlpp} statements using the N1QL() call
== Executing {sqlpp} Statements Using the N1QL() Call

In addition, you can also execute a {sqlpp} statement by calling it from the `N1QL(…)` function.
[source, javascript]
Expand All @@ -47,26 +47,26 @@ will generate an error because the `AddAirline()` function will attempt to alter
IMPORTANT: Functions that change data must be called using the `EXECUTE FUNCTION` statement.


== Returning values from {sqlpp} statements
== Returning Values from {sqlpp} Statements

As shown in the <<calling-statements-inline, examples above>>, embedded {sqlpp} statements return values which can be used later on in your code.

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, we're going to retrieve a list of the hotels stored in the `travel-sample` database:
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:

[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`.
<.> 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/{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 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.
Expand All @@ -77,9 +77,9 @@ include::partial$diagrams/inline-call-sequence.puml[]
....
====

== Passing Parameters to {sqlpp} statements
== Passing Parameters to {sqlpp} Statements

You can pass parameters from your Javascript to your {sqlpp} statements.
You can pass parameters from your JavaScript 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.
Expand All @@ -96,7 +96,7 @@ Named:: The parameters are given a mnemonic name attached to the value, so they
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.
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]
****
Expand All @@ -121,7 +121,7 @@ Inline calls only support named parameters.

== Transactions

Transactions are supported from {sqlpp} statements called from Javascript functions.
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.
Expand All @@ -140,13 +140,13 @@ include::partial$diagrams/transactions-and-iterators.puml[]

== Role-Based Access Control

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.
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.

== Executing {sqlpp} statements that call functions
== Executing {sqlpp} Statements that Call Functions

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.
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:

[source, javascript]
Expand All @@ -168,16 +168,15 @@ returns the following result:
----
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.
<.> 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.

asciimath:["Number of JavaScript Workers" = 4 xx "Number of CPUs"]

The service will automatically prevent recursive calls if there are less than 50% javascript workers available

The service will automatically prevent recursive calls if there are fewer than 50% JavaScript workers available.
====

== Further Reading
Expand Down
Loading