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 VBA, parse.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
1 2 3 |
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
1 2 3 4 5 6 7 |
getScriptDb("VBAParseCustomers","dbTest").getCount() .done (function (data,cob) { renderScriptDb(data.count,'#countcopycustomers'); }) .fail(function (data,cob) { renderScriptDb(JSON.stringify(data),'#countcopycustomers'); }); |
1 2 3 4 5 |
var dbCustomer = getScriptDb("VBAParseCustomers","dbTest"); dbCustomer.getObjectsByQuery({country:"United States"}) .done (function (data,cob) { renderScriptDb(data.results,'#countryquery'); }) |
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
1 2 3 |
db.createObjects([some objects...]) .done( function (data) {...it worked..}) .fail( function (error) {...it failed..}); |
1 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
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