The JavaScript client is very similar to A VBA API for scriptDB, so reading that will give you a more detailed flavor of what can be done. The implementation is very different though, and there are a few complications you need to watch out for.

Asynchronicity

Everything about this API happens asynchronously. POSTS are batched up, and although most of this is hidden and shouldn’t provide too much difficulty for the javasScript developer, some care needs to be taken. jQuery promises are used throughout and can be used to test completion of requested operations.

Test data

We’ll use exactly the same data as was used in parse.com – nosql database for VBAparse.com – noSQL database for GAS and the same database and Google Apps Script handlers as used by A VBA API for scriptDB. The term ‘class’ in these examples refers to a group of objects which are stored in a scriptDB against a particular siloID, and is somewhat similar to the parse.com definition of a class.

Rendering results

For our tests, we’ll render all results in <div> elements in the testing web page using this simple function
function renderScriptDb(control,id) {
    $(id).text(JSON.stringify(control));
}

GET

Here’s how to count how many objects of class ‘VBAParseCustomers’ are in the scriptDB described by the entry ‘dbTest’, and shows the result (or the error) on a web page element
getScriptDb("VBAParseCustomers","dbTest").getCount()
    .done (function (data,cob) {
        renderScriptDb(data.count,'#countcopycustomers');
    })
    .fail(function (data,cob) {
        renderScriptDb(JSON.stringify(data),'#countcopycustomers');
    });

This one show all objects for customers in the United States

var dbCustomer = getScriptDb("VBAParseCustomers","dbTest");
    dbCustomer.getObjectsByQuery({country:"United States"})
        .done (function (data,cob) {
            renderScriptDb(data.results,'#countryquery');
        })

See how the .getCount() and .getObjectsByQuery() function are executed asynchronously, and the results are only available for rendering when the the promise they return is resolved (or rejected).

POST examples and explanation

Functions which POST data (as opposed to GETting data) are more complex. This is because POSTS are batched (when you execute a POST, the API might not actually execute that POST until there is more to do – this helps to avoid scriptDB rate limits. Note also that the Google Apps Script handler (which deals with requests for both this and A VBA API for scriptDB), also does its own batching. Finally, it can’t be guaranteed that your requested POSTS happen in the order that you execute them, since that is the nature of asynchronous requests.
DELETE, UPDATE and CREATE are all POST type operations.
Here’s an example of how you would do a POST type operation
db.createObjects([some objects...])
    .done( function (data) {...it worked..})
    .fail( function (error) {...it failed..});

At first this looks not much different the GET operation, and in fact will not be resolved until all the objects have actually been finally handled by the Script Apps handler as part of some future batch operation. However, when you are done with all POST operations , you need to execute a finalFlush(). Although flush() is executed from time to time as the queue of requests builds up, there will usually be a queue of some size to empty out. This ensures that any request which are still in the batch queue get executed. So your final operation needs to be

db.finalFlush();
.finalFlush() follows .createObjects(), and .createObjects() will not be resolved until .finalFlush() is. This guarantees that any objects you have posted have indeed been completed. You can use the promise returned by .finalFlush() to know that there is nothing more to do. Note that different POST operations are dealt with in the same batch, so there is only a need for one finalFlush() per scriptdb object.
The following example copies a couple of classes from one scriptDb to another, and excercises all the concepts mentioned above.
function testCopy() {
    // do the copies simulatneously
    var dd = dbCopy ("primer", "dbTest", "VBAParseData");
    var dc = dbCopy ("primer", "dbTest", "VBAParseCustomers");
    
    // report when done
    showCount (dd,'#countcopydata');
    showCount (dc,'#countcopycustomers');
    
    // we can return a promise for them all being done
    return $.when(dd,dc);
    
    // show counts
    function showCount (promise, elemID ) {
        promise
            .done (function(pData,cob) {
                cob.getCount()
                    .done (function (data) {
                        renderScriptDb(data.count,elemID);
                    })
                    .fail(function (error) {
                        renderScriptDb(JSON.stringify(error),elemID);
                    });
            })
            .fail(function(error) {
                 alert (JSON.stringify(error));
            });
    }

    
    function dbCopy( source, target , cls) {
        var dbSource = getScriptDb(cls,source);
        var dbTarget = getScriptDb(cls,target);
        var d= $.Deferred();
        
        //delete everything in source db of this class
        if (!(dbTarget && dbSource)) {
            d.reject ("scriptdbs not opened");
        }
        else {
            dbTarget.deleteObjects()
                .done( function() {
                    // get the whole thing
                    dbSource.getAllMatchingQueries()
                        .done (function (data){
                            // copy to target
                            dbTarget.createObjects(data);
                            
                            // clear anything in batch not yet done.
                            dbTarget.finalFlush()
                                .done(function(data,cob){
                                    d.resolve(data,cob);
                                })
                                .fail(function(error,cob){
                                    d.reject(error,cob);
                                });

                        })
                        .fail ( function (error,cob){
                            // failed to do a query
                            alert (JSON.stringify(error));
                        });
                })
                .fail( function (error,cob){
                    // didnt manage to delete it
                    alert (JSON.stringify(error));
                });

        }

        return d.promise();
    }
    
}
There’s a few things of note here
  • Both copy operations will be executed simultaneously, and we don’t care and can’t predict which one will finish first. See trace from browser below.
  • Each dbCopy will return a promise. We can use this to postpone the counting  of the results until the copy is done.
  • testCopy itself will return a promise that will only be resolved when both copies are completed. Here’s how I use the result of the testCopy to do some queries and some further processing I don’t want to execute until both copies are complete.
 testCopy()
            .done (function() {
               // do a query------
               var dbCustomer = getScriptDb("VBAParseCustomers","dbTest");
               dbCustomer.getObjectsByQuery({country:"United States"})
                    .done (function (data,cob) {
                        renderScriptDb(data.results,'#countryquery');
                    })
                    
                    
                // look up date in another table based on data in another
                var dbData = getScriptDb("VBAParseData","dbTest");
                
                // restrict to paricular customers
                dbCustomer.getObjectsByQuery({country:"United States"})
                    .done (function (data,cob) {
                        $('#matchquery').html('');
                        for ( var i = 0 ; i < data.results.length;i++) {
                            printTransaction (dbData,data.results[i]);
                        }
                        
                    })
                    
            });
                
            function printTransaction (dbData,result) {
                dbData.getObjectsByQuery({customerid:result.customerid})
                    .done (function (transaction,cob) {
                        if (transaction.results.length) {
                            $('#matchquery').append(JSON.stringify(
                                { country:result.country,
                                  name:result.name,
                                  transaction:transaction.results
                                 }) + '<br>');  
                        }
                    });
            }

For help and more information join our forum, follow the blog or follow me on Twitter