
DovetailDB supports Javascript stored procedures that will execute remotely. This feature allows you to perform complex operations and calculations that would otherwise be prohibitive to perform on the client side. It can also be used to control access to data in a highly customizable manner. The following steps will walk you through the processes of creating and calling code in the server.
To begin, make sure you've got an accesskey or go get one.
Then, log into the management interface with your accesskey:
Find or create a database to work with, and click on the "(code)" link:
Create a new server-side javascript file, or edit an existing one.
For the filename, you can type any descriptive name that you like. In the large text area, you may start entering some javascript functions.
When done, click "save". You may now invoke the dovetail.call() method to call these functions on the DovetailDB server.
The same functions available in the client library are also available on the server, but with some variations. For this reason, they are not namespaced under "dovetail", but "_server". Thus, when writing code for the server, you type _server.query() instead of dovetail.query().
On the server side, API calls block - they are not asynchronous. When calling the _server functions, you never specify a callback function. Instead, the parameter that would have been passed to the callback is returned directly from the function itself. These two examples demonstrate the differences between calling query() on the client (first) and the server (second):
dovetail.query("people", {age_is:4}, function(kids){ something(kids); });var kids = _server.query("people", {age_is:4});
something(kids);You can register Javascript functions to intercept insert(), update(), remove(), and even query() calls. These correspond roughly to triggers in a relational database, but are implemented more like "around advice" in AOP jargon. You can set hooks by calling the following methods in one of your server-side code files. Each method takes a single parameter, which should be a function that will intercept calls of the appropriate type.
Each of these handler functions should take the same parameter list as the call it is intercepting. For instance, a query hook function should accept three parameters: a bag name, a constriants object, and an options object.
When a hook is defined, the registered handler function is called instead of the action that would otherwise take place. You may invoke the original operation by passing the handler's arguemnts to _server.inner.query(), _server.inner.insert(), _server.inner.update(), or _server.inner.remove(), as appropriate.
You normally do not want to call _server.query() from within a query hook, as that call will be subject to the same hook, and you may enter an infinite loop. Refer to the diagram below to help you understand how Javascript hooks influence the normal execution of a query.
Javascript hook examples:
// Force every object to store the time it was inserted into a member called "insertedTimestamp"
function insertHandler(bag, entry, options) {
entry.insertedTimestamp=new Date().getTime();
return _server.inner.insert(bag, entry, options);
}
_server.setInsertHook(insertHandler);
// Nobody can query for people whose status is "hidden":
function queryHandler(bag, query, options) {
query.status_notin = ['hidden'];
return _server.inner.query(bag, query, options);
}
_server.setQueryHook(queryHandler);