From 250c1d9034b7c69effcce54d34e2b2765de4b9b1 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Thu, 14 Mar 2024 11:56:11 +0000 Subject: [PATCH 01/16] Update EBNF syntax for CREATE FUNCTION --- modules/n1ql/partials/grammar/ddl.ebnf | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/n1ql/partials/grammar/ddl.ebnf b/modules/n1ql/partials/grammar/ddl.ebnf index 4938af0c6..76522d34f 100644 --- a/modules/n1ql/partials/grammar/ddl.ebnf +++ b/modules/n1ql/partials/grammar/ddl.ebnf @@ -179,7 +179,7 @@ create-function-inline ::= 'CREATE' ( 'OR' 'REPLACE' )? 'FUNCTION' function '(' /* tag::create-function-external[] */ create-function-external ::= 'CREATE' ( 'OR' 'REPLACE' )? 'FUNCTION' function '(' params? ')' ( 'IF' 'NOT' 'EXISTS' )? - 'LANGUAGE' 'JAVASCRIPT' 'AS' obj 'AT' library + 'LANGUAGE' 'JAVASCRIPT' 'AS' ( javascript | obj 'AT' library ) /* end::create-function-external[] */ /* tag::function[] */ @@ -194,6 +194,10 @@ params ::= identifier ( "," identifier )* | "..." body ::= expr /* end::body[] */ +/* tag::javascript[] */ +javascript ::= string +/* end::javascript[] */ + /* tag::obj[] */ obj ::= string /* end::obj[] */ From 975f222ec373f5171fa0574af4d7299756d822d9 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Thu, 14 Mar 2024 11:56:27 +0000 Subject: [PATCH 02/16] Update syntax diagrams --- .../create-function-external.png | Bin 20518 -> 23721 bytes .../n1ql-language-reference/javascript.png | Bin 0 -> 1401 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 modules/n1ql/assets/images/n1ql-language-reference/javascript.png diff --git a/modules/n1ql/assets/images/n1ql-language-reference/create-function-external.png b/modules/n1ql/assets/images/n1ql-language-reference/create-function-external.png index 2dbfd31724567cc2409aafe894912cca4df4dc1f..53233992386dd2474c3668cd3cc2fd9e8286ce6f 100644 GIT binary patch literal 23721 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 LYAKZ8w+{X<=FHBt literal 20518 zcmdSBWn5cb^Y2Ydfwp)l?ogyS#U-Q^YfFLRo)iu4E}=kicPQ@e?(SaPi%W0_E>F1b z>psu_oEPW)Nj^Yitv$2X+Op<5zaiketQ6*JlGjK`NSI$fiz^@@J%=G)@4iGu{7x=$ zrbPUq()+9+gM{QlkA(E|7ZTD9;-jBCNJ#b^NJx7>kdOr9k&p1>Kxw9YAqe~y~>oZ zoiS$)-Z1>EuT3KDu8$4ZRC{?obX^$~oWG*yW`2oB@z_TIb2Oc`C|>(pxiwgJt8#B^ z23=g$3ge{J(6Mr&@_N36yR&WLNcu&?kW)4bUsq9_1bTgIlu#HXCT`=h8r|p4-=*#E z566Yo&ZEI_NeMa6MsY;+HJVXj_H%MhceI*CE5$mE_C{mVAMjo?TOp>C(V9lzHzrXlW4*cZ3 zy;uK^)s1`@JimB-BH<+G(aS>`#ej0P6B(MT$Kc3JGc8rLLR17cE3?oa`LU$+@0MJ} z%xmX;2l$cT1IuSQu8&Fm>lwYsIUs8xAe1Tn;Kta)j(jcA!po=9S06rMAsBm94wmuPoU zu?XlHUGUKySFbWNoX->Pwn6!~)mc9~V^8@8Mv}04+w=VG`**akx1rf@*YqvkBW7l5 zp%{c+T|AJTB@VHN|Ni|7`q7blp$0pD+hyD*rIb~>o?>2O$hw~S=AFp3$g_xBxeTqQ zS{ZalErBfJ!}u{3gZ*{eOC{&#usE)p%hT>;yoHXrxiN}_lT!<_F9je0If?}mKJAG= zb{;1MdL|KuvasOv`}?Vb%wF`93-=cb+!>Kr^`X_?Yj~=*(0y�i{o_Qrwr%cVb}Q>hC3tHN%_aB8!aD4#zH01X~T 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 PJE5mzs9kW?;>kY&5AHzO diff --git a/modules/n1ql/assets/images/n1ql-language-reference/javascript.png b/modules/n1ql/assets/images/n1ql-language-reference/javascript.png new file mode 100644 index 0000000000000000000000000000000000000000..42231623b50e4cc4cfb70943fe20a6245dcf672b GIT binary patch literal 1401 zcmV-<1%~>GP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00004XF*Lt006O$eEU(800001 zb5ch_0Itp)=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01m_e01m_fl`9S#000Eg zNkl-bi zR<7mPa5J(9hh~}BQ<_l0U|#FbSiK^`aI8hbU2=SIJmoquJ3!h zJ@@c=zMt>DpBJCc^ZkCG=Kv<3kxYtC^*UI6J+PIH-jA(9s=*pdi+vVka%z?&{ra)u zm%Y6Z z=gR7*G=#~<*WR9oIc!F|UWXGxPQ~m}=<_en;m6WTqSvLTB_ldYGo@ipG`^4Nutpz; zKTT$|aOeEqtjq>A(`+WA4&Nx`*j7=8PJ1IUyC+ps*NWp`m!hZlCgz5#@lxhe+#MW7 z!{xuw)iZ!QcLt%2)F5N^5`0*6nm?8sFQcjXI$mDC0)O}2g4t~0ef?bCh{2&@boboE z>5@vQLsi(3^DJhE&EV~~$=AUn-@{n-JEFC-5E(HOOBTfK_7_|iU{DpcvnVN`cK@T7#IEW9pMjgUm zUqCRAeN~F2_-M>jt6;KNaP;_3m_xAUMbAdr#YPl;T7tFD8Ib<89;eRyf*m^#Yj|P}lees?O)b zUug@=x8E5hDZBT_*H4BsR9oH=g6I^cUF4ve@;}WgVmF!4LY)S>dr*s0VvraYg$0IO zB*bfxN|3f@r9m}axT{&32c7zq%m1Cgt5kt7(G81J^R-UO-mnpn?$TtQoN)1_5}a*&1Ehsx?Ed{lfEH@fX>9WKH0Wl6N834@=X*WUgR zjqkm`2||_KOY__09F-sV2x8tnG<0CVGHWtNHQ|EzxiqWu6Rz5N&300000NkvXX Hu0mjfx4@z$ literal 0 HcmV?d00001 From 0d1a6c76d2218dccd6f29a7cb1fc6a815145fa13 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Thu, 14 Mar 2024 12:02:22 +0000 Subject: [PATCH 03/16] Minor tweak to syntax diagram --- .../create-function-external.png | Bin 23721 -> 23668 bytes modules/n1ql/partials/grammar/ddl.ebnf | 10 +++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/n1ql/assets/images/n1ql-language-reference/create-function-external.png b/modules/n1ql/assets/images/n1ql-language-reference/create-function-external.png index 53233992386dd2474c3668cd3cc2fd9e8286ce6f..d8a611c093342208884beb9a51e124cf9fa6c7f8 100644 GIT binary patch literal 23668 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 literal 23721 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 LYAKZ8w+{X<=FHBt diff --git a/modules/n1ql/partials/grammar/ddl.ebnf b/modules/n1ql/partials/grammar/ddl.ebnf index 76522d34f..827efc4b9 100644 --- a/modules/n1ql/partials/grammar/ddl.ebnf +++ b/modules/n1ql/partials/grammar/ddl.ebnf @@ -179,7 +179,7 @@ create-function-inline ::= 'CREATE' ( 'OR' 'REPLACE' )? 'FUNCTION' function '(' /* tag::create-function-external[] */ create-function-external ::= 'CREATE' ( 'OR' 'REPLACE' )? 'FUNCTION' function '(' params? ')' ( 'IF' 'NOT' 'EXISTS' )? - 'LANGUAGE' 'JAVASCRIPT' 'AS' ( javascript | obj 'AT' library ) + 'LANGUAGE' 'JAVASCRIPT' 'AS' ( obj 'AT' library | javascript ) /* end::create-function-external[] */ /* tag::function[] */ @@ -194,10 +194,6 @@ params ::= identifier ( "," identifier )* | "..." body ::= expr /* end::body[] */ -/* tag::javascript[] */ -javascript ::= string -/* end::javascript[] */ - /* tag::obj[] */ obj ::= string /* end::obj[] */ @@ -206,6 +202,10 @@ obj ::= string library ::= string /* end::library[] */ +/* tag::javascript[] */ +javascript ::= string +/* end::javascript[] */ + /* tag::drop-function[] */ drop-function ::= 'DROP' 'FUNCTION' function ( 'IF' 'EXISTS' )? /* end::drop-function[] */ From ebe507568a6ed31605c6572ff55b61cf6618f7ff Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Thu, 14 Mar 2024 20:58:07 +0000 Subject: [PATCH 04/16] Update CREATE FUNCTION --- .../createfunction.adoc | 186 +++++++++++++----- 1 file changed, 135 insertions(+), 51 deletions(-) diff --git a/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc index d6af47dab..4828bda76 100644 --- a/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc @@ -5,6 +5,10 @@ :imagesdir: ../../assets/images :page-partial: :page-toclevels: 2 +:keywords: library namespacing + +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] [abstract] {description} @@ -13,13 +17,16 @@ There are two types of user-defined function: -* [def]_Inline functions_ are defined using {sqlpp} expressions, including subqueries. +* [def]_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. * [def]_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. +External 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]] === Global Functions and Scoped Functions @@ -46,7 +53,11 @@ Finally, it is important to note that a global function is _not_ the same as a s === External Libraries (((library namespacing))) -External functions are stored in _libraries_. +You can store external functions in _libraries_. +This enables you to share external function code in more than one user-defined function. + +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-api/functions.adoc[Functions REST API]. + Like user-defined functions, these libraries may also be scoped or global. This enables you to keep the code for external functions separate where required. @@ -56,21 +67,55 @@ Code which is stored in a _global library_ is available to users of all scopes. 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. -== RBAC Privileges +=== {sqlpp} Managed User-Defined Functions + +ifeval::['{page-component-version}' == '7.6'] +_(Introduced in Couchbase Server 7.6)_ +endif::[] + +In 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. + +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. + +== 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. -To manage global internal functions, you must have the *Manage Global Functions* role. -To manage scoped internal functions, you must have the *Manage Scope Functions* role, with permissions on the specified bucket and scope. +| Global external functions +| *Manage Global External Functions* role. -To manage global external functions, you must have the *Manage Global External Functions* role. -To manage scoped external functions, you must have the *Manage Scope External Functions* role, with permissions on the specified bucket and scope. +| 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. -To execute global internal functions, you must have the *Execute Global Functions* role. -To execute scoped internal functions, you must have the *Execute Scope Functions* role, with permissions on the specified bucket and scope. +[cols="2,3"] +|=== +| To execute ... | You must have ... -To execute global external functions, you must have the *Execute Global External Functions* role. -To execute scoped external functions, you must have the *Execute Scope External Functions* role, with permissions on the specified bucket and scope. +| 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:learn:security/authorization-overview.adoc[Authorization]. @@ -103,11 +148,30 @@ image::n1ql-language-reference/create-function-inline.png["Syntax diagram: refer // TODO: Automatic links in EBNF. -function:: (Required) Refer to <> below. +[horizontal.compact] +function:: <> icon:caret-down[] +params:: <> icon:caret-down[] +body:: <> icon:caret-down[] + +// tag::replace[] +[id='{section}-replace'] +==== OR REPLACE / IF NOT EXISTS + +The optional `OR REPLACE` clause enables you to redefine a user-defined function if it already exists, whereas the optional `IF NOT EXISTS` clause enables the statement to complete successfully without replacing the function. + +When a function with the same name already exists within the same context: +footnote:context[That is, you are creating a global function, and a function with the same name already exists within the same namespace; or, you are creating a scoped function, and a function with the same name already exists within the same scope.] + +* If the `OR REPLACE` clause is present, the existing function is replaced. -params:: (Optional) Refer to <> below. +* If the `IF NOT EXISTS` clause is present, the statement does nothing and completes without error. -body:: (Required) Refer to <> below. +* If neither of these two clauses is present, an error is generated. + +NOTE: These clauses are exclusive. +If the statement contains both the `OR REPLACE` clause and the `IF NOT EXISTS` clause, an error is generated. + +// end::replace[] // tag::arguments[] [id='{section}-name'] @@ -165,30 +229,12 @@ For inline functions, the result and type of the function are the result and typ If you need to return multiple values, construct an array. ==== -// tag::replace[] -[id='{section}-replace'] -==== OR REPLACE / IF NOT EXISTS - -The optional `OR REPLACE` clause enables you to redefine a user-defined function if it already exists, whereas the optional `IF NOT EXISTS` clause enables the statement to complete successfully without replacing the function. - -When a function with the same name already exists within the same context: -footnote:context[That is, you are creating a global function, and a function with the same name already exists within the same namespace; or, you are creating a scoped function, and a function with the same name already exists within the same scope.] - -* If the `OR REPLACE` clause is present, the existing function is replaced. - -* If the `IF NOT EXISTS` clause is present, the statement does nothing and completes without error. - -* If neither of these two clauses is present, an error is generated. - -NOTE: These clauses are exclusive. -If the statement contains both the `OR REPLACE` clause and the `IF NOT EXISTS` clause, an error is generated. - -// end::replace[] - [[create-function-external]] :section: external === External 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. + [source,ebnf] ---- include::partial$grammar/ddl.ebnf[tag=create-function-external] @@ -198,36 +244,46 @@ image::n1ql-language-reference/create-function-external.png["Syntax diagram: ref // TODO: Automatic links in EBNF. -function:: (Required) Refer to <> below. +[horizontal.compact] +function:: <> icon:caret-down[] +params:: <> icon:caret-down[] +obj:: <> icon:caret-down[] +library:: <> icon:caret-down[] +javascript:: <> icon:caret-down[] -params:: (Optional) Refer to <> below. - -obj:: (Required) Refer to <> below. - -library:: (Required) Refer to <> below. +include::createfunction.adoc[tag=replace] include::createfunction.adoc[tag=arguments] [[external-object]] ==== External Object +[Optional] Use this parameter where the function code is stored in an external library. + 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. -// FIXME: -External functions in {sqlpp} _only_ support plain JavaScript, without any of the xref:eventing:eventing-language-constructs.adoc#added-lang-features[added language features] supported by functions in the Eventing Service. [[external-library]] ==== External Library -The name of the JavaScript library that contains the function you want to use. +[Optional] Use this parameter where the function code is stored in an external library. + +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. -You must create the JavaScript library and the JavaScript function using the {sqlpp} Functions REST API. -For details, refer to xref:n1ql-rest-api/functions.adoc[Functions REST API]. 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`. -include::createfunction.adoc[tag=replace] +[[javascript]] +==== Function Body + +[Optional] Use this parameter to create a {sqlpp} managed user-defined function. + +The external JavaScript function code. +This must contain a function with the same name and the same number of parameters as the {sqlpp} user-defined function. +This parameter is a string and must be wrapped in quotes. + +The JavaScript code can contain multiple function definitions, but these functions can only be referenced within this {sqlpp} user-defined function, and cannot be shared. == Examples @@ -425,6 +481,32 @@ EXECUTE FUNCTION phi(); ---- ==== +[[ex-managed]] +.{sqlpp} managed user-defined function +==== +The following statement creates external JavaScript function code and the corresponding {sqlpp} user-defined function in one operation. + +[source,sqlpp] +---- +CREATE FUNCTION add100(num) LANGUAGE JAVASCRIPT AS +"function add100(param1) {return param1+100;}"; +---- + +.Test +[source,sqlpp] +---- +EXECUTE FUNCTION add100(100); +---- + +.Result +[source,json] +---- +[ + 200 +] +---- +==== + [[ex-external]] .External functions ==== @@ -572,8 +654,10 @@ At this level of precision, the geohash should appear to be in almost exactly th == Related Links -* To manage external libraries of user-defined functions, refer to xref:n1ql-rest-api/functions.adoc[Functions REST API]. -* To execute user-defined functions, refer to xref:n1ql-language-reference/execfunction.adoc[EXECUTE FUNCTION]. -* To include user-defined functions in an expression, refer to xref:n1ql-language-reference/userfun.adoc[User-Defined Functions]. -* To view user-defined functions, refer to xref:manage:monitor/monitoring-n1ql-query.adoc#sys-functions[Monitor Queries]. -* To drop user-defined functions, refer to xref:n1ql-language-reference/dropfunction.adoc[DROP FUNCTION]. +* To manage user-defined functions in the Query Workbench, see xref:tools:udfs-ui.adoc[]. +* To manage external libraries and external functions, see xref:n1ql-rest-api/functions.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[]. +* To monitor user-defined functions, see xref:manage:monitor/monitoring-n1ql-query.adoc#sys-functions[Monitor Functions]. +* To drop a user-defined function, see xref:n1ql-language-reference/dropfunction.adoc[]. From 95da70938605e398e5699590364bf55736f648c5 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Thu, 14 Mar 2024 21:01:36 +0000 Subject: [PATCH 05/16] Update DROP FUNCTION --- .../n1ql-language-reference/dropfunction.adoc | 62 +++++++++++++++---- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc index 21357a14b..922f4d4b9 100644 --- a/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc @@ -5,16 +5,30 @@ :imagesdir: ../../assets/images :page-partial: +// TEMP +include::partial$n1ql-language-reference/horizontal-style.adoc[] + [abstract] {description} -== RBAC Privileges +== Prerequisites + +[cols="2,3"] +|=== +| To manage ... | You must have ... + +| Global inline functions +| *Manage Global Functions* role. -To manage global internal functions, you must have the *Manage Global Functions* role. -To manage scoped internal functions, you must have the *Manage Scope Functions* role, with permissions on the specified bucket and scope. +| Scoped inline functions +| *Manage Scope Functions* role, with permissions on the specified bucket and scope. -To manage global external functions, you must have the *Manage Global External Functions* role. -To manage scoped external functions, you must have the *Manage Scope External 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:learn:security/authorization-overview.adoc[Authorization]. @@ -30,7 +44,8 @@ image::n1ql-language-reference/drop-function.png["Syntax diagram: refer to sourc // TODO: Automatic links in EBNF. -function:: (Required) Refer to <> below. +[horizontal.compact] +function:: <> icon:caret-down[] [[name]] === Function Name @@ -66,11 +81,12 @@ footnote:context[That is, you are dropping a global function, and the function d == Usage -When you drop an external user-defined function, the JavaScript library and function on which the user-defined function depended are not deleted. +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 the JavaScript library and the JavaScript function, you must use the {sqlpp} Functions REST API. -For details, refer to xref:n1ql-rest-api/functions.adoc[Functions REST API]. +To change or delete an external library or the external function code, you must use the xref:tools:udfs-ui.adoc[Query Workbench] or the {sqlpp} xref:n1ql-rest-api/functions.adoc[Functions REST API]. + +When you drop a {sqlpp} managed user-defined function, the associated external function code is deleted also. == Examples @@ -91,6 +107,23 @@ SELECT * FROM system:functions; ---- ==== +.Drop a {sqlpp} managed user-defined function +==== +This statement deletes a {sqlpp} managed user-defined called `add100`. + +[source,sqlpp] +---- +DROP FUNCTION add100 IF EXISTS; +---- + +You can run the following query to check that the function is no longer available. + +[source,sqlpp] +---- +SELECT * FROM system:functions; +---- +==== + .Drop an external function ==== These statements delete two external functions: @@ -117,7 +150,10 @@ http://localhost:8093/evaluator/v1/libraries/geohash-js \ == Related Links -* To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[CREATE FUNCTION]. -* To execute user-defined functions, refer to xref:n1ql-language-reference/execfunction.adoc[EXECUTE FUNCTION]. -* To include user-defined functions in an expression, refer to xref:n1ql-language-reference/userfun.adoc[User-Defined Functions]. -* To view user-defined functions, refer to xref:manage:monitor/monitoring-n1ql-query.adoc#sys-functions[Monitor Queries]. +* To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. +* To manage user-defined functions in the Query Workbench, see xref:tools:udfs-ui.adoc[]. +* To manage external libraries and external functions, see xref:n1ql-rest-api/functions.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[]. +* To monitor user-defined functions, see xref:manage:monitor/monitoring-n1ql-query.adoc#sys-functions[Monitor Functions]. From c509674a56e28a3a52f9f3e2f0b80b63b13a2437 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Thu, 14 Mar 2024 21:01:48 +0000 Subject: [PATCH 06/16] Update EXECUTE FUNCTION --- .../n1ql-language-reference/execfunction.adoc | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc index 260d5f904..0fadddf1c 100644 --- a/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/execfunction.adoc @@ -11,17 +11,6 @@ include::partial$n1ql-language-reference/horizontal-style.adoc[] [abstract] The `EXECUTE FUNCTION` statement enables you to execute a user-defined function. -== RBAC Privileges - -To execute global internal functions, you must have the *Execute Global Functions* role. -To execute scoped internal functions, you must have the *Execute Scope Functions* role, with permissions on the specified bucket and scope. - -To execute global external functions, you must have the *Execute Global External Functions* role. -To execute scoped external functions, you must have the *Execute Scope External Functions* role, with permissions on the specified bucket and scope. - -For more details about user roles, see -xref:learn:security/authorization-overview.adoc[Authorization]. - == Purpose The `EXECUTE FUNCTION` statement enables you to execute a user-defined function. @@ -31,6 +20,28 @@ It also enables you to execute functions which have side effects, such as perfor You cannot use the `EXECUTE FUNCTION` statement to execute a built-in {sqlpp} function. 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:learn:security/authorization-overview.adoc[Authorization]. + == Syntax [source,ebnf] @@ -81,7 +92,10 @@ 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[CREATE FUNCTION]. -* To include user-defined functions in an expression, refer to xref:n1ql-language-reference/userfun.adoc[User-Defined Functions]. -* To view user-defined functions, refer to xref:manage:monitor/monitoring-n1ql-query.adoc#sys-functions[Monitor Queries]. -* To drop user-defined functions, refer to xref:n1ql-language-reference/dropfunction.adoc[DROP FUNCTION]. +* To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. +* To manage user-defined functions in the Query Workbench, see xref:tools:udfs-ui.adoc[]. +* To manage external libraries and external functions, see xref:n1ql-rest-api/functions.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:manage:monitor/monitoring-n1ql-query.adoc#sys-functions[Monitor Functions]. +* To drop a user-defined function, see xref:n1ql-language-reference/dropfunction.adoc[]. From b412b0ccc3e9315bb5270e8878b312fa80013f2e Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Thu, 14 Mar 2024 21:02:43 +0000 Subject: [PATCH 07/16] Update EXPLAIN FUNCTION --- .../explainfunction.adoc | 65 ++++++++++++++----- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc index ecd739a1c..6bedb21ae 100644 --- a/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/explainfunction.adoc @@ -4,12 +4,14 @@ :imagesdir: ../../assets/images // TEMP -include::partial$n1ql-language-reference/collapsible-style.adoc[] +include::partial$n1ql-language-reference/horizontal-style.adoc[] [abstract] {description} -You can supply the name of an inline or external user-defined function. +== Purpose + +You can request the execution plan for an inline or external user-defined function. * For an inline function, EXPLAIN FUNCTION returns the query plans for all of the subqueries present in the function body. + @@ -28,17 +30,22 @@ The following constraints apply: == Prerequisites -To execute EXPLAIN FUNCTION on an inline user-defined function, you must have the necessary execute function permission on that function. - -* For a global internal function, you must have the Execute Global Functions role. +[cols="2,3"] +|=== +| To execute EXPLAIN FUNCTION on ... | You must have ... -* For a scoped internal function, you must have the Execute Scope Functions role, with permissions on the specified bucket and scope. +| Global inline functions +| *Execute Global Functions* role. -To execute EXPLAIN FUNCTION on an external user-defined JavaScript function, you must have the necessary execute external function permission on that function. +| Scoped inline functions +| *Execute Scope Functions* role, with permissions on the specified bucket and scope. -* For a global JavaScript function, you must have the Execute Global External Functions role. +| Global external functions +| *Execute Global External Functions* role. -* For a scoped JavaScript function, you must have the Execute External Scope Functions role, with permissions on the specified bucket and scope. +| Scoped external functions +| *Execute Scope External Functions* role, with permissions on the specified bucket and scope. +|=== You must also have the necessary privileges required for the {sqlpp} statements inside the function. @@ -54,14 +61,33 @@ include::partial$grammar/utility.ebnf[tag=explain-function] image::n1ql-language-reference/explain-function.png["Syntax diagram: refer to source code listing", align=left] -The statement consists of the `EXPLAIN FUNCTION` keywords followed by the name of the user-defined function that has the execution plan you want to review. +[horizontal.compact] +function:: <> icon:caret-down[] + +[[name]] +=== Function Name + +[source,ebnf] +---- +include::partial$grammar/ddl.ebnf[tag=function] +---- + +image::n1ql-language-reference/function.png["Syntax diagram", align=left] -For more information about function name syntax and requirements, see xref:n1ql-language-reference/createfunction.adoc#inline-name[CREATE FUNCTION]. +The name of the function. +This is usually an unqualified identifier, such as `func1` or `{backtick}func-1{backtick}`. +In this case, the path to the function is determined by the current xref:n1ql:n1ql-intro/queriesandresults.adoc#query-context[query context]. + +To get the plan for a global function in a particular namespace, the function name must be a qualified identifier with a namespace, such as `default:func1`. +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. + +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. == Examples .Inline Function Example - ==== In this example, you create an inline function named `func1` and then request the plan for its subquery. @@ -78,7 +104,6 @@ include::n1ql:example$utility/explainfunction.jsonc[] ==== .External Function Example - ==== This example assumes that you have defined a JavaScript library named `lib1`. @@ -105,6 +130,16 @@ include::n1ql:example$utility/explainfunctionjs.n1ql[] include::n1ql:example$utility/explainfunctionjs.jsonc[] ---- -<.> The line number in the JavaScript function that includes a N1QL() call. +<.> The line number in the JavaScript function that includes a N1QL() call. <.> The query plan for the embedded {sqlpp} statement. -==== \ No newline at end of file +==== + +== Related Links + +* To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. +* To manage user-defined functions in the Query Workbench, see xref:tools:udfs-ui.adoc[]. +* To manage external libraries and external functions, see xref:n1ql-rest-api/functions.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:manage:monitor/monitoring-n1ql-query.adoc#sys-functions[Monitor Functions]. +* To drop a user-defined function, see xref:n1ql-language-reference/dropfunction.adoc[]. From d803eac68133bca72abf7e1390157f97edd05c7a Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Thu, 14 Mar 2024 21:03:24 +0000 Subject: [PATCH 08/16] Update User-Defined Functions --- .../n1ql-language-reference/userfun.adoc | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/modules/n1ql/pages/n1ql-language-reference/userfun.adoc b/modules/n1ql/pages/n1ql-language-reference/userfun.adoc index acacc18e0..6aa54a14c 100644 --- a/modules/n1ql/pages/n1ql-language-reference/userfun.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/userfun.adoc @@ -8,17 +8,6 @@ [abstract] {description} -== RBAC Privileges - -To execute global internal functions, you must have the *Execute Global Functions* role. -To execute scoped internal functions, you must have the *Execute Scope Functions* role, with permissions on the specified bucket and scope. - -To execute global external functions, you must have the *Execute Global External Functions* role. -To execute scoped external functions, you must have the *Execute Scope External Functions* role, with permissions on the specified bucket and scope. - -For more details about user roles, see -xref:learn:security/authorization-overview.adoc[Authorization]. - == Description When you have created a user-defined function, you can call it in any expression, just like a built-in function. @@ -37,6 +26,28 @@ You must call the user-defined function using the same case that was used when i It is not possible to call a user-defined function in an expression if the function has side effects, such as performing mutations. 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:learn:security/authorization-overview.adoc[Authorization]. + == Arguments A user-defined function has zero, one, or more arguments, separated by commas, just like a built-in function. @@ -175,7 +186,10 @@ 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[CREATE FUNCTION]. -* To execute user-defined functions, refer to xref:n1ql-language-reference/execfunction.adoc[EXECUTE FUNCTION]. -* To view user-defined functions, refer to xref:manage:monitor/monitoring-n1ql-query.adoc#sys-functions[Monitor Queries]. -* To drop user-defined functions, refer to xref:n1ql-language-reference/dropfunction.adoc[DROP FUNCTION]. +* To create user-defined functions, refer to xref:n1ql-language-reference/createfunction.adoc[]. +* To manage user-defined functions in the Query Workbench, see xref:tools:udfs-ui.adoc[]. +* To manage external libraries and external functions, see xref:n1ql-rest-api/functions.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 monitor user-defined functions, see xref:manage:monitor/monitoring-n1ql-query.adoc#sys-functions[Monitor Functions]. +* To drop a user-defined function, see xref:n1ql-language-reference/dropfunction.adoc[]. From 3fc653c20c67d01ec002cee37ca2e24095942dd4 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Thu, 14 Mar 2024 21:12:23 +0000 Subject: [PATCH 09/16] Standardize capitalization in JavaScript reference --- .../pages/calling-n1ql-from-javascript.adoc | 31 +++++++++---------- .../pages/handling-errors-javascript-udf.adoc | 6 ++-- .../javascript-functions-with-couchbase.adoc | 4 +-- .../javascript-udfs/partials/diagrams.adoc | 2 +- .../partials/libraries-and-scopes.adoc | 2 +- 5 files changed, 22 insertions(+), 23 deletions(-) diff --git a/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc b/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc index bb47eee6c..453a7b4af 100644 --- a/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc +++ b/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc @@ -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: @@ -9,12 +9,12 @@ == 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 -You can embed a {sqlpp} statement directly in your Javascript code: +You can embed a {sqlpp} statement directly in your JavaScript code: [source,javascript] ---- @@ -51,7 +51,7 @@ IMPORTANT: Functions that change data must be called using the `EXECUTE FUNCTION As shown in the <>, 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. +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: [source, javascript] @@ -60,13 +60,13 @@ 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. @@ -79,7 +79,7 @@ include::partial$diagrams/inline-call-sequence.puml[] == 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. @@ -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] **** @@ -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. @@ -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 -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] @@ -168,7 +168,7 @@ 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] ==== @@ -176,8 +176,7 @@ 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 diff --git a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc index 053a78a77..13cca99c7 100644 --- a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc +++ b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc @@ -1,5 +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. += 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. :page-edition: Enterprise Edition :page-topic-type: guide :page-toclevels: 2 @@ -22,7 +22,7 @@ then an error object is returned: include::example$duplicate-key-error.json5[] ---- -In most cases, it's a lot better if the Javascript function itself can handle errors that are likely to occur. +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. The following function will add an airline record, but will return an `failure` message if the attempt isn't successful. diff --git a/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc b/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc index 6970d51d3..a3d44f65f 100644 --- a/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc +++ b/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc @@ -15,7 +15,7 @@ If you want to learn how to create JavaScript function libraries using the admin == Added Constructs -Javascript functions in Couchbase 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. +JavaScript functions in Couchbase 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. === {sqlpp} Embedded Statements @@ -49,7 +49,7 @@ 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. -Arrow functions local to individual javascript functions are supported. +Arrow functions local to individual JavaScript functions are supported. === Logging diff --git a/modules/javascript-udfs/partials/diagrams.adoc b/modules/javascript-udfs/partials/diagrams.adoc index f726f5813..66229646d 100644 --- a/modules/javascript-udfs/partials/diagrams.adoc +++ b/modules/javascript-udfs/partials/diagrams.adoc @@ -30,7 +30,7 @@ include::diagrams/udf-scopes-diagram.puml[] include::diagrams/banking-scope-scenario.puml[] .... -.Javascript UDFs Structure +.JavaScript UDFs Structure [plantuml] .... include::diagrams/javascript-scopes.puml[] diff --git a/modules/javascript-udfs/partials/libraries-and-scopes.adoc b/modules/javascript-udfs/partials/libraries-and-scopes.adoc index 05dfefbe2..1c235bac7 100644 --- a/modules/javascript-udfs/partials/libraries-and-scopes.adoc +++ b/modules/javascript-udfs/partials/libraries-and-scopes.adoc @@ -8,7 +8,7 @@ JavaScript functions are stored inside a _library_. A library can contain one or more functions, and can also be assigned to a scope, which allows libraries to be partitioned for logical grouping. // tag::scoping-diagram[] -.Javascript UDFs Structure +.JavaScript UDFs Structure [plantuml#javascript-scopes,javascript-scopes,svg] .... include::partial$diagrams/javascript-scopes.puml[] From 2100488bcaa1f5f12fad6fa5c15d6be95c15c782 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Thu, 14 Mar 2024 21:16:04 +0000 Subject: [PATCH 10/16] Remove 1st person from JavaScript UDF reference --- .../javascript-udfs/pages/calling-javascript-from-n1ql.adoc | 6 +++--- .../javascript-udfs/pages/calling-n1ql-from-javascript.adoc | 2 +- .../pages/handling-errors-javascript-udf.adoc | 6 +++--- .../pages/javascript-functions-with-couchbase.adoc | 6 +++--- modules/javascript-udfs/partials/libraries-and-scopes.adoc | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc b/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc index eb4fefaf3..44d2b6773 100644 --- a/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc +++ b/modules/javascript-udfs/pages/calling-javascript-from-n1ql.adoc @@ -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 @@ -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] ---- diff --git a/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc b/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc index 453a7b4af..9e74d0f53 100644 --- a/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc +++ b/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc @@ -52,7 +52,7 @@ IMPORTANT: Functions that change data must be called using the `EXECUTE FUNCTION As shown in the <>, 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: +In the next example, you're going to retrieve a list of the hotels stored in the `travel-sample` database: [source, javascript] ---- diff --git a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc index 13cca99c7..e0ee779f7 100644 --- a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc +++ b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc @@ -8,7 +8,7 @@ {description} 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. -For example, if we execute a record insertion function with a key that already exists: +For example, if you execute a record insertion function with a key that already exists: [source, sqlpp] ---- @@ -39,7 +39,7 @@ If the record key already exists, then calling this method with `EXECUTE FUNCTIO include::example$add-airline-with-check-failure-return-response.jsonc[] ---- -Alternatively, we can simply throw the error, rather than returning it as a string: +Alternatively, you can simply throw the error, rather than returning it as a string: [source, javascript] ---- @@ -93,7 +93,7 @@ This code will send back the entire message structure. include::example$parsed-error-in-full.json5[] ---- -Once we know the structure of the error message, there's no reason why we can't carry out alternative actions depending on the type of error encountered: +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: [source, javascript] ---- diff --git a/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc b/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc index a3d44f65f..e3c82c9f2 100644 --- a/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc +++ b/modules/javascript-udfs/pages/javascript-functions-with-couchbase.adoc @@ -11,7 +11,7 @@ include::partial$javascript-udf-introduction.adoc[] -If you want to learn how to create JavaScript function libraries using the administration console and/or the REST-API then take a look at our xref:guides:javascript-udfs.adoc[JavaScript UDF Guides]. +If you want to learn how to create JavaScript function libraries using the administration console and/or the REST-API then take a look at the xref:guides:javascript-udfs.adoc[JavaScript UDF Guides]. == Added Constructs @@ -29,7 +29,7 @@ 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. -We can even provide parameters that can be used in the {sqlpp} statement. +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. include::partial$libraries-and-scopes.adoc[leveloffset=+2] @@ -55,7 +55,7 @@ Arrow functions local to individual JavaScript functions are supported. Logging using the `console.log(..)` function is not supported. -In the rest of this section, we're going to look at the concepts behind JavaScript User-Defined Functions: +In the rest of this section, you're going to look at the concepts behind JavaScript User-Defined Functions: * xref:calling-javascript-from-n1ql.adoc[] * xref:calling-n1ql-from-javascript.adoc[] diff --git a/modules/javascript-udfs/partials/libraries-and-scopes.adoc b/modules/javascript-udfs/partials/libraries-and-scopes.adoc index 1c235bac7..caeb50423 100644 --- a/modules/javascript-udfs/partials/libraries-and-scopes.adoc +++ b/modules/javascript-udfs/partials/libraries-and-scopes.adoc @@ -20,7 +20,7 @@ As shown in xref:javascript-scopes[xrefstyle=short], a JavaScript function libra * A library accessible within a scope. // end::scoping-diagram[] -NOTE: You can find an introduction to scopes in our xref:tutorials:buckets-scopes-and-collections.adoc#scopes_and_collections[Couchbase Tutorials]. +NOTE: You can find an introduction to scopes in the xref:tutorials:buckets-scopes-and-collections.adoc#scopes_and_collections[Couchbase Tutorials]. Furthermore, access restrictions can be applied to scopes, so that only certain groups of users will be able to access collections and libraries within that scope. From 78d650aa4329ab98a1bc5a0155c149185280cfcb Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Thu, 14 Mar 2024 21:33:16 +0000 Subject: [PATCH 11/16] Title case for headings in JavaScript UDF reference --- .../pages/calling-n1ql-from-javascript.adoc | 10 +++++----- .../pages/handling-errors-javascript-udf.adoc | 17 ++++++++++++----- .../partials/javascript-udf-introduction.adoc | 2 +- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc b/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc index 9e74d0f53..ac558874e 100644 --- a/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc +++ b/modules/javascript-udfs/pages/calling-n1ql-from-javascript.adoc @@ -12,7 +12,7 @@ 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: @@ -21,7 +21,7 @@ You can embed a {sqlpp} statement directly in your JavaScript code: 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] @@ -47,7 +47,7 @@ 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 <>, embedded {sqlpp} statements return values which can be used later on in your code. @@ -77,7 +77,7 @@ 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. Parameters can either be _positional_ or _named_. @@ -142,7 +142,7 @@ include::partial$diagrams/transactions-and-iterators.puml[] 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. diff --git a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc index e0ee779f7..2d8e966c9 100644 --- a/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc +++ b/modules/javascript-udfs/pages/handling-errors-javascript-udf.adoc @@ -1,12 +1,14 @@ = 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. :page-edition: Enterprise Edition -:page-topic-type: guide +:page-topic-type: reference :page-toclevels: 2 [abstract] {description} +== 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. For example, if you execute a record insertion function with a key that already exists: @@ -22,6 +24,8 @@ then an error object is returned: include::example$duplicate-key-error.json5[] ---- +== 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. @@ -53,16 +57,15 @@ which will produce the following result: 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: +As well as wrapping the expection in a detailed JSON object, there is another fundamental difference between throwing an error or returning it. + +=== Throw vs Return -.Throw vs Return -**** Aside from the data returned, throwing an error or returning a value/error will affect how subsequent {sqlpp} operations are processed. *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. *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. -**** You can, of course, throw the error object itself, rather than just a string. @@ -78,6 +81,8 @@ which deliver a lot more useful information than just posting back a string: include::example$add-airline-with-check-failure-throw-object-response.jsonc[] ---- +=== Parse the Error + Another approach is to parse the error using the `JSON.parse()` function and return the resulting object: [source, javascript] @@ -93,6 +98,8 @@ This code will send back the entire message structure. include::example$parsed-error-in-full.json5[] ---- +=== Carry Out Alternative Actions + 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: [source, javascript] diff --git a/modules/javascript-udfs/partials/javascript-udf-introduction.adoc b/modules/javascript-udfs/partials/javascript-udf-introduction.adoc index 4457fed22..9642d4628 100644 --- a/modules/javascript-udfs/partials/javascript-udf-introduction.adoc +++ b/modules/javascript-udfs/partials/javascript-udf-introduction.adoc @@ -5,7 +5,7 @@ Shouldn't be too JavaScript specific. {sqlpp} includes a large number of xref:n1ql:n1ql-language-reference/index.adoc[operations and generic functions] that cover every aspect of data manipulation. In addition to the built-in functions, Couchbase also allows you to create your own extensions to the language. -Using User-Defined Functions, you can: +Using user-defined functions, you can: * Create reuseable, domain-specific functions for use in your applications. * Execute complex logic that may be difficult to do in {sqlpp}. From b41e4fa6ba343bbdffbc27398013e37fdca4a0b3 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Thu, 14 Mar 2024 21:33:34 +0000 Subject: [PATCH 12/16] Update JavaScript UDF reference --- modules/javascript-udfs/partials/libraries-and-scopes.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/javascript-udfs/partials/libraries-and-scopes.adoc b/modules/javascript-udfs/partials/libraries-and-scopes.adoc index caeb50423..2311f85cf 100644 --- a/modules/javascript-udfs/partials/libraries-and-scopes.adoc +++ b/modules/javascript-udfs/partials/libraries-and-scopes.adoc @@ -4,7 +4,7 @@ The libraries and scope section can be reused in the guides section [#libraries-and-scopes] = Libraries and Scopes -JavaScript functions are stored inside a _library_. +JavaScript functions can be stored inside a _library_. A library can contain one or more functions, and can also be assigned to a scope, which allows libraries to be partitioned for logical grouping. // tag::scoping-diagram[] From 8c27b00cfe1e10b3cbbf692b0cfc0c8c6bdaae47 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Fri, 15 Mar 2024 10:53:42 +0000 Subject: [PATCH 13/16] Standardize capitalization and wording in JavaScript guides --- .../pages/call-user-defined-function.adoc | 10 ++++----- .../pages/create-javascript-library.adoc | 10 ++++----- .../pages/create-user-defined-function.adoc | 22 +++++++++---------- modules/guides/pages/javascript-udfs.adoc | 16 +------------- 4 files changed, 21 insertions(+), 37 deletions(-) diff --git a/modules/guides/pages/call-user-defined-function.adoc b/modules/guides/pages/call-user-defined-function.adoc index 0891a1c2e..ef8f343bf 100644 --- a/modules/guides/pages/call-user-defined-function.adoc +++ b/modules/guides/pages/call-user-defined-function.adoc @@ -14,12 +14,12 @@ 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. +The JavaScript is not called directly; it is called through the {sqlpp} user-defined 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] ==== @@ -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] ---- @@ -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"] \ 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 ca0f7a796..28a47234a 100644 --- a/modules/guides/pages/create-javascript-library.adoc +++ b/modules/guides/pages/create-javascript-library.adoc @@ -14,7 +14,8 @@ 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] @@ -46,7 +47,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. @@ -93,9 +94,6 @@ 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. - - -== Further Reading +== Related Links include::partial$javascript-udfs/further-reading.adoc[tags="user-defined-functions-ui;rest-create-library-call"] - diff --git a/modules/guides/pages/create-user-defined-function.adoc b/modules/guides/pages/create-user-defined-function.adoc index cf788320d..2e4566375 100644 --- a/modules/guides/pages/create-user-defined-function.adoc +++ b/modules/guides/pages/create-user-defined-function.adoc @@ -13,13 +13,13 @@ include::partial$other-guide.adoc[] -- [#creating-the-n1ql-udf-function] -== Creating the {sqlpp} User-Defined Function +== Creating a {sqlpp} User-Defined Function -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: +Before you can run a 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: * 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 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. For more information on {sqlpp} User Defined Functions in general, read xref:n1ql:n1ql-language-reference/userfun.adoc[]. @@ -42,16 +42,16 @@ which will display the `Add Function` screen. + 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. + 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. +. Select `JavaScript` for the function type. A field will appear in the dialog with a list of available libraries in the namespace you selected. + image::javascript-udfs/add-function-dialog-switch-to-javascript.png[] @@ -64,7 +64,7 @@ From this list select the library containing your function. REST API:: + -- -Run a `curl` command from the shell to add a {sqlpp} User-Defined Function that calls your Javascript function. +Run a `curl` command from the shell to add a {sqlpp} user-defined function that calls your JavaScript function. [source, console] ---- @@ -75,7 +75,7 @@ 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] ---- @@ -84,6 +84,6 @@ 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. -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. +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. diff --git a/modules/guides/pages/javascript-udfs.adoc b/modules/guides/pages/javascript-udfs.adoc index e308e296c..48b0fb4e4 100644 --- a/modules/guides/pages/javascript-udfs.adoc +++ b/modules/guides/pages/javascript-udfs.adoc @@ -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 @@ -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[] - - - - - - - - - - - - - - From 40b646fb680fde6d2b690d4abfdfe08c89fd16e8 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Fri, 15 Mar 2024 11:24:43 +0000 Subject: [PATCH 14/16] Temporary fixup for JavaScript UDF guide --- .../pages/call-user-defined-function.adoc | 2 +- .../pages/create-javascript-library.adoc | 6 +- .../pages/create-user-defined-function.adoc | 59 +++++++++---------- 3 files changed, 32 insertions(+), 35 deletions(-) diff --git a/modules/guides/pages/call-user-defined-function.adoc b/modules/guides/pages/call-user-defined-function.adoc index ef8f343bf..33d7890dc 100644 --- a/modules/guides/pages/call-user-defined-function.adoc +++ b/modules/guides/pages/call-user-defined-function.adoc @@ -4,6 +4,7 @@ :page-edition: Enterprise Edition :page-topic-type: guide :page-toclevels: 2 +:imagesdir: ../assets/images :flag-devex-escape-hatch!: [abstract] @@ -15,7 +16,6 @@ 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. == Calling the {sqlpp} User-Defined Function diff --git a/modules/guides/pages/create-javascript-library.adoc b/modules/guides/pages/create-javascript-library.adoc index 28a47234a..ee9d7ebf6 100644 --- a/modules/guides/pages/create-javascript-library.adoc +++ b/modules/guides/pages/create-javascript-library.adoc @@ -4,6 +4,7 @@ :page-edition: Enterprise Edition :page-topic-type: guide :page-toclevels: 2 +:imagesdir: ../assets/images :flag-devex-escape-hatch!: [abstract] @@ -21,7 +22,7 @@ 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: @@ -91,8 +92,7 @@ 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. == Related Links diff --git a/modules/guides/pages/create-user-defined-function.adoc b/modules/guides/pages/create-user-defined-function.adoc index 2e4566375..102d037b0 100644 --- a/modules/guides/pages/create-user-defined-function.adoc +++ b/modules/guides/pages/create-user-defined-function.adoc @@ -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] @@ -12,66 +14,59 @@ include::partial$other-guide.adoc[] -- -[#creating-the-n1ql-udf-function] -== Creating a {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 a 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}:: + -- @@ -86,4 +81,6 @@ 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. -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. +== Related Links + +* 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]. From 16ddb1cfe9bdd5bea3fda5cca79fd46cfaafb610 Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Fri, 15 Mar 2024 11:54:23 +0000 Subject: [PATCH 15/16] Minor fix --- modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc index 922f4d4b9..8675c9e3f 100644 --- a/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/dropfunction.adoc @@ -109,7 +109,7 @@ SELECT * FROM system:functions; .Drop a {sqlpp} managed user-defined function ==== -This statement deletes a {sqlpp} managed user-defined called `add100`. +This statement deletes a {sqlpp} managed user-defined function called `add100`. [source,sqlpp] ---- From ad94ce10cd713833b16a00ef62fbf25cd445c59e Mon Sep 17 00:00:00 2001 From: Simon Dew Date: Fri, 15 Mar 2024 17:52:06 +0000 Subject: [PATCH 16/16] Update after review --- modules/n1ql/pages/n1ql-language-reference/createfunction.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc b/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc index 4828bda76..57a89ccba 100644 --- a/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc +++ b/modules/n1ql/pages/n1ql-language-reference/createfunction.adoc @@ -283,7 +283,7 @@ The external JavaScript function code. This must contain a function with the same name and the same number of parameters as the {sqlpp} user-defined function. This parameter is a string and must be wrapped in quotes. -The JavaScript code can contain multiple function definitions, but these functions can only be referenced within this {sqlpp} user-defined function, and cannot be shared. +The JavaScript code can contain multiple function definitions, but these functions can only be referenced within the JavaScript code for this {sqlpp} user-defined function, and cannot be shared. == Examples