If you are only interested in a simple object store without any database queries or structure, Depot will likely meet your needs. You can store up to 1 MB of data in a depot by default. Mojo provides a few simple functions that wrap the HTML 5 APIs to create, read, update, or delete a database.
Mojo.Depot()
opens the depot that matches the
name argument. If there is no match, it creates a new depot with that
name. There are four methods:
The Depot is simple to use. As with Cookie, you call Depot’s constructor with a unique name to create a new store or open an existing one. Unlike Cookie, Depot calls are asynchronous, so you will do most of your handling in callback functions. Once opened, you can save and retrieve any JavaScript object. To simplify your data handling, the Depot function will flatten the object so that it can be stored using SQL.
You do need to keep this to simple objects, as Depot is not very efficient, and if you extend it to complex objects it can impact application performance and memory. JSON objects are recommended as the best-performing. Beyond that you’ll have to experiment to see how the Depot performs with your application. Deep hierarchy, multiple object layers, array and object datatypes, and large strings are all characteristics of complex objects that may push the limits of the Depot capabilities.
The Depot will be used by News to store the feedlist for offline access of the stored feeds, to retain the user’s feed choices, and to maintain the stories’ unread state. Storing this state information will let us provide a better user experience at launch time and allow us to present the stored feeds quickly, without having to wait for a full sync from the various servers.
The Depot functions will be added to the Feeds data model through two new methods:
loadFeedDb()
Loads the feed database depot or creates one using the default feed list if there isn’t an existing depot.
storeFeedDb()
Writes the contents of Feeds.list
array to the database
depot.
The database will be loaded once, when the application is first launched, so the stage assistant is modified:
StageAssistant.prototype.setup = function() { // initialize the feeds model this.feeds = new Feeds(); this.feeds.loadFeedDb();
The load method simply opens the depot or creates one if it doesn’t exist:
// loadFeedDb - loads feed db depot, or creates it with default list // if depot doesn't already exist loadFeedDb: function() { // Open the database to get the most recent feed list // DEBUG - replace is true to recreate db every time; false for release this.db = new Mojo.Depot( {name:"feedDB", version:1, estimatedSize: 100000, replace: false}, this.loadFeedDbOpenOk.bind(this), function(result) { Mojo.Log.warn("Can't open feed database: ", result); } ); },
Depot’s constructor first takes an object, which must include a
name
. This is a required property
that must be unique for this depot. The version
indicates the desired database
version, but any version can be returned. The estimatedSize
advises the system on the
potential size of the database in bytes, and the replace
property indicates that if a depot
exists with this name, it should be opened. Should the replace
property be set to true, an existing
depot will be replaced. The replace
property is optional; if missing, it defaults to false
.
The loadFeedDbOpenOk
callback
will handle both the case where the feedlist had been previously saved
and the case when a new database is created. The function literal is
used if there is a database error. The cause of such a failure could be
either that the database exists but failed to open, or that it didn’t
exist and failed to be created.
In loadFeedDbOpenOk
, attempt to
retrieve the data with a call to the get()
method. The first argument is a key
, which must match the key used when the
data was saved. The other two arguments are the success and failure
callbacks.
If the request was successful, the callback function receives a
single argument, an object with the returned data. In the following
example, the success callback is loadFeedDbGetSuccess
, which first tests
the returned object, fl
, for null. If
fl
is a valid object, it is assigned
to feedlist and the update cycle is started to refresh the feeds:
// loadFeedDbOpenOk - Callback for successful db request in setup. Get stored // db or fallback to using default list loadFeedDbOpenOk: function() { Mojo.Log.info("Database opened OK"); this.db.simpleGet("feedList", this.loadFeedDbGetSuccess.bind(this), this.loadFeedDbUseDefault.bind(this)); }, // loadFeedDbGetSuccess - successful retrieval of db. Call // loadFeedDbUseDefault if the feedlist empty or null or initiate an update // to the list by calling updateFeedList. loadFeedDbGetSuccess: function(fl) { if (fl === null) { Mojo.Log.warn("Retrieved empty or null list from DB"); this.loadFeedDbUseDefault(); } else { Mojo.Log.info("Retrieved feedlist from DB"); this.list = fl; // If update, then convert from older versions this.updateFeedList(); } },
Should get()
fail to retrieve
any data, the sample code assumes that this is because we’re creating a
new database rather than opening an existing one, so we pass loadFeedDbUseDefault
as
the second (failure case) callback. The default feedlist is assigned
and, again, the feed update cycle is started with a call to
this.updateFeedList()
:
// loadFeedDbUseDefault() - Callback for failed DB retrieval meaning no list loadFeedDbUseDefault: function() { // Couldn't get the list of feeds. Maybe its never been set up, so // initialize it here to the default list and then initiate an update // with this feed list Mojo.Log.warn("Database has no feed list. Will use default."); this.list = this.getDefaultList(); this.updateFeedList(); },
If the call to open the database fails, there is a database error and the failure callback is used. In this sample, a function literal is used to log the error. There should be some proper error handling added to notify the user and advise on recovery actions, but that’s not shown here.
The storeFeedDb()
method is
much less involved, but it is critical to keep the data updated. The
webOS application model and user experience rely on saving data as it is
entered or received, without explicit actions by the user. The News
application has several points at which the data needs to be saved, and
each time, calling this method will do it:
// storeFeedDb() - writes contents of Feeds.list array to feed database depot storeFeedDb: function() { Mojo.Log.info("FeedList save started"); this.db.add("feedList", this.list, function() {Mojo.Log.info("FeedList saved OK");}, this.storeFeedDbFailure); }, // storeFeedDbFailure(transaction, result) - handles save failure, usually an // out of memory error storeFeedDbFailure: function(result) { Mojo.Log.warn("Database save error: ", result); },
The add()
method accepts
the "feedList"
string as the depot
key and writes this.list
as the
stored object. The success callback is a function literal that logs the
transaction, but the failure callback is another method. This is where
you’d want to put recovery logic for memory full conditions, for
example.
These calls can be implemented at these points in the
FeedListAssistant
:
AddDialogAssistant
A new feed has been added, so clearly an update is required to save that new feed and its contents.
showFeatureStory()
This might seem odd, but since this is a periodic updater, a flag can be set indicating that the data has changed (for example, from a feed update, or perhaps the unread status has changed); performing the update here implements a lazy update of the depot.
cleanup()
As a precaution, save the most recent version in case something has slipped through during execution.
News never deletes its Depot object, but you can use the
discard()
method to
remove objects if needed. To be safe, you should only use this method
after a successful open or create transaction, and you may want to
include success and failure callbacks as a further precaution. The
framework will remove an application’s Depot objects when the
application is deleted from the device.
3.145.155.91