# db8 Service API

API | Description
--- | ---
batch | Execute put, get, del, find (without a watch) and merge operations in one service request. All other database operations are not allowed. Atomicity is NOT guaranteed across batched operations.
del | Deletes objects from the database. Objects can be specified using a query or array of object IDs.
delKind | Deletes a JSON kind object from the database. All objects of that kind are also deleted.
find | Finds objects matching a query.
get | Gets objects by ID. Returns array of complete objects. Fastest way to get data from database storage.
merge | Updates properties in existing objects. Similar to SQL UPDATE. Objects can be specified using a query or array of object IDs.
put | Writes JSON data objects to db8 storage.
putKind | Puts a JSON kind object into the database. A kind object must be created before objects of that kind are stored.
reserveIds | Reserves a block of object IDs.
search | Searches for objects matching a query. Supports the "?" operator, which you can use for full-text searching.
watch | Watch for updates to database that would change the results of a query.

## batch

Execute put, get, del, find (without a watch) and merge operations in one service request. All other database operations are not allowed. Atomicity is NOT guaranteed across batched operations.

### Schema

    {
        "operations" : BatchOperation array
    }

### Parameters

Argument | Required | Type | Description
--- | --- | --- | ---
operations | Yes | BatchOperation array | Array of operations to perform in the batch.

### Return

Response | Succcess: BatchResponse Failure: ErrResponse

Example

Batch with put, del, and find operations.

     var operations = [{"method" : "put",
                       "params" :{ "objects": [{ "_kind": "com.palm.sample:1", "displayName": "Chester Fields", "state" : "CA",
                                                   "name": [{"familyName":"Fields", "givenName":"Chester"}], "nickname": "Smokey",
                                                   "emails":[{"value":"cfields@gmail.com", "type":"home"},
                                                           {"value": "chester.fields@palm.com", "type":"work"}]}]
                                 },
                       },
                       {"method": "del", "params":{"ids":["116d"]}},
                       {"method": "find", "params":{"query":{"from":"com.palm.sample:1", "where":[{"prop":"state","op":"=","val":"OR"}]}}}
                     ];

      this.controller.serviceRequest("palm://com.palm.db/", {
            method: "batch",
            parameters: { "operations": operations },
            onSuccess: function(e) { Mojo.Log.info("Batch success! results=" + JSON.stringify(e));},
            onFailure: function(e) { Mojo.Log.info("Batch failure! Err = " + JSON.stringify(e));}
     });

Example Output

    Batch success!
    results={
       "returnValue":true,
       "responses":[
          {
             "returnValue":true,
             "results":[
                {
                   "id":"++HEHBh2FRWQsiSM",
                   "rev":4810
                }
             ]
          },
          {
             "returnValue":true,
             "results":[

             ]
          },
          {
             "returnValue":true,
             "results":[
                {
                   "_id":"++HEDfsxCncIyLO8",
                   "_kind":"com.palm.sample:1",
                   "_rev":4456,
                   "displayName":"Helen Wheels",
                   "emails":[
                      {
                         "_id":"1169",
                         "type":"home",
                         "value":"hwheels@gmail.com"
                      },
                      {
                         "_id":"116a",
                         "type":"work",
                         "value":"helen.wheels@palm.com"
                      }
                   ],
                   "name":[
                      {
                         "_id":"116b",
                         "familyName":"Wheels",
                         "givenName":"Helen"
                      }
                   ],
                   "nickname":"Speedy",
                   "state":"OR"
                }
             ]
          }
       ]
    }

## del

Deletes JSON data objects from the database.

Objects can be specified as a set of IDs (returns PutResponse) or as a db8 Query (returns CountResponse).

### Schema

    {
       "ids"   : string array,
       "query" : Query,
       "purge" : boolean
    }

### Parameters

