In previous blogs, we covered executing N1QL (SQL++) from JavaScript functions, processing documents through iterators, manipulating data, handling errors, prepared statements and other advanced topics. The final topic to cover is a newly added feature to 7.1 that enables JavaScript library storage options.
Hierarchical JavaScript library storage
Another major change in 7.1 is the JavaScript library storage having changed from flat to hierarchical.
This means that alongside global libraries, you can now have libraries created under a bucket and a scope.
Global libraries are available to use as both global and scope UDFs, while scope libraries are only available to use for scope UDFs created under the same scope as the library.
This means that while, by using global libraries, you can continue to treat libraries as an extension of your application, and by publishing a new library you automatically amend all its instances in different buckets and scope, if you only have been granted the manage_external_scope_functions privilege and want to create libraries for your own use, you can.
Or maybe as an application developer you may want to create scope specific implementations of certain global libraries, for instance a local instance with new code that you are implementing for the next release of your application.
Manipulating libraries
The jsevaluator REST endpoint used to manipulate libraries shown at the beginning of this blog has been extended to accept buckets and scope.
This is done like so:
Global library
1 |
curl -v -X POST http://localhost:8093/evaluator/v1/libraries/math -u Administrator:password -d 'function add(a, b) { let data = a + b; return data; }' |
Scope library
1 |
curl -v -X POST 'http://localhost:8093/evaluator/v1/libraries/math?bucket=b1&scope=s1' -u Administrator:password -d 'function add(a, b) { let data = a + b; return data; }' |
Clearly the authenticated user needs to have appropriate privileges to create libraries at each level: manage_external_functions for global libraries and manage_external_scope_functions for scope libraries.
Also, the referenced bucket and scope must already exist.
At the cost of repeating myself, the curl command must contain the whole library, not just any new function you may want to define: please remember that any change that you make is reflected across all UDFs using the library, and any function you may drop by mistake will potentially affect multiple scopes and UDFs, so be careful.
For the avoidance of doubt, this applies to the UI too.
Referencing libraries in UDFs
All the examples of CREATE FUNCTION seen so far use a simple string identifier for the library, meaning that they use a global library.
CREATE FUNCTION … LANGUAGE JAVASCRIPT supports the following three formats for library names:
-
- An identifier, e.g., “library“: this points to a global library
- The ./ notation, e.g., “./library“: this means a library under the current query_context, a global library for a global function and the corresponding scope library for a scope function
- A full scope path, e.g., “bucket/scope/library“: scope functions can point to scope libraries, but please be aware that cross scope pollination is not allowed – scope functions can only point to libraries in their own scope.
Any other library name format is disallowed.
Curl tips and tricks
Amending libraries
When amending libraries using the REST API, for example to add a new function, be mindful that you have to submit the whole library again: if you just pass the text of the new function, all the previous functions will be obliterated!
Useful command line switches and options
The curl –data-binary command line option instructs curl not to discard newlines and carriage returns.
This is useful in that, if your function returns an error, the error message will contain the correct line information for the error, vs using -d or –data will cause the errors to always be reported to have occurred in line 1!
As an example:
1 2 3 4 |
curl -v -X POST http://localhost:8093/evaluator/v1/libraries/math -u Administrator:password —data-binary 'function add(a, b) { let data = a + b; return data; }' |
Another useful feature is to save the contents of a library in a file, and then reference the file in the –data-binary (or -d) argument, by prefixing with a “@“, for instance:
1 |
curl -v -X POST http://localhost:8093/evaluator/v1/libraries/math -u Administrator:password –data-binary '@path/to/file' |
Where your library would be saved in path/to/file.
Conclusion
This brief post shows how these new storage options give you flexibility in how to hierarchically manage the code you build and deploy.
One final update for you, while there are code-based references to the term N1QL in this series, we refer to the query language as SQL++ – an extension of the SQL standard. Queries in Couchbase are generally SQL++ based, allowing you to build on your standard SQL querying knowledge but apply it to JSON documents and more. Going forward, you can likely swap the term N1QL for SQL++ and you’ll be all caught up to date.
Thank you for following along with this series of N1QL and JavaScript topics, a summary list of topics is included below for your reference.
Resources
-
- SQL++ – The next-generation query language for managin JSON data
- SQL++/N1QL to JavaScript and Back Series:
- SQL++ functions
- Processing documents through iterators
- Manipulating data
- Handling errors
- Prepared statements
- and other advanced topics
- This post, hierarchical JavaScript library storage