Class ydn.db.Storage

The instance of Storage class connects to a suitable browser database and provides transactional database query on optionally defined database schema.

NOTE: This documentation list all available methods to the storage instance, but only subset of them are available depending on the distribution used. The require distribution name is given on the right side in a small yellow box.


Constructor
ydn.db.Storage(name, schema, opt_options)
Create a connection to suitable storage mechanism and initialize the database.

A database connection is created with the given database name of the first available storage mechanisms supported by the browser respecting preferential ordering of mechanisms if given.

If database schema is given, object stores and indexes are created or updated before firing 'ready' event. During schema upgrade, data may lost if existing data are not met by database constraint in new schema. If schema is not given or autoSchema is set true, object stores or indexes are created as necessary. If schema version is given, the connected database version is same as given version. If schema version is not given and schema in the browser is different from given schema, the database is upgraded by increasing version 1. If schema version is given, but schema in the browser is different from given schema, the connection fail.

The following runnable code snippet describes a simple library usage.

db = new ydn.db.Storage('db-name');
db.put('store-name', {foo: 'bar'}, 'id1');
db.get('store-name', 'id1').always(function(record) {
  console.log(record);
});
Parameters:
{string} name
The database name.
{!ydn.db.schema.Database=} schema

Optional. Set a defining schema in JSON format. The default schema is auto scheme, in which require schema is generated on-the-fly.

Schema defines a list of store schemas.

schema = {
stores: [{
    name: 'customer',    // required. object store name or TABLE name
    keyPath: 'email',    // keyPath.
    autoIncrement: true, // if true, key will be automatically created
}, {
    name: 'product',
    keyPath: 'id.sku',
    indexes: [{
       keyPath: 'origin', // required.
       name: 'name',      // usually omitted. generally same as keyPath.
       unique: true,      // unique constrain
       multiEntry: true   //
    }]
}]
};
{!Object=} options
Additional options.
Option keys:
{boolean=} autoSchema
Optional. Set true to auto schema mode.
{number=} connectionTimeout
Optional. Database connection timeout interval in milli-second. Default to 60 seconds or 2 seconds in dev.
{Object=} EncryptionOption crypt
Optional. Encryption options having {number=} expiration, data expiration interval in milli seconds, {Array} secrets as array of Object having name and key field for encryption key.
{!Array.<string>=} mechanisms
Optional. Preferential ordering of store mechanisms. 'indexeddb' for HTML5 IndexedDB storage, 'sqlite' for SQLitePlugin storage in Cordova platform, 'websql' for legacy WebSQL Database, 'localstorage' and 'sessionstorage' for WebStorage, 'userdata' for Internet Explorer 6 User Data and 'memory' for in-memory storage.
{number=} size
Optional. Estimated database size in bytes (used only by WebSQL). IndexedDB storage requirement should be allocated by Quota Management API before using it.
{number=} Sync
Optional. Synchronization options.
{string=} policy
Optional. Base transaction thread policy . Default transaction thread policy is 'single', which satisfy read-your-own-write consistency.
{boolean=} isSerial
Optional. Default is true. Set true to use serial transaction queue, otherwise parallel transaction queue is used. Parallel transactiond queue increases performance, but does not respect ordering.
options = {
  Encryption: {
    expiration: 1000*60*60*24, // expires in one day
    secrets: [{
      name: 'key1',
      key: 'aYHF6vfuGHpfWSeRLrPQxZjS5c6HjCscqDqRtZaspJWSMGaW'
    }]
  },
  mechanisms: ['indexeddb', 'sqlite', 'websql', 'localstorage', 'sessionstorage', 'userdata', 'memory'], // default ordering
  size: 2 * 1024 * 1024, // 2 MB
};

Methods
add(store_name, value)
Add an object to the store using in-line key or auto increment key.

If the store use in-line key, the key of the record is extracted from the given record value according to store keyPath.

If autoIncrement of the store is true, a key will be generated by the underlying database as necessary.

Underlying storage mechanisms may throw ConstraintError or SQLError if object with the same key already exists in the database. This error event object is received by error callback handler in the request object. In case of WebSQL, it is SQLError object with name set to 'ConstraintError'.

ConstraintError also occurs when index unique condition is not met.

UnknownError are for reasons unrelated to the database itself and not covered by any other errors, mostly due to I/O error. Any SQLError other than code value of 6 are set its name to UnknownError.

Parameters:
{string|ydn.db.schema.Store} store_name
The store name.
{!Object} value
Non-nullable. The value to be stored in the record.
Returns:
{!ydn.db.Request} Returns a request object.
done: {!IDBKey} Primary key of the record added to.
fail: {SQLError|ConstraintError|AbortError|UnknownError} Error as returned by underlying storage mechanisms.
Throws:
{DataError} Async. DataError
The calculated key for the insertion was not a valid key. Also thrown if the calculated key for any of the indexes which belong to this object store had a calculated key which was not a valid key.
{DataCloneError} Async. DataCloneError
The data being stored could not be cloned by the internal structured cloning algorithm.
{ydn.error.NotSupportedException} ydn.error.NotSupportedException
Store schema is given, the store exists but different schema.
add(store_name, value, id)
Add an object to the store using given out-of-line primary key.
Error behavior and implementation is same as in-line-key store.
Parameters:
{string|ydn.db.schema.Store} store_name
The name of store.
{!Object} value
Non-nullable. The value to be stored in the record.
{IDbKey} id
Non-nullable. The key used to identity the record.
Returns:
{!ydn.db.Request} Returns a request object.
done: {!IDBKey} Primary key of the record added to.
fail: {SQLError|ConstraintError|AbortError|UnknownError} Error as returned by underlying storage mechanisms.
Throws: DataError, DataCloneError, ydn.errorNotSupportedException

addAll(store_name, values)
Add a list of object to an in-of-line or auto increment store.

If adding records violate database constraint, the request fail, but transaction continue and will eventually commit. The transaction can be cancelled on receiving the request result.

var req = db.addAll('store name', objs);
req.done(function(keys) {
  console.log('all ' + keys.length + ' objects added');
});
req.fail(function(keys_or_errors) {
  console.warning('some requests cause error, aborting transaction.');
  req.abort();
});
Parameters:
{string|ydn.db.schema.Store} store_name
The name of store.
{!Array} values
Non-nullable. The list of record values to be stored.
Returns:
{!ydn.db.Request} Returns a request object. If all records are successfully added, done callback is invoked, otherwise, fail callback is invoked.
done: {!Array.<!IDBKey>} Primary keys added to the store respectively.
fail: {!Array.<!IDBKey|SQLError|ConstraintError|AbortError|UnknownError>} Primary keys added to or errors of given records respectively.
Throws: DataError, DataCloneError, ydn.error.NotSupportedException
addAll(store_name, values, ids)
Add list of object to an out-of-line store.
If out-of-line store use auto increment key, given primary key may be set to null or undefined to let the key to auto generated.
Error behavior and implementation is same as in-line-key store.
Parameters:
{string|ydn.db.schema.Store} store_name
The store name.
{!Array} values
Non-nullable. List of record values to be stored.
{!Array.<IDbKey>} ids
Non-nullable. List of primary keys corresponding to the record values.
Returns:
{!ydn.db.Request} Returns a request object. If all records are successfully added, done callback is invoked, otherwise, fail callback is invoked.
done: {!Array.<!IDBKey>} Primary keys added to the store respectively.
fail: {!Array.<!IDBKey|SQLError|ConstraintError|AbortError|UnknownError>} Primary keys added to or errors of given records respectively.
Throws: DataError, DataCloneError, ydn.error.NotSupportedException

addEventListener(type, handler, capture)event
Adds an event listener to the this storage object.
The same handler can only be added once per the type. Even if you add the same handler multiple times using the same type then it will only be called once when the event is dispatched.
Parameters:
{string} type
event type.
{Function|Object} handler
The function to handle the event. The handler can also be an object that implements the handleEvent method which takes the event object as argument.
{boolean=} capture
whether the listener is fired during the capture or bubble phase of the event.

branch(tx_policy, is_serial, store_names, mode, max_tx) 
Create a new storage instance with given transaction thread policy from the connection.

When requests are placed to storage instance, these requests can be either of serial or parallel depending on transaction policy used. Primary storage instance use serial transaction policy by default. Use parallel transaction policy for performance and serial transaction policy when request needed to be executed in order.

var parallel = db.branch('repeat', false);
var req1 = db.put('store1', record1);
var req2 = db.get('store1', record1); // this request execute after req1
var req3 = parallel.put('store1', record1); // this request may execute before req1 or req2
  
Parameters:
{string} tx_policy
The transaction policy. Valid values are 'atomic', 'single', 'repeat', and 'multi'.
Transaction policy determines whether to reuse or create a new transaction when a new request come in. Single transaction policy always create a new transaction for each request. Repeat transaction policy reuse active transaction if scope are same (both store names and mode). Multi transaction policy reuse active transaction if applicable. Atomic transaction policy is single policy, but additionally the transaction layer intersect request layer and hold request callbacks until transaction is completed. 
{boolean=} Optional. is_serial
If true, transaction are created serially. By default, transaction are create as necessary resulting parallel execution. In serial transaction, only one transaction is active by reserving transaction request into last-in-fast-out queue.  
{Array.<string>=} Optional. store_names
List of store names as transaction scope. If provided, all transactions in the branch are created using given scope. 
{TransactionMode=} Optional. mode
Transaction mode, either 'readonly' or 'readwrite'. If provided, all transactions in the branch are created using given scope. 
{Array=} Optional. max_tx
Limit number of transaction created in the branch.
Returns:
{!ydn.db.Storage} return a shallow copy of this storage instance with given transaction policy thread.

clear(store_name, key_range)
Clear records in a given key range.

See also remove.

Parameters:
{string} store_name
The store name.
{!ydn.db.KeyRange|!IDBKeyRange} key_range
Non-nullable. The key range.
Returns:
{!ydn.db.Request} Returns a request object.
done: Result is not defined.
fail: Not used.
clear(store_name)
Clear all records in a store.
Parameters:
{string} store_name
store name.
Returns:
{!ydn.db.Request} Returns a request object.
done: Result is not defined.
fail: Not used.
clear(store_names)
Clear all records in stores.
Parameters:
{!Array.<string>} store_names
Non-nullable. List of store names.
Returns:
{!ydn.db.Request} Returns a request object.
done: {number}Number of stores cleared.
fail: Not used.
clear()
Clear all entries in the database.
Returns:
{!ydn.db.Request} Returns a request object.
done: {number} Number of stores cleared.
fail: Not used.

close()
Close the database connection.

count(store_name, key_range)
Get number of records in the key range.
Parameters:
{string} store_name
Store name.
{ydn.db.KeyRange} key_range
Key range object.
Returns:
{!ydn.db.Request} Returns a request object.
done: {number} Total number of records found in the given key range.
fail: Not used.
count(store_name)
Get number of items in a store.
Parameters:
{string} store_name
store name.
Returns:
{!ydn.db.Request} Returns a request object.
done: {number} Total number of records in the store.
failResult is not defined.
count(store_names)
Get number of records in a give stores.
Parameters:
{!Array.<string>} store_name
store name.
Returns:
{!ydn.db.Request} Returns a request object.
done: {!Array.number} Total number of records for each respective store.
fail: Not used.

countByIndex(store_name, index_name, key_range) 
Get number of records in the index key range.

The following example illustrate to count number of users of age between 25 and 30.

var req = db.count('user', 'age', ydn.db.KeyRange.bound(25, 30))
req.done(function(count){
  console.log(count); // number of user of age between 25 and 30 inclusive.
);
Parameters:
{string} store_name
Store name.
{string} index_name
Index name.
{ydn.db.KeyRange} key_range
Key range object.
Returns:
{!ydn.db.Request} Returns a request object.
done: {number} Total number of records in the key range of the index.
fail: Not used.

countOf(iterator) core
Get number of records in the iterator.

Count number of cursors found by iterating the iterator until it is done.

Parameters:
{ydn.db.Iterator} iterator
The iterator object.
Returns:
{!ydn.db.Request} Returns a request object.
done: {number} Total number of records found during cursor iteration.
fail: Error as received on cursor request.

executeSql(sql, params) sql
Execute a simple SQL statement.
WebSQL storage mechanism directly execute the SQL statement. In other storage mechanism, the SQL statement is parsed and converted into physical execution operations using indexes.
Scalar results are converted into native type, otherwise the result is an array. 
db.executeSql("SELECT * FROM article WHERE license = 'SA' LIMIT 5 OFFSET 50").then(function(results) {
  console.log(results);
}, function(e) {
  throw e;
});
Parameters:
{string} sql
The SQL statement.
{!Array=} params
Non-nullable. Query parameters.
Throws:
{NotFoundError}
If store is not found in the database.
Returns:
{!ydn.db.Request} resulting in request object.
done: {*|!Array} Native data type for scalar query, othereise SQLResultSetRowList is converted into an array.
fail: {SQLError|ConstraintError|AbortError|UnknownError}  Invoke fail callback if the request fail.

from(store_name, op, value, op2, value) query
Create a query.
var q = db.from('store name');
q = q.where('country', '=', 'SG').order('age');
q.list(function(list) {
  console.log(list);
});
Parameters:
{string} store_name
The store name.
{enum.<string>} op
Operator symbol. One of '<', '<=', '=', '>', '>=', '^'. The last operator is for string value having starts with.
{*} value
Left value for the operator.
{enum.<string>=} op_2
Operator symbol 2.
{*=} value_2
Left value for the operator 2.
Returns:
{!ydn.db.Query} A query object.

get(store_name, id) 
Retrieve a record value by primary key.
Parameters:
{string} store_name
The name of store to be retrieved record from.
{!IDbKey} id
Non-nullable. Key of record to be retrieved. IDbKey is either of string, number, Date or Array.<!IDBKey>
Returns:
done: {!Object|undefined} Record if found, undefined otherwise.
fail: If request fail.
get(key)
Retrieve a record value by key object.
Parameters:
{!ydn.db.Key} key
Non-nullable. Key object of the record to be retrieved.
Returns:
done: {!Object|undefined} Record if found, undefined otherwise.
fail: Not used.
get(iterator) core
Retrieve the first record value of cursor range iterator results.

The follow example illustrates getting the the first key of 'book' object store.

var iter = new ydn.db.KeyIterator('book');
db.get(iter).done(function(key) {
if (key) {
  console.log('the first book id: ' + key);
} else {
  console.log('no book');
});
Parameters:
{!ydn.db.Iterator} iterator
Non-nullable. The iterator.
Returns:
done: {!Object|undefined} The first record if found, undefined otherwise.
fail: Error as received on cursor request.

getSchema (callback) 
Get schema of this storage.
Parameters:
{function(!ydn.db.schema.Database)=} callback
Optional. Extract actual schema from the database connection. null return if the database is not connected.
Returns:
{ydn.db.schema.Database?} Return defining schema

getType() 
Get storage mechanism type.
Returns:
{string|undefined} Type of storage mechanism used in the connection. Return undefined if not connected.

keys(store_name, key_range, limit, offset, reverse)
Retrieve primary keys from a store.

The follow code snippet illustrates listing product id starts with 'category/hardware/computer/'.

var key_range = ydn.db.KeyRange.starts('category/hardware/computer/');
db.keys('product', key_range, 500).then(function(keys) {
  console.log(keys);
}, function(e) {
  throw e;
});
Parameters:
{string} store_name
Optional. The store name.
{ydn.db.KeyRange=} key_range
Key range object.
{number=} limit
Optional. Limit number of results, default to 100.
{number=} offset
Optional. Skip number of first records.
{boolean=} reverse
Optional. Sorted by descending order of keys.
Returns:
done: {!Array.<!IDBKey>} List of primary keys in the key range.
fail: Not used.

keysByIndex(store_name, index_name, key_range, limit, offset, reverse)
Retrieve primary keys from a store on an index.
Resulting primary keys are sorted by respective effective key and then by primary key.

The follow code snippet illustrates listing product id (primary keys) which is tagged with with 'flammable'.

var key_range = ydn.db.KeyRange.only('flammble');
db.keysByIndex('product', 'tag', key_range, 500).then(function(keys) {
  console.log(keys);
}, function(e) {
  throw e;
});
Parameters:
{string} store_name
The store name.
{string} index_name
Index name of key_range.
{ydn.db.KeyRange=} key_range
Optional. Key range object.
{number=} limit
Optional. Limit number of results. Default is 100.
{number=} offset
Optional. Skip number of first records.
{boolean=} reverse
Optional. Set true to reverse the ordering. Default ordering is ascending.
Returns:
done: {!Array.<!IDBKey>} List of primary keys in the index key range.
fail: Not used.

keysOf(iterator, limit) core
Retrieve effective keys of the iterator.
Resulting keys are sorted by effective keys and then by primary keys.

The follow example illustrate retrieving unique list of 'tag' index key from store 'article'.

var iter = new ydn.db.IndexIterator('article', 'tag', null, false, true);
db.keysOf(iter, 500).done(function(keys) {
  console.log(keys);
});
Parameters:
{ydn.db.Iterator} iterator
Non-nullable. The iterator.
{number=} limit
Optional. Limit maximum number of results, default to 100.
Returns:
done: {!Array.<!IDBKey>} List of effective keys yield in iterating the iterator.
fail: {Error|SQLError} Error as received on cursor request.

onReady(cb, scope) 
Add database ready event listener.

Opening database connection is an asynchronous operation. This ready event listener is invoked when database is connected and after necessary schema changes are made. This is the first asynchronous function call make by the database instance. If database opening fail, the callback is invoke with error event object. Multiple listener can be added. Heavy database write operation should invoke after this ready event handler. Alternatively 'ready' event can be listen through DOM event listener pattern.

var db = new ydn.db.Storage('db name');
db.onReady(function(e) {
  if (e) {
    if (e.target.error) {
      console.log('Error due to: ' + e.target.error.name + ' ' + e.target.error.message);
    }
    throw e;
  }
  db.put('st1', large_data);
});
Parameters:
{Function} cb
Callback to handle database connection ready event.
{Object=} scope
Optional. An optional scope to call the functions in.

open(next_callback, iterator, mode, scope) cursor
Open iterator to perform iteration process.

Scanning iterates effective key of the iterator in their specified cursor ranges and directions. Each iteration invokes given callback with transient cursor object. The callback may direct next cursor positions by returning cursor advancement object. The cursor advancement object format is the following table. All attributes are optional and may use in any combination. They are executed in the order given by the table from top to bottom.

If next_callback do not return a value, cursor will continue next. Return null to stop iterating.

Attributes of cursor advancement object 
Attribute Type Description
restart boolean? Restart the cursor if true. If null, cursor may restart for key to continue.
continue IDBKey? Move cursor to next position by given effective key. Cursor will iterate while the effective key position of the cursor is lower to the given effective key.
continuePrimary IDBKey? Move cursor to next position by given primary key. Cursor will iterate while the primary key position of the cursor is lower to the given primary key.
advance number Move cursor to a given number of steps.

Instead of giving cursor advancement object, a short form may be used such that boolean value as 'restart' attribute and non-trivial value as 'continue' attribute.

If done flag of the query is false, query will resume from the current index key exclusive.

The follow example illustrates updating a set of records.

var iter = ydn.db.ValueIterator.where('player', 'clad', '=', 'hobbit');
var req = db.open(function(icursor) {
  var player = icursor.getValue();
  player.health += 10;
  icursor.update(player).then(function(key) {
    console.log('player ' + key + ' got health boost');
  }, function(e) {
    throw e;
  });
  return {advance: 5 * Math.random()} // randomly jump
}, iter, 'readwrite');
req.then(function () {
  console.log('committed');
}, function(e) {
  throw e;
});
Parameters:
{!function(!ydn.db.ICursor): (Object|boolean|IDBKey|undefined)} next_callback
Callback function to receive stream of cursors. Optionally return next cursor advancement.
{!ydn.db.Iterator} iterator
Cursor object to define iteration parameters.
{string=} mode
Optional. Either one of readonly (default) or readwrite.
{*=} scope
Optional. An optional scope to call the callback in.
Throws:
{NotFoundError}
If a store is not found in the database.
Returns: {!ydn.db.Request} Returns a request object.
done: {*} Result not defined.
fail: {Error|SQLError} Error as received on cursor request.

put(store_name, value)
Put an object to the store using in-line key or auto increment key.

If the store use in-line key, the key of the record is extracted from the given record value according to store keyPath.

If autoIncrement of the store is true, a key will be generated by the underlying database as necessary.

ConstraintError occur when index unique condition is not met.

Parameters:
{string|ydn.db.schema.Store} store_name
The store name.
{!Object} value
Non-nullable. The value to be stored in the record.
Returns:
{!ydn.db.Request} Returns a request object.
done: {!IDBKey}Effected record primary key.
fail: {SQLError|ConstraintError|AbortError|UnknownError} Error as returned by underlying storage mechanisms.
Throws:
{DataError} Async. DataError
The calculated key for the insertion was not a valid key. Also thrown if the calculated key for any of the indexes which belong to this object store had a calculated key which was not a valid key.
{DataCloneError} Async. DataCloneError
The data being stored could not be cloned by the internal structured cloning algorithm.
{ydn.error.NotSupportedException} ydn.error.NotSupportedException
Store schema is given, the store exists but different schema.
put(store_name, value, id)
Put an object to the store using out-of-line primary key.
Parameters:
{string|ydn.db.schema.Store} store_name
The store name.
{!Object} value
Non-nullable. The value to be stored in the record.
{IDbKey} id
Non-nullable. The primary key used to identify the record.
Returns:
{!ydn.db.Request} Returns a request object.
done: {!IDBKey} Effected record primary key.
fail: {SQLError|ConstraintError|AbortError|UnknownError} Error as returned by underlying storage mechanisms.
Throws: DataError, DataCloneError, ydn.error.NotSupportedException
put(keys, values)
Put list of objects to the store using key objects.

This method can be used to put list of objects to multiple stores in a single transaction as illustrated below.

var message = {title: 'test'};
var body = {content: 'testing'};
var recp = {delivered: false};
var key1 = new ydn.db.Key('message', uid);
var key2 = new ydn.db.Key('message_body', uid);
var key3 = new ydn.db.Key('recipient', email, key1);
db.put([key1, key2, key3], [message, message_body, recp]);
Parameters:
{!Array.<ydn.db.Key>} keys
List of key objects corresponding to the record values.
{!Array} values
List of record values to be stored.
Returns:
{!ydn.db.Request} Returns a request object. If all records are successfully added, done callback is invoked, otherwise, fail callback is invoked.
done: {!IDBKey} Respective list of effected primary keys.
fail: {!IDBKey|SQLError|ConstraintError|AbortError|UnknownError} Respective list of effected primary keys or error received on the put request.
Throws: DataError, DataCloneError, ydn.error.NotSupportedException

putAll(store_name, values)
Put list of objects to the store using in-line primary key or auto increment key.
Parameters:
{string} store_name
The store name.
{!Array} values
Non-nullable. List of record values to be stored.
Returns:
{!ydn.db.Request} Returns a request object. If all records are successfully added, done callback is invoked, otherwise, fail callback is invoked.
done: {!Array.<!IDBKey>} Respective list of effected primary keys.
fail: {!Array.<!IDBKey|SQLError|ConstraintError|AbortError|UnknownError>} Respective list of effected primary keys or error received on the put request.
Throws: DataError, DataCloneError, ydn.NotSupportedException
putAll(store_name, values, ids)
Put list of objects to the store using out of line key.
Parameters:
{string} store_name
The store name.
{!Array} values
Non-nullable. List of record value to be stored.
{!Array.<!IDbKey>} ids
Non-nullable. List of primary keys corresponding to record values.
Returns:
{!ydn.db.Request} Returns a request object. If all records are successfully added, done callback is invoked, otherwise, fail callback is invoked.
done: {!Array.<!IDBKey>} Respective list of effected primary keys.
fail: {!Array.<!IDBKey|SQLError|ConstraintError|AbortError|UnknownError>} Respective list of effected primary keys or error received on the put request.
Throws: DataError, DataCloneError, ydn.error.NotSupportedException

remove(store_name, id)
Delete a record from an object store.
Parameters:
{string} store_name
The store name.
{IDBKey} id
Non-nullable. The primary key.
Returns:
{!ydn.db.Request} Returns a request object.
done: {number} Return number of records deleted.
fail: Not used.
remove(store_name, key_range)
Delete records in a given key range.

See also clear.

Parameters:
{string} store_name
The store name.
{!ydn.db.KeyRange|!IDBKeyRange} key_range
Non-nullable. The key range.
Returns:
{!ydn.db.Request} Returns a request object.
done: {number} Return number of records deleted.
fail: {Error} Resulting error object on deleting.
remove(store_name, index_name, key_range)
Delete records in a given index key range.
Parameters:
{string} store_name
The store name.
{string} index_name
The index name.
{!ydn.db.KeyRange|!IDBKeyRange} key_range
Non-nullable. The key range.
Returns:
{!ydn.db.Request} Returns a request object.
done: {number} Return number of records deleted.
fail: {Error|Array.<Error>} Resulting error object or objects on deleting.
remove(key)
Delete a record of a key object.
Parameters:
{!ydn.db.Key} key
Non-nullable. key to clear associated object.
Returns:
{!ydn.db.Request} Returns a request object.
done: {number} Return number of records deleted.
fail: {Error} Resulting error object on deleting.
remove(keys)
Delete records of given list of key objects.
Clear list of objects. Objects can be from multiple object stores. 
Parameters:
{!Array.<!ydn.db.Key>} keys
Non-nullable. keys to clear associated objects.
Returns:
{!ydn.db.Request} Returns a request object.
done: {number} Return number of keys deleted.
fail: {!Array.<Error|undefined>} If any one of deleting a key fail, fail callback is invoked, with the resulting error in respective elements. 

removeEventListener(type, handler, capture) event
Removes an event listener from the event target.
The handler must be the same object as the one added. If the handler has not been added then nothing is done.
Parameters:
{string} type
event type.
{Function|Object} handler
The function to handle the event. The handler can also be an object that implements the handleEvent method which takes the event object as argument.
{boolean=} capture
whether the listener is fired during the capture or bubble phase of the event.

scan(callback, iterators) cursor
Perform index or table scan iteration.

Index scan iteration is a fundamental database query process. This is similar to table and index scanning in relational database. Use value iterator to perform table scanning. Use key iterator to perform index scanning.

Scanning iterates effective keys of the iterators in their specified cursor ranges and directions. Each iteration invokes given callback with two arguments of resulting effective key array and its reference value array for respective iterators. The callback may direct next cursor positions by returning cursor advancement array object.  The cursor advancement object format is described above. In cursor advancement array object, each value are array with each element corresponds to iterator.

Instead of returning cursor advancement object, the scan callback may return cursor advancement array as short notation. Cursor advancement array has the same length as input iterator. Each element of non-trivial value is next position effective key. If the value is true, it is taken as 'advance' of 1 step and if false, it is taken as 'restart' to true. Trivial values are ignored.

Instead of giving callback function, a more high level key joining algorithm object may be used.

The follow example illustrate finding the first people having name is 'John' and country is 'SG'.

var iter_a = ydn.db.IndexKeyIterator.where('people', 'name', '=', 'John');
var iter_b = ydn.db.IndexKeyIterator.where('people', 'country', '=', 'SG');
var result;
db.scan(function(keys, values) {
  // keys[0] == 'John', keys[1] == 'SG'
  var cmp = ydn.db.cmp(values[0], values[1]); // compare primary keys
  if (cmp == 0) {
     result = values[0];
     return []; // done
  } else if (cmp == 1) { // values[0] is ahead of values[1]
     return {continuePrimary: [values[1], null]}; // jump iter_a to iter_b cursor position
  } else {
     return {continuePrimary: [null, values[0]]};
  }
}, [iter_a, iter_b]).done(function() {
  if (result) {
    db.get(result).done(function(people) {
      console.log(people)
    }
  } else {
    console.log('not found');
  }
});
Parameters:
{!Array.<!ydn.db.Iterator|!ydn.db.Streamer>}iterators
The array of iterator or streamers. Streamer must immediately follow its relationship iterator.
{(function(keys: Array, value: Array): (Array.<boolean|IdbKey>|Object)|ydn.db.algo.Solver)} callback
 Join function or solver callback receive cursor values and reference values and returns next iterator advancement object.
Returns:{!ydn.db.Request} Returns a request object.
done: {!Array.<!IDBKey>} Result not defined.
fail: {Error|SQLError} Error as received on cursor request.

search(catalog, query, limit, th) text
Full text search query using inverted indexes.

Documents are indexed during storing into the database using add or put methods.

Query format is free text, in which implicit and/or/near logic operator apply for each token. Use double quote for exact match, - to subtract from the result and * for prefix search.

var schema = {
  fullTextCatalogs: [{
    name: 'name',
    lang: 'en',
    sources: [
      {
        storeName: 'contact',
        keyPath: 'first'
      }
    ]
  }],
    stores: [
      {
        name: 'contact',
        autoIncrement: true
      }]
};
var db = new ydn.db.Storage('db name', schema);
db.putAll('contact', [{first: 'Peter'}, {first: 'Collin'}]);
db.search('name', 'poter').done(function(x) {
  console.log(x);
  db.get(x[0].storeName, x[0].primaryKey).done(function(top) {
    console.log(top); // {first: "Peter"}
  })
});
Parameters:
{string} catalog
Full text search catalog name, as defined in schema.
{string} query
Free text query string.
{number=} limit
Optional. Maximum number of satisfactory results.
{number=} th
Optional. Threshold score of a result to consider as a success.
Returns:
{!ydn.db.Request} Returns a request object.
done: {Array} Return list of inverted index. An inverted index has the following attributes: storeName, primaryKey, score, tokens, representing for store name of original document, primary key of original document, match quality score and array of token objects. Token object has the following attributes: keyPath, value and loc representing key path of index of the original document, original word from the original document and array list of position of word in the document.
fail: {Error} If any one of deleting a key fail, fail callback is invoked, with the resulting error in respective elements. 
setName(name) 
Set database name to start a database connection.
var db = new ydn.db.Storage(undefined, schema);
db.count('inbox').done(function(x) {
  console.log('You have ' + x + ' messages.');
});
var eventHandlerLogin = function(e) {
  // database name is known only after user login.
  db.setName(e.target.result.name + '-db');
};
Parameters:
{string} name
name of database.
Throws:
{Error}
If database is already connected.

run(transaction_callback, store_names, mode) 
Run an isolated database transaction.

This method create a new shallow copy of storage instance, which place all requests against in a single transaction. All database operations on this storage instance are performed in this single transaction until it was committed. Transaction is committed by not using actively.

When a request cause error due to database constraint fail, transaction continue. Use abort method to abort the transaction. Errors from database request and transaction can be listened by error events of the storage instance.

var req = db.run(function update_prop (run_db) {
run_db.get('player', 1).done(function(data) {
    data.health += 10;
    run_db.put('player', data).done(function(key) {
      if (data.health > 100) {
        req.abort();
      }
    });
  }
}, ['player'], 'readwrite');
req.then(function() {
  console.log('updated.');
}, function(e) {
  console.log('transaction aborted');
});
Parameters:
{!function(db)} transaction_callback
Non-nullable. Transaction in callback function. The callback is invoke is Storage instance.
{Array.<string>=} store_names
Optional. List of store name. Default to all object stores.
{string=} mode
Optional. Transaction mode: readonly (default) or readwrite.
Returns:
{!ydn.db.Request} Returns a request object.
done: {*} Invoke done callback when the transaction is successfully committed. Its result is not defined.
fail: {*} Invoke done callback when the transaction is aborted. Result is not defined.

transaction(transaction_callback, store_names, mode, completed_event_handler) 
Create a native transaction.

This method can be used for database operations not supported by this library.

db.transaction(function transaction_callback (tx) {
  if (tx.objectStore) {
    request = tx.objectStore('player').getAll()
    ...
  } else if (tx.executeSql) {
    tx.executeSql('create virtual table doc using fts3(content text, tokenize=porter');
    ...
  } else { // localStorage or memory store, no transaction yet
    ...
  }
}, ['player'], 'readwrite')
Parameters:
{!function((!IDBTransaction|!SQLTransaction|Object))} transaction_callback
Non-nullable. Transaction in callback function. The callback is invoked with either of IDBTransaction, SQLTransaction, or localStorage depending on runtime environment. 
{Array.<string>} store_names
List of store name. If empty list, all stores are open.
{string} mode
Transaction mode: readonly (default) or readwrite.
{function(string: type, *: event)} completed_event_handler
Handle event for transaction completed, error or abort event type. If provided, handler will be called once and only once immediately after the transacting become inactive.

values(store_name, ids)
Retrieve record values of given primary keys.
Parameters:
{string} store_name
The name of store to retrive object from.
{!Array.<IDBKey?>} ids
Non-nullable. List of primary keys to retrieve.
Returns:
done: {!Array.<!Object|undefined>} Respective list of record values.
fail: {Error|SQLError} Error as received on cursor request.
values(store_name, key_range, limit, offset, reverse)
Retrieve record values from a store.
Parameters:
{string} store_name
The store name.
{ydn.db.KeyRange=} key_range
Optional. Key range object.
{number=} limit
Optional. Limit maximum number of results, default to 100.
{number=} offset
Optional. Number of first results to skip.
{boolean=} reverse
Optional. Default ordering is ascending. Set true to reverse the ordering.
Returns:
done: {!Array.<!Object>} List of records in the key range.
fail: {Error|SQLError} Error as received on cursor request.
values(keys)
Retrieve list of record values as referred by the given key objects.

The follow example illustrates retrieving a record from 'player' object store and a record from 'weapon' object store.

var k1 = new ydn.db.Key('player', 'abc');
var k2 = new ydn.db.Key('weapon', 'abc');
db.values([k1, k2]).done(function(objs) {
  var player_abc = objs[0];
  var weapon_abc = objs[1];
});
Parameters:
{!Array.<!ydn.db.Key>} keys
The key object of the object to retrieve.
Returns:
done: {!Array.<!Object|undefined>} Respective list of reference values yield in iterating the iterator. If record is not found, the result is undefined.
fail: {Error|SQLError} Error as received on cursor request.

valuesByIndex(store_name, index_name key_range, limit, offset, reverse)
Retrieve record values from a store by index.
Resulting records are sorted by their effective (index) key and then by primary key (for duplicated index keys).
Parameters:
{string} store_name
The store name.
{string} index_name
Index name of key_range.
{ydn.db.KeyRange=} key_range
Optional. Key range object.
{number=} limit
Optional. Limit maximum number of results, default to 100.
{number=} offset
Optional. Number of first results to skip.
{boolean=} reverse
Optional. Default ordering is ascending. If reverse is true, ordering is descending.
Returns:
done: {!Array.<!Object>} Non-nullable. List of records in the index key range.
fail: {Error|SQLError} Error as received on cursor request.

valuesOf(iterator, limit) core
Retrieve reference values of the iterator.

Resulting values are sorted by effective keys and then by primary keys. If iterator is in resting stage, retrieving values start from previous position exclusive.

The follow example illustrate retrieving 'article', records by their index key value of 'javascript'.

var iter = ydn.db.ValueIterator.where('article', 'tag', '=', 'javascript');
db.valuesOf(iter, 10).done(function(tags) {
  console.log(tags);
});
db.valuesOf(iter, 10).done(function(tags) { // get next 10 articles
  console.log(tags);
});
Parameters:
{!ydn.db.Iterator} iterator
Non-nullable. The iterator.
{number=} limit
Optional. Limit maximum number of results, default to 100.
Returns:
done: {!Array.<!Object>} List of reference values yield in iterating the iterator.
fail: {Error|SQLError} Error as received on cursor request.

Events
created
Record created event.
This class dispatch installable event StoreEvent or RecordEvent of type created, when it a new record is stored to the target object store.

deleted
Record deleted event.
This class dispatch installable event StoreEvent or RecordEvent of type created, when it a new record is stored to the target object store.

error
Receive database error events.
Storage instance dispatch error event received from the storage mechanism.
Parameters:
{?function(!ydn.db.events.StorageErrorEvent)} An event handler.
db.addEventListener('error', function (event) {
  var e = event.getError();
  // common errors are AbortError, ConstraintError and UnknownError (possibliy for Quota exceed error).
  // log error for debugging
  console.log('connection failed with ' + e.name);
});

fail
Database connection fail event.
Storage instance fail event when it no longer be used due to fatal error. This is the last event dispatched.
db.addEventListener('fail', function (event) {
  var err = event.getError();
  if (err.name == 'versionchange') {
    alert('The application is updated, please refresh to upgrade.')
  } else {
    console.log('connection failed with ' + err.name + ' by ' + err.message);
  }
  db = null; // no operation can be placed to the database instance
});
Parameters:
{?function(!ydn.db.events.StorageErrorEvent)} An event handler.

ready
Database connection ready event.
Listen ready StorageEvent dispatched when a connection is successfully established. The storage instance must invoke this event handler not more than once before connection time out interval.
db.addEventListener('ready', function (event) {
  var is_updated = event.getVersion() != event.getOldVersion();
  if (is_updated) {
    console.log('database connected with new schema');
  } else if (isNaN(event.getOldVersion()))  {
    console.log('new database created');
  } else {
    console.log('existing database connected');
  }
  // heavy database operations should start from this.
);
Parameters:
{?function(!ydn.db.events.StorageEvent)} An event handler.

updated
Record updated event.
This class dispatch installable event StorageEvent or RecordEvent of type updated, when it a record is updated, possibly a new one, to the target object store.

put database operation dispatch updated events and currently it does not distinguish between created and updated suituation.


versionchange
Event for current version database has changed.

When an app, possibly from other tab, open with new version of the database, current event receive IDBVersionChangeEvent. The default operation of the event is closing the connection.

An app may want to store data before the connection was closed. This is the last chance to to use the connection.

db.addEventListener('versionchange', function(e) {
  db.put('temp', draft_data);
});