Argument | Required | Type | Description
--- | --- | --- | ---
ids | No | string array | Array of JSON data object IDs to delete. This or "query" must be specified.
query | No | Query | Query specifying set of objects to delete. This or "ids" must be specified.
purge | No | boolean | Purge immediately flag. If not purged, target objects are marked as deleted and not completely removed until an administrative purge operation is run. Objects marked as deleted can still be retrieved. Default is false.

### Return

Response | Succcess: PutResponse (IDs) or CountResponse (query) Failure: ErrResponse

Examples

Example delete using ID

       var id1 = "++HE8X59Y00hoKrF";
       var ids = [id1];
       this.controller.serviceRequest("palm://com.palm.db/", {
            method: "del",
            parameters: { "ids": ids },
            onSuccess: function(e)
            {
                Mojo.Log.info("del success!");
                Mojo.Log.info("del #1, id="+ e.results[0].id+", rev="+e.results[0].rev);
            },
            onFailure: function(e) { Mojo.Log.info("del failure! Err = " + JSON.stringify(e));}
     });

Example delete using query

       var q = { "from":"com.palm.sample:1", "where":[{"prop":"state","op":"=","val":"OR"}] };
       this.controller.serviceRequest("palm://com.palm.db/", {
          method: "del",
          parameters: { "query": q },
          onSuccess: function(e) { Mojo.Log.info("del success!, count="+e.count);},
          onFailure: function(e) { Mojo.Log.info("del failure! Err = " + JSON.stringify(e));}
     });

## delKind

Deletes a kind object from the database. Deleting a kind deletes ALL data objects of that kind.

### Schema

    {
       "id" : string
    }

### Parameters

Argument | Required | Type | Description
--- | --- | --- | ---
id | Yes | string | ID of kind to delete.

### Return

Response | SuccessResponse or ErrResponse

Example

       var id = "com.palm.sample:1"; // kind + version number
         this.controller.serviceRequest("palm://com.palm.db/", {
            method: "delKind",
            parameters: { "id": id },
            onSuccess: function(e) { Mojo.Log.info("delKind success!");},
            onFailure: function(e) { Mojo.Log.info("delKind failure! Err = " + JSON.stringify(e));}
         });

## find

Returns a set of objects matching a query.

If your query is limited to a specified number of results, you can set a flag ("count") to get the number that would have been returned without a limit. You can also set a flag ("watch") to request notification if any of the returned results from the query changes in the future.

### Schema

    {
       "query" : Query,
       "count" : boolean,
       "watch" : boolean
    }

### Parameters

Argument | Required | Type | Description
--- | --- | --- | ---
query | Yes | Query | db8 query for retrieving results.
count | No | boolean | Return number of objects that would have been returned without the limit specified in the query flag. Default is false.
watch | No | boolean | Notify if change flag. Default is false.

### Return

Response | Succcess: FindResponse or NotificationResponse (watch == true) Failure: ErrResponse

Examples

Example 1: Simple find

This query returns all data objects. No notification and no count is requested.

       var fquery = {"from":"com.palm.sample:1"};

       this.controller.serviceRequest("palm://com.palm.db/", {
          method: "find",
          parameters: { "query": fquery },
          onSuccess: function(e) { Mojo.Log.info("find success!, results="+JSON.stringify(e.results));},
          onFailure: function(e) { Mojo.Log.info("find failure! Err = " + JSON.stringify(e));}
       });

Example 2: Using where, select, order by, and desc in a query

