Jsormdb

From Jsorm

Jump to: navigation, search

Contents

Overview

jsormdb is a full-featured stand-alone database written entirely in JavaScript. jsormdb can be used to store data within a client-side or server-side JavaScript application. jsormdb supports full transaction semantics including commit and partial/full rollback, and queries.

jsormdb also supports loading information from and sending information to a remote data source. In this, jsormdb acts as a local representation of remote data, and can fully interact with the data. Commits are sent to the remote data source in one of multiple methods, and the returned data can be entered in the jsormdb in one of multiple methods.

jsormdb was inspired by the write-store extension to ExtJS. The author of write-store saw a general need for a proper data store and built jsormdb from scratch to meet that need.

jsormdb currently supports only one table per instance. A direct result of this limitation is that a join query is not possible. Multi-table is scheduled for a future release.

New in 1.3 jsormdb now supports multiple record types, the equivalent of multiple tables per instance. Thus, one can have a single database with multiple record types. For example, one might have people and cars:

var records = [
    {name: "John",type:"person"},
    {name: "Jill",type:"person"},
    {name: "Jim",type:"person"},
    {name: "Ford",type:"car"},
    {name: "Fiat",type:"car"},
    {name: "Ferrari",type:"car"}];

Joins between records of the same or different types are not yet supported.

When To Use It

You should use jsormdb if you want to do any of the following:

  • Use loosely- or rigidly-structured data within a client-side or server-side JavaScript application.
  • Query data within a dataset in simple or complex ways.
  • Persist modified data to a remote data store.
  • Use full transactions on a data set. You can make any changes, and then commit or reject the changes, rolling back to the last commit or reject.
  • Desire to use indexing, such that not every query results in a full-table scan.
  • Develop using a proper data-driven model from within your application. Really simple "hello, world!" applications or simple drag and drop have no need.

You should not use write-store if you:

  • Have no need of transactions; and
  • Have no data to manage or persist; and
  • Are not using structured data; and
  • Have no need to query data.

That having been said, we recommend you read this wiki and try jsormdb even if you think you have no need. You may discover better ways to work within JavaScript, and you may come up with recommendations for how we can help you.

Usage

jsormdb adds these features by creating several new classes. From a user's perspective, the only ones you need to know about are:

  • JSORM: A general container for all JSORM related features. There are a number of basic extensions to JavaScript here, some developed independently by the jsorm project, some inspired by Douglas Crockford. For the details, see the [jsorm] entry.
  • JSORM.db.db: The actual db element. Instantiated as db = JSORM.db.db(config). See below for more detailed usage.
  • Remote: If you want to load data from and send data to a remote data source, you need two additional pieces:
    • Parser: For example the included JSORM.db.parser.json. This is an object that can translate between a remote data source encoding, e.g. JSON text, and convert it into JavaScript objects suitable for jsormdb. It does not know how to send and receive data, only how to translate between jsormdb's native format, JavaScript objects, and a format suitable for transmission or storage. For more information on how a parser is designed, see JSORM.db.parser.
    • Channel: For example the included JSORM.db.channel.http. This is object that can communicate with a remote data source, and understands how to send data to and retrieve data from the remote source. It does not understand the content of the data, only how to send and receive given data. For more information on how a parser is designed, see JSORM.db.channel.

Following Douglas Crockford's principles, all of the classes are instantiated directly without using the 'new' keyword.

Record Types and Tables

New in 1.3 Version 1.3 and upwards supports multiple records types, what those coming from SQL would call multiple tables. To indicate which type (or table) a record should belong to, it must have a property 'type'. This property will automatically be indexed and searched appropriately. All records without a 'type' field will be placed in a catch-all bucket, or table.

var rec1 = {name: "John",type:"person"}; // will be of type person
var rec2 = {name: "No one"}; // will be of no particular type and in the catch-all

Instantiation

To instantiate a database, you simply need to create it:

// to get a fully functional database
// NOTE: there is no "new" call
var db = JSORM.db.db();

You can add configuration parameters to instantiation by passing a config object. If you wanted to pass some initial data, while indexing the name field:

conf =
{
  'data': [{name: "John", age: 25},{name: "Jill", age: 20},{name: "Jim", age: 35}],
  'index': 'name',
 'parser': JSORM.db.parser.json(),
 'channel': JSORM.db.channel.http({updateUrl: "/send/text.php", loadUrl: "/receive/text.xml"})
}
// NOTE: there is no "new" call
var db = JSORM.db.db(conf);

The following elements are accepted as part of the instantiation config object:

  • data: Raw data to load into the database to start. Should be an array of JavaScript objects.
  • index: Single text field or array of text fields to index. Note that the 'type' field is automatically indexed.
  • parser: An object to use as a parser for loading from and writing to a channel.
  • channel: An object to use as a channel for loading from and writing to a remote data source.
  • updateParams: An object with parameters to pass to every update call through the channel.
  • loadParams: An object with parameters to pass to every load call through the channel.
  • updateMode: Default updateMode to use when updating the database based on the response to a commit() call, unless specifically overridden as part of that commit() call. Must be one of the #static updates properties.
  • writeMode: Default writeMode to use when writing to a remote data source as part of a commit() call, unless specifically overridden as part of that commit() call. Must be one of the #static mode properties.

Loading Data

Loading data means wiping the entire database clean and loading a new set of data. If you just want to insert a few records, you use insert. Data can be loaded in one of two methods:

  • By passing raw data to the load() call
  • By configuring a channel and a parser, and then calling load without raw data. This will cause the database to query data from the channel, pass it to the parser, and load it.

Raw Data

To load raw data, you must simply pass the data in object format to the database in a load() call, exactly the same way you would insert. The only differences between an insert() and a load() with raw data are:

  • insert() is journalled and part of a transaction, while load() begins a new transaction.
  • insert() adds to the currently existing data, while load() replaces it.
// to load data directly
data = [{name: "John", age: 25},{name: "Jill", age: 20},{name: "Jim", age: 35}];
db.load({data: data});

Remote Data

To load data from a remote source, you must first configure a parser and a channel. The channel is responsible for communicating with the remote data source, including both retrieving the data from the remote source on a load(), and sending an update to the remote source on a commit(). The parser is responsible for converting between the remote data source's encoding, e.g. json or xml or text, and jsormdb's format, JavaScript objects, including any metadata about the sent data.

Neither a parser nor a channel necessarily requires any configuration parameters. However, particular implementations may require one. The JSORM.db.channel.http shipping with jsormdb requires one configuration parameter on instantiation, a config object, with one or two elements:

  • loadUrl: The URL to be used by the http channel to load data.
  • updateUrl: The URL to be used by the http channel to send data.
  • url: A single URL to be used to both send and load data, instead of separate loadUrl and updateUrl.

The load call itself can have an element in its object argument, params, indicating parameters to pass to the remote data source. The params element should itself be an object, with each element of the object a string of information to pass to the channel.

When using params, the params passed as part of arg.params are combined with config.loadParams passed at db instantiation. Params passed to the load call always override those passed at instantiation.

// set up a channel, parser and config
var config = {
  channel: JSORM.db.channel.http({updateUrl: "/send/foo.php", loadUrl: "/receive/foo.xml"}),
  parser: JSORM.db.parser.json()
}
// to load data via the channel and parser
var db = JSORM.db.db(config);
db.load();

Inserting Data

Inserting data means adding new data to the database. Because jsormdb is not a strictly column-oriented RDBMS, you can add any data you want to any table you want. There will be no field or validity checks. This is an incredible strength, but it is also a weakness if misused. Be sure you understand what this means.

// insert some records
data = [{name: "Jack", age: 30},{name: "Jeff", age: 60}];
// note: if the data were a string, rather than an actual object, it would be passed to the parser
db.insert(data);

Clearing Data

Clearing data means clearing out the entire database. The only differences between clearing data and starting anew - either a new instance or a load() - are:

  • clear() is a journalled activity. Thus, it can be committed or rolled back.
  • All configuration remains the same.
db.clear();
// note: the journal now contains a single entry that the data was cleared

Querying Data

Querying data means finding entries in the database that conform to a particular set of requirements. These may be as simple as "everyone over 30" or as complex as "everyone over 30 AND their name starts with J but not those whose name ends in L OR are over 60 AND live in Kalamazoo."

Query Process

The query process is fairly straightforward:

var query = {where: where, fields: fields};
 
// note: if the query is blank, it will return all records
var results = db.find(query);

The returned results will be a copy of the original data in the database, not the original. Thus, it is safe to manipulate it without concern for changing the original data.

Query Structure

The query itself, passed to db.find(), has two elements

  • where: determines what the exact query to match is.
  • fields: which fields to return.

To return only the name field, we would use:

var fields = {name: true};
var query = {where: where, fields: fields};
 
// note: if the query is blank, it will return all records
var results = db.find(query);

The query itself is composed of two elements:

  • Primitive: A primitive is a basic match for a field. For example, name equals John.
  • Compound: A compound is multiple primitives are compounds joined together with an AND or OR.

New in 1.3 Both primitives and compounds can have an optional 'type' field, which will restrict the search to records with a valid type field that matches the query's type field.

To create a query, you first build your primitive(s), and then, if relevant, join them together as compounds.

Primitive

Primitives are JavaScript objects with three elements:

  • field: The name of the field against which the match is to be made
  • value: The value against which the field should be compared
  • compare: The comparator, examples of which are below

New in 1.3 A fourth field, 'type', can be included, which will restrict the search to records with a valid type field that matches the query's type field. Additionally, the 'value' field is now optional, if the compare field is "isnull" or "notnull".

The following are the available comparators:

  • equals: exact match
  • in: in a list, the value must be an array
  • gt: greater than, the value must be a number
  • ge: greater than or equal to, the value must be a number
  • lt: less than, the value must be a number
  • le: less than or equal to, the value must be a number
  • starts: starts with, the value must be a string
  • ends: ends with, the value must be a string
  • contains: contains, the value must be a string
  • isnull: is null, the value is ignored and, in version 1.3 and up, can be left out
  • notnull: is not null, the value is ignored and, in version 1.3 and up, can be left out

The following are examples of query primitives:

var p;
// name equals John
p = {field: "name", compare: "equals", value: "John"};
// age greater than 25
p = {field: "age", compare: "gt", value: 25};
// name starts with "Jo"
p = {field: "name", compare: "starts", value: "Jo"};
Compound

Compounds are responsible for joining together multiple primitives, or other compounds, with a logical AND or OR. Compounds are JavaScript objects that have two elements:

  • join: how the multiple primitives or compounds are joined together in this compound, either "and" or "or"
  • terms: an array of primitives or compounds that are joined together

New in 1.3 A third field, 'type', can be included, which will restrict the search to records with a valid type field that matches the query's type field.

The following is an example of a compound:

var q;
 
// name is John and age is greater than 25
q = {join: "and", terms: [{field: "name", compare: "equals", value: "John"},{field: "age", compare: "gt", value: 25}]};
 
// name is John or age is greater than 25
q = {join: "or", terms: [{field: "name", compare: "equals", value: "John"},{field: "age", compare: "gt", value: 25}]};
 
// name is John or Jill and age is greater than 25
q = {join: "and", terms: [
    {join: "or", terms: [
         {field: "name", compare: "equals", value: "John"},
         {field: "name", compare: "equals", value: "Jill"}
    ],{field: "age", compare: "gt", value: 25}]};

Removing Data

Removing data means removing particular entries from the database. To remove an entry, you need to provide a query indicating which ones are to be removed.

var q = {where: where};
db.remove(q);
 
// remove all those over the age of 30
var q = {where: {field: "age", compare: "gt", value:30}};
db.remove(q);

Transactions

A transaction is started whenever one of the following occurs:

  • A new database object is created
  • A load is called
  • A commit is called
  • A reject is called

The activities insert(), remove() and update() all log to the current transaction. Specifically, the activity is noted, and can be rolled back with a reject(). Thus, if you insert a record, update a record, then insert another record, three activities have taken place within this one transaction. Each call within a transaction is its own entry. Thus, if you insert one record at a time or one hundred, it is a single journalled event.

To complete a transaction, you must either commit or reject.

Reject

If you reject the transaction, all changes since the transaction was initiated are rolled back, leaving the data within the exact same state as before the reject. Additionally, you may reject part of a transaction, by telling the database the number of activities within the transaction to reject. Obviously, if the number to reject is greater than the number within the transaction, the entire transaction is rejected.

// new transaction started
db.load(data);
 
// make three changes
db.insert(newdata);
db.insert(moredata);
db.remove({where: query});
 
// reject all of the changes
db.reject();
 
// make three new changes
db.insert(newdata);
db.insert(moredata);
db.remove({where: query});
 
// reject only the remove
db.reject(1);

Committing the Transaction

Of course, if all of the steps of the transaction complete to your satisfaction, you may want to commit the transaction. Once you commit, you can never roll back. Additionally, if the database is configured to send changed data to a remote data source, data will be sent at the commit.

// new transaction started
db.load(data);
 
// make three changes
db.insert(newdata);
db.insert(moredata);
db.remove({where: query});
 
// commit
db.commit();

When transactions are committed, one of several events occurs:

  • If the database is not configured to write its changes to the server, changes are immediately committed, a "commit" event is triggered, and a new transaction is begun.
  • If the database is configured to write its changes to the server, the changes are first sent to the server.
    • If the server successfully accepts the changes, the commit is complete, a commit event is triggered, and a new transaction is begun.
    • If the server can not be reached due to network or other errors, the commit is not complete, a writeexception event is triggered, a new transaction is not begun, and all changes remain in the journal.
    • If the server can be reached, normally defined as an HTTP response of 200, but the server program rejects the changes, the commit is not complete, a new transaction is not begun, and all changes remain in the journal.

The events launched by the database, which is given event capabilities using a variant on Douglas Crockford's eventuate(), are as follows.

  • If the database is not configured to write changes to the server, a commit event is triggered immediately after committing.
  • If the database is configured to write changes to the server, the following events are triggered:
    • At the beginning of a commitChanges(), the beforewrite event is triggered. Like all before type events, the write will occur unless a registered handler returns false.
    • After the write, one of the following two events is triggered.
      • In case of successful connection, normally defined as an HTTP status code of 200 from the server, a write event is triggered. If not registered event handlers exist, or no handler returns false, the commit is completed locally, a commit event is triggered, and a new transaction is begun.
      • In case of a failure to reach the server/page, a writeexception event is triggered, the commit is not completed locally, and no new transaction is begun.

This structure enables an application to check the response to write from the server, and determine if it was successful or not, and thus enable the local commit to proceed or prevent it.

The following code demonstrates a commit.

db.load();
 
// make some changes
db.remove({where: query});
db.update({data: data, where: query});
 
// commit the changes
db.commit();


Writing Data

Overview

When a commit takes place, the data is permanently changed on the database. The database also write data back to a remote data source, if two conditions are met:

  • The database was configured to connect to a remote data source
  • The database was given a write mode indicating that it should send to the remote data source

The database can write back to the data source one of:

  • The complete updated state of the database. This is known as "replace" mode.
  • The changes that occurred in the database, i.e. the details of the transaction journal. This is known as "update" mode.
  • The condensed changes that occurred in the database. This mode is similar to the update mode, except that multiple changes to a single record are condensed into a single state. This is known as the "condensed" mode.
  • Nothing. This is the default.

Setup

In order to use the write functionality in jsormdb, you must configure the database with the writeMode to be one of:

  • nothing: do not write
  • replace: send the entire data set
  • update: send the journal log
  • condensed: send the condensed journal log

Each of these is a property of JSORM.db.db.modes.

The default mode is nothing, and thus writing is not performed.

The following is a sample configuration:

// at initialization
var config = {writeMode: JSORM.db.db.modes.replace};
var db = JSORM.db.db(config);

Alternatively, you can set the write mode at the commit call as part of it parameters:

var config = {mode: JSORM.db.db.modes.update};
db.commit(config);

The per-transaction configuration, i.e. the one passed in the commit, always overrides the database-wide configuration.

Writing Data

Data writing from the database to its data source happens when a transaction is committed. For an overview of transactions, commit and reject, see #Transactions. In the case of a reject, no changes are written to the data source. Writes occur only in the case of a commit.

When you call commit() and writeMode or options.mode has been defined as other than JSORM.db.db.modes.nothing, the database does the following:

  1. send out a 'beforewrite' event
  2. use configured parser's write() method to convert from JavaScript objects to raw data (e.g. JSON)
  3. use channel's update() method to send the data back to the server
  4. Complete the commit:
    • If successful in sending the write from a network-layer perspective, send out a 'write' event. There are two possible outcomes to the write event.
      • If there are no registered handlers, or no handler returns false, commit the changes in the store, purge the journal, and trigger a commit event.
      • If there are registered handlers and at least one handler returns false, consider the write to have failed from an application perspective, do not commit the changes or start a new transaction, and send out a commitexception event.
    • If not successful in sending the write from a network-layer perspective, do not commit the changes locally, do not purge the journal, send out a writeexception event.
db.on('write',function() {alert('Successful write!');}
db.on('writeexception',function() {alert('Error in write!');}
 
db.commit();

The options parameter to commit supports three handlers:

  • success: will be called for success of submission and processing of this transaction
  • failure: will be called if any of the write handlers returns false, i.e. application processing has failed, or a network send failed
  • callback: will be called in all circumstances

While success and failure are mutually exclusive, callback will always be called.

To use these, set options.success or options.failure when calling commit().

commit() supports adding your own parameters to the update call. This can be done in one of two ways:

  • options.params: add a params object as a member of the options passed to commit(), and the key-value pairs listed therein will be passed via the update.
  • updateParams: add an updateParams element to the configuration object passed at db instantiation time.

Several important rules are observed when mixing and matching parameters from the three sources, i.e. db.updateParams, options.params and the base ones already part of the update call:

  1. For each call, first the store-wide store.updateParams are taken, and then the per-call options.params are added. The per-call options will override the store-wide options.
  2. The result of the first rule will be applied to the params to be sent via the update(). However, privileged system parameters will not be overridden. Privileged ones are:
    • data - the data to be sent
    • mode - the update mode

Write Modes

Data Sent

There are four methods for sending data: nothing, update, replace and condensed. The default mode is nothing. Constants defined in JSORM.db.db.modes represent the four modes.

  • Nothing: In nothing mode, no data is sent.
  • Update: In update mode, all the journal entries since the last commit, reject or load, i.e. the entire transaction, is sent back to the server. The server is expected to receive these updates and apply them as it sees fit. Represented by JSORM.db.db.modes.update.
  • Replace: In replace mode, the entire dataset - including unchanged data - is sent back to the server. Represented by JSORM.db.db.modes.replace.
  • Condensed: Condensed mode works exactly like update mode, with one significant change. All the changes related to a particular record are condensed into a single change. Represented by JSORM.db.db.modes.condensed.

Update mode works well when the data source can apply changes, for example an SQL-based system; replace mode works when the data source cannot, for example while updating a flat file.

The mode is set in one of several ways:

  • Database: When creating the database, you can specify a config parameter writeMode. This parameter can be set to one of the JSORM.db.db.modes constants.
var config = {writeMode: JSORM.db.db.modes.replace};
var db = JSORM.db.db(config);
  • Store: After the database is created, you can set the public property writeMode to one of the JSORM.db.db.modes constants.
db.writeMode = JSORM.db.db.modes.update; // or replace or condensed or nothing
  • Transaction: You can override the setting for a particular transaction by passing a mode config parameter to the commit() call.
var myMode = JSORM.db.db.modes.update; // or replace or condensed or nothing
db.commitChanges({mode: myMode});
  • Default: If not other settings are provided, the default mode will be used, which is JSORM.db.db.modes.nothing

The differences between the three modes are highlighted below. In the example, the original data is as follows:

{
	meta: {
			root: 'person',
			id: 'id'
	},
	person: 
 [
   {id: 1, firstName: 'John', lastName: 'Smith', address: [{number: '123', street: 'Main St'},{number: '456', street: 'Elm St'}]},
   {id: 2, firstName: 'Jill', lastName: 'Stein', address: [{number: '789', street: 'Park St'},{number: '012', street: 'Birch St'}]}
 ]
}

The following changes are then made:

db.update({data: {lastName: "Smithers"},where:{field: "id", compare: "equals", value: 1}});
db.update({data: {lastName: "Steiner"},where:{field: "id", compare: "equals", value: 2}});
db.update({data: {firstName: "Jane"},where:{field: "id", compare: "equals", value: 1}});

Note that we make changes to record 0, then to record 1, then back to record 0.

The resultant data transmitted to the server in each of the modes is:

// update mode
{"person":
[
{"type":0,
"data":
 [{"name":"lastName","old":"Smith","new":"Smithers"}],"id":1},
  {"type":0,"data":{"lastName":"Steiner","id":2}},
  {"type":0,"data":{"firstName":"Jane","id":1}}
 ]
}
 
// a more detailed update example involving updates and inserts
{"root":[{"type":0,"data":{"age":30,"uid":10}},{"type":0,"data":{"age":30,"uid":10}},{"type":1,"data"
	:{"name":"Karl","age":25,"uid":20}},{"type":1,"data":{"name":"Kelly","age":18,"uid":21}},{"type":1,"data"
	:{"name":"Kris","age":60,"uid":22}},{"type":1,"data":{"name":"Knute","age":45,"uid":23}},{"type":1,"data"
	:{"name":"Kandy","age":12,"uid":24}}],"meta":{"root":"root","id":"uid"}}
 
// replace mode
{"person":
 [
  {"firstName":"Jane","lastName":"Smithers",
   "address":[{"number":"123","street":"Main St"},{"number":"456","street":"Elm St"}],
   "id":1},
  {"firstName":"Jill","lastName":"Steiner",
    "address":[{"number":"789","street":"Park St"},{"number":"012","street":"Birch St"}],"id":2}
 ]
}
 
// condensed mode
{"person":
 [
 {"type":0,  "data":{"lastName":"Smithers","firstName":"Jane","id":1}},
 {"type":0,  "data":{"lastName":"Steiner"},"id":2}}
 ]
}
 
// a more detailed condensed example involving updates, inserts, and removals
{"root":[{"type":0,"data":{"age":30,"uid":10,"name":"Josh"}},{"type":0,"data":{"age":30,"uid":12
	}},{"type":0,"data":{"age":30,"uid":13}},{"type":1,"data":{"name":"Karl","age":27,"uid":20}},{"type"
	:1,"data":{}},{"type":1,"data":{"name":"Kris","age":60,"uid":22}},{"type":1,"data":{"name":"Knute","age"
	:45,"uid":23}},{"type":1,"data":{"name":"Kandy","age":12,"uid":24}},{"type":2,"data":[21]}],"meta":{"root"
	:"root","id":"uid"}}

Note that the id field is always sent in any mode.

The "type" in each entry in update or condensed mode is one of the following:

  • 0 = change
  • 1 = add
  • 2 = remove

The information sent to the server as part of a commit() is provided in the "data" parameter of a POST. One additional parameter is sent, a "mode" parameter, which is one of the following:

  • 1 = replace
  • 2 = update
  • 3 = condensed
MetaData

Sometimes a remote data source sends metadata, in the "meta" field, along with the data. If the metadata which configured this database was read from the server, rather than from the reader creation config object, the metadata will be sent back to the server.

{
 "meta":{"root":"person","id":"id"},
 "person":
 [{"type":"u","data":[{"name":"lastName","old":"Smith","new":"Smithers"}],"id":1},
 {"type":"u","data":[{"name":"lastName","old":"Stein","new":"Steiner"}],"id":2},
 {"type":"u","data":[{"name":"firstName","old":"John","new":"Jane"}],"id":1}]
}
ID

The ID of the record comes from one of several sources.

  • If the ID field is provided at construction time, then that field is treated as a source for IDs, and is used to uniquely identify records between the remote data source and the local database.
  • If the metadata provided provides an ID field, then that field is treated as a source for IDs, and is used to uniquely identify records between the remote data source and the local database. Note that the metadata provided by a load always overrides the configured metadata.
  • If no id property is provided in the metadata, then the ID field is presumed to be "id". If not such field is available, then update and condensed mode may not work, and the behaviour is unpredictable.

Success or Failure

When sending data back to the source in a commit with write, the result is always given by a callback to an event handler. The signature is always as follows:

function(database,options,response);

Parameters are as follows:

  • database is the one that actually called the callback
  • options are the ones passed in to the commit() call by the calling application
  • response is the response from the remote data source

There are three possible outcomes to a commit with write:

  • The send (e.g. POST) fails. This can be due to application problems server-side, network problems, or a host of other issues. In HTTP parlance, this is anything other than a 200 response. In this case, a writeexception event is triggered by the database. The response parameter includes response.status to check, like loadexception from the http channel.
  • The send (e.g. POST) succeeds, and the processing succeeds. In this case, a write event is triggered by the database. The response parameter includes response to check, like load from the http channel. jsormdb understands that the processing has succeeded because no registered handler exists, or no handler returns false. The local commit completes, a new transaction is begun, and a commit event is triggered.
  • The send (e.g. POST) succeeds, but the processing fails. For example, the POST goes, yet the processing on the server works and decides that it does not accept the changes. This is a network-layer success but an application-layer failure. In this case, a write is triggered by the database. The response parameter includes response to check, like load from the http channel. jsormdb understands that the processing has failed because a registered handler returns false.

Static

JSORM.db.db provides several static properties that are members of JSORM.db.db. These are used as part of the journal and updates.

modes

JSORM.db.db.modes provide the various methods for updating the remote data store through a channel. They determine in what data is passed to the parser, to be encoded and then transmitted back to the remote data source via the channel.

  • nothing: Do nothing, do not send. This is equivalent to having no channel.
  • replace: Replace the entire data set with the current contents of the database. This is particularly useful when the remote data source is simply a flat file.
  • update: Send the journal of all changes. This is particularly useful when the remote data source is its own database.
  • condensed: Send the journal of all changes, but condense the entries such that no more than one record is sent per internal entry in the database.

The difference between update mode and condensed mode is best illustrated by the following example. Suppose that the following changes are made:

  1. Insert a record, for simplicity we will identify it as record 10.
  2. Update 10 to change the "name" field from "Jack" to "Jill".
  3. Update a different record, record 20, to change the "name" field from "Jim" to "James".
  4. Remove record 20.

Under update mode, four journal entries will be sent to the remote data source, one for each change. Under condensed mode, only two entries will be sent:

  • Insert record 10 with the initial data that of post-update, i.e. "name" field as "Jill"
  • Remove record 20

updates

JSORM.db.db.updates provide the various methods for handling the data sent back from the remote data source, if any, from a channel after an update() is complete. They determine how to update the database after an update as part of a commit().

  • nothing: Do nothing. We never update our local database from the remote data source except via a load().
  • update: Update our data with data from the remote data source.
  • replace: Completely replace our local data with new data from the data source.

types

JSORM.db.db.types provide the various types of entries in the journal. These are useful not only for the local journal entry, but also for update and condensed modes when sending to a remote data source.

  • change: Change to one or more data fields in one or more records.
  • add: Add one or more new records.
  • remove: Remove one or more records.
  • clear: Clear the database entirely.
  • load: Load entirely new data into the database.

joins

JSORM.db.db.joins provide the types of joins that can be used in a composite query. These are, of course, basic logic constructs.

  • and: Join together the elements with a logical AND.
  • or: Join together the elements with a logical OR.

Server Side

In order to support writing from a database, certain behaviours must follow from the server side. This section delineates those behaviours.

Success or Failure

jsormdb, relying on Ajax, can inherently determine if the send succeeds or fails. It cannot determine if the application processing was successful. As such, the client-side application is expected to register a handler for the write event. When the send has succeeded, a write event will be triggered. The application can indicate that processing has failed by returning false in any registered handler, or it can indicate that processing has succeeded by returning true.

The content of the response will be passed as a parameter to the event handlers.

Processing Data

The format of the data sent to the server is configured by the parser. The only write-capable reader shipping at this time with jsormdb is JSORM.db.parser.json. Put in other terms, the data will be transmitted in JSON format. An XML parser is being developed at this time.

Personal tools