This query searches for contacts who live in California (state == 'CA'. The displayName and state fields are returned for each match. Returned objects are sorted on the displayName field in descending order. No notification is requested.

     //**
     //** Note: A dual index for the kind was created, allowing this call to work:
     //**          var indexes = [{"name":"dNameState", props:[{"name": "state"}, {"name":"displayName"}]} ];
     //**
     //**       The query below will not work if 'displayName' is declared as the first 'props' entry and 'state' the second.
     //**       Results can only be returned for contiguously ordered index entries. If you have the entries ["CA", "John Doe"], ["CA","Mabel Syrup"], etc.,
     //**       then, all of the entries with the same state are consecutive and only secondarily ordered by display name. Therefore, the index can answer the query.
     //**       If the index entries were ordered in ["displayName", "state"] order, the entries for the same state are not consecutive and
     //**       could not be used to answer the query (the query would fail with a "no index for query" message).

       var fquery = {"select": ["displayName", "state"],
                     "from":"com.mystuff.contacts:1",
                     "where":[{"prop":"state","op":"=","val":"CA"}],
                     "orderBy":"displayName",
                     "desc":true };

       this.controller.serviceRequest("palm://com.palm.db/", {
            method: "find",
            parameters: { "query": fquery },
            onSuccess: function(e)
            {
               Mojo.Log.info("find success!");
               var results = e.results;
               for (i=0; results[i] != null; i++)
                  Mojo.Log.info("find #"+i+"  state ="+ results[i].state+", displayName="+results[i].displayName);
            },
            onFailure: function(e) { Mojo.Log.info("find failure! Err = " + JSON.stringify(e));}
       });

Example 3: Query with change notification

This example shows how change notiification for a find works. The "onSuccess" code is called again if results for the initial query have changed. The "fired" flag is true if this is a notification response.

        var fquery = {"select": ["displayName", "state"],"from":"com.palm.sample:1"};

       this.controller.serviceRequest("palm://com.palm.db/", {
            method: "find",
            parameters: { "query": fquery,
                          "watch": true },
            onSuccess: function(e)
            {
              if (!e.fired)
              {
                 Mojo.Log.info("find initial response success, e= " + JSON.stringify(e));
              }
              else
              {
                 Mojo.Log.info("find results changed");
                 //
                 // Do something, i.e., reissue find
                 //
              }
            },
            onFailure: function(e) { Mojo.Log.info("find failure! Err = " + JSON.stringify(e));}
       });

## get

Gets JSON data objects by IDs. This is the fastest way to retrieve data.

### Schema

    {
       "ids" : string array
    }

### Parameters

Argument | Required | Type | Description
--- | --- | --- | ---
ids | Yes | string array | Array of JSON data object IDs.

### Return

Response | Success: GetResponse Failure: ErrResponse

Example

      var id1 = "++HE8X59Y00hoKrF";
      var id2 = "++HE8X59ZZCfac68";
      var ids = [id1, id2];
      this.controller.serviceRequest("palm://com.palm.db/", {
            method: "get",
            parameters: { "ids": ids },
            onSuccess: function(e)
            {
               Mojo.Log.info("get success!, e=" + JSON.stringify(e));
               var rs = e.results;
               for (i=0; rs[i] != null; i++)
                  Mojo.Log.info("get #"+ (i+1) +", id="+ rs[i]._id+", displayName="+rs[i].displayName+", nickname="+rs[i].nickname+", familyName="+rs[i].name[0].familyName);
            },
            onFailure: function(e) { Mojo.Log.info("get failure! Err = " + JSON.stringify(e));}
     });

## merge

Updates properties in existing objects. Objects can be specified using a query (returns CountResponse) or array of IDs (returns PutResponse).

### Schema

    {
       "objects" : any object array,
       "query"   : Query,
       "props"   : any object
    }

### Parameters

Argument | Required | Type | Description
--- | --- | --- | ---
objects | No | any object array | Array of IDs and properties to update. Either this or "query" is required.
query | No | Query | Query specifying set of objects to merge properties into. Either this or "objects" is required.
props | No | any object | Requires "query". Set of properties to merge into existing object(s) from query.

### Return

Response | Succcess: PutResponse (IDs) or CountResponse (query) Failure: ErrResponse

Examples

Example using IDs

       //** Create objects to update nickname field
       var m1 = {  "_id": "++HECGnRNNF_7TdA", "nickname": "Sugar" };
       var m2 = {  "_id": "++HECGnRLstE6iwP", "nickname": "Swifty" };

       var mobjs = [m1, m2];

       this.controller.serviceRequest("palm://com.palm.db/", {
            method: "merge",
            parameters: { "objects": mobjs },
            onSuccess: function(e)
            {
               Mojo.Log.info("merge success!");
               var results = e.results;
               for (i=0; results[i] != null; i++)
                  Mojo.Log.info("merge #"+i+"  id ="+ results[i].id+", rev="+results[i].rev);
            },
            onFailure: function(e) { Mojo.Log.info("merge failure! Err = " + JSON.stringify(e));}
       });

Example using query

       //** Assign a property to update, and create the query
       //** Note that indexes must exist for the fields you are querying on
       //**
       var mprops = { "nickname":"Spud"};
       var mquery = { "from":"com.palm.sample:1","where":[{"prop":"state","op":"%","val":"C"}] };
       this.controller.serviceRequest("palm://com.palm.db/", {
            method: "merge",
            parameters: {
                          "query": mquery,
                          "props": mprops
                         },
            onSuccess: function(e) { Mojo.Log.info("merge success!, count= " +e.count);},
            onFailure: function(e) { Mojo.Log.info("merge failure! Err = " + JSON.stringify(e));}
       });

## put

Puts JSON data objects of a particular kind into the database. Assigns "id" field if not set. Returns "id" and "rev" for each object stored.

### Schema

    {
       "objects" : any object array
    }

### Parameters

Argument | Required | Type | Description
--- | --- | --- | ---
objects | Yes | any object array | Array of JSON data objects of a particular kind to store.

### Return

Response | Succcess: PutResponse Failure: ErrResponse

Example

       //** Create new JSON data objects
       var  contact1 = {
          _kind: "com.palm.sample:1",
          displayName: "Mabel Syrup",
          state : "CA",
          name: [{"familyName":"Syrup", "givenName":"Mabel"}],
          nickname: "Sticky",
          emails:[
            {"value":"msyrup@gmail.com", "type":"home"},
            {"value": "mabel.syrup@palm.com", "type":"work"}]};

       var  contact2 = {
          _kind: "com.palm.sample:1",
          displayName: "Helen Wheels",
          state : "OR",
          name: [{"familyName":"Wheels", "givenName":"Helen"}],
          nickname: "Speedy",
          emails:[
            {"value":"hwheels@gmail.com", "type":"home"},
            {"value": "helen.wheels@palm.com", "type":"work"}]};

       //** Create object array
       var objs = [contact1, contact2];

       //** Call DB service
       this.controller.serviceRequest("palm://com.palm.db/", {
            method: "put",
            parameters: { "objects": objs },
            onSuccess: function(e)
            {
               Mojo.Log.info("put success! e=" + JSON.stringify(e));
               var results = e.results;
               for (i=0; results[i] != null; i++)
                  Mojo.Log.info("put #"+i+"  id ="+ results[i].id+", rev="+results[i].rev);
            },
            onFailure: function(e) { Mojo.Log.info("put failure! Err = " + JSON.stringify(e));}
     });

## putKind

Registers a kind JSON object with the database.

Kind objects define the owner and indexes for a JSON data object.

Your indexes can be composed of single or multiple fields. When you create your index, be aware that queries can only return results that are indexed and are contiguously ordered. See All Queries Must be on Indexed Fields for more information.

If your app or service wants to be notified only when a subset of an object's properties are updated, then you can use revision sets. See Using Revision Sets for more information.

If your app or service creates objects that other apps or services need to access, then see Allowing Other Apps or Services to Access Your db8 Data for more information.

### Syntax

    {
       "id"      : string,
       "owner"   : string,
       "schema"  : Schema,
       "sync"    : boolean,
       "extends" : string array,
       "indexes" : IndexClause array,
       "revSets" : RevSetClause array,
    }

### Parameters

Argument | Required | Type | Description
--- | --- | --- | ---
id | Yes | string | Kind identifier.
owner | Yes | string | Kind owner—service's bus address or app's app ID. Only the owner has permission to modify the kind.
schema | No | Schema | JSON schema for data objects of this kind. If set, this kind's data objects are validated before being stored.
sync | No | boolean | Backup and restore objects of this kind flag. Objects are backed up to Palm's servers on a daily basis. If the user moves to another device, saved app data can be restored. Default is `false`.
extends | No | string array | IDs of kind parents.
indexes | No | IndexClause array | Kind indexes.
revSets | No | RevSetClause array | Array of revision sets. See Using Revision Sets for more information.

### Return

Response | Succcess: SuccessResponse Failure: ErrResponse

Example

    var indexes = [{"name":"dNameState", props:[{"name": "state"}, {"name":"displayName"}]} ];
       this.controller.serviceRequest("palm://com.palm.db/", {
            method: "putKind",
            parameters: { "id":"com.palm.sample:1",
                          "owner":"com.palm.dbtest",
                          "indexes": indexes
            },
            onSuccess: function() { Mojo.Log.info("putKind success!");},
            onFailure: function(e) { Mojo.Log.info("putKind failure! Err = " + JSON.stringify(e));}
     });

## reserveIds

Reserves a block of object ids.

### Schema

    {
       "count" : int
    }

### Parameters

Argument | Required | Type | Description
--- | --- | --- | ---
count | Yes | int | Number of Ids to reserve.

### Return

Response | Success: ReserveIdsResponse Failure: ErrResponse

Example

Get block of 5 IDs:

       var count = 5;
       this.controller.serviceRequest("palm://com.palm.db/", {
          method: "reserveIds",
          parameters: { "count": count  },
          onSuccess: function(e) {
             Mojo.Log.info("reserveIds success!");
             var ids = e.ids;
             for (i=0; i < count; i++)
                Mojo.Log.info("reserveIds ID #"+(i+1)+" ="+ids[i]);
          },
          onFailure: function(e) { Mojo.Log.info("delKind failure! Err = " + JSON.stringify(e));}
       });

## search

Unlike find, this call supports the '?' operator, which can be used for full-text searching. Also, ordering by any property is supported. However, this call is significantly slower and should only be used for full-text type-down search; never for retrieving results that are going to be scrolled in a list.

### Schema

    {
       "query" : Query,
       "watch" : boolean
    }

### Parameters

Argument | Required | Type | Description
--- | --- | --- | ---
query | Yes | Query | Query for search.
watch | No | boolean | Notify if change flag. Default is false.

### Return

Response | Succcess: FindResponse or NotificationResponse (watch == true) Failure: ErrResponse

Example

       var fquery = {"from":"com.palm.searchtest:1","orderBy":"foo","where":[{"prop":"foo","op":"?","val":"fo","collate":"primary"}]};

       this.controller.serviceRequest("palm://com.palm.db/", {
            method: "search",
            parameters: { "query": fquery},
            onSuccess: function(e) { Mojo.Log.info("Search success, results= " + JSON.stringify(e));},
            onFailure: function(e) { Mojo.Log.info("Search failure! Err = " + JSON.stringify(e));}
       });

## watch

Watch for updates to database that would change the results of a query.

### Schema

    {
       "query" : Query
    }

### Parameters

Argument | Required | Type | Description
--- | --- | --- | ---
query | Yes | Query | Query whose results should be watched.

### Return

Response | Succcess: SuccessResponse or NotificationResponse Failure: ErrResponse

Example

Query on a revision set field. See Using Revision Sets for more information.

       var fquery = {"from":"com.palm.sample:1", "where":[{"prop":"stateRev","op":">","val":4881}]};

       this.controller.serviceRequest("palm://com.palm.db/", {
            method: "watch",
            parameters: { "query": fquery},
            onSuccess: function(e)
            {
               if (!e.fired)
                  Mojo.Log.info("RevSet watch initial response success, results= " + JSON.stringify(e));
               else
                  Mojo.Log.info("RevSet watch results changed");
            },
            onFailure: function(e) { Mojo.Log.info("RevSet watch failure! Err = " + JSON.stringify(e));}
       });