# Yahoo! UI Library

### Storage 2.8.1

Yahoo! UI Library > Storage > StorageEngineGears.js (source view)
Search:
Filters Show Private Show Protected Show Deprecated

    /*
     * Gears limitation:
     *  - SQLite limitations - http://www.sqlite.org/limits.html
     *  - DB Best Practices - http://code.google.com/apis/gears/gears_faq.html#bestPracticeDB
     * 	- the user must approve before gears can be used
     *  - each SQL query has a limited number of characters (9948 bytes), data will need to be spread across rows
     *  - no query should insert or update more than 9948 bytes of data in a single statement or GEARs will throw:
     *  	[Exception... "'Error: SQL statement is too long.' when calling method: [nsIDOMEventListener::handleEvent]" nsresult: "0x8057001c (NS_ERROR_XPC_JS_THREW_JS_OBJECT)" location: "<unknown>" data: no]
     *
     * Thoughts:
     *  - we may want to implement additional functions for the gears only implementation
     *  - how can we not use cookies to handle session location
     */
    (function() {
    	// internal shorthand
    var Y = YAHOO.util,
    	YL = YAHOO.lang,
    	_SQL_STMT_LIMIT = 9948,
    	_TABLE_NAME = 'YUIStorageEngine',

    	// local variables
    	_engine = null,

    	eURI = encodeURIComponent,
    	dURI = decodeURIComponent;

    	/**
    	 * The StorageEngineGears class implements the Google Gears storage engine.
    	 * @namespace YAHOO.util
    	 * @class StorageEngineGears
    	 * @constructor
    	 * @extend YAHOO.util.Storage
    	 * @param location {String} Required. The storage location.
    	 * @param conf {Object} Required. A configuration object.
    	 */
    	Y.StorageEngineGears = function(location, conf) {
    		var _this = this;
    		Y.StorageEngineGears.superclass.constructor.call(_this, location, Y.StorageEngineGears.ENGINE_NAME, conf);

    		if (! _engine) {
    			// create the database
    			_engine = google.gears.factory.create(Y.StorageEngineGears.GEARS);
    			_engine.open(window.location.host + '-' + Y.StorageEngineGears.DATABASE);
    			_engine.execute('CREATE TABLE IF NOT EXISTS ' + _TABLE_NAME + ' (key TEXT, location TEXT, value TEXT)');
    		}

    		var isSessionStorage = Y.StorageManager.LOCATION_SESSION === _this._location,
    			sessionKey = Y.Cookie.get('sessionKey' + Y.StorageEngineGears.ENGINE_NAME);

    		if (! sessionKey) {
    			_engine.execute('BEGIN');
    			_engine.execute('DELETE FROM ' + _TABLE_NAME + ' WHERE location="' + eURI(Y.StorageManager.LOCATION_SESSION) + '"');
    			_engine.execute('COMMIT');
    		}

    		var rs = _engine.execute('SELECT key FROM ' + _TABLE_NAME + ' WHERE location="' + eURI(_this._location) + '"'),
    			keyMap = {};

    		try {
    			// iterate on the rows and map the keys
    			while (rs.isValidRow()) {
    				var fld = dURI(rs.field(0));

    				if (! keyMap[fld]) {
    					keyMap[fld] = true;
    					_this._addKey(fld);
    				}

    				rs.next();
    			}
    		}
    		finally {
    			rs.close();
    		}

    		// this is session storage, ensure that the session key is set
    		if (isSessionStorage) {
    			Y.Cookie.set('sessionKey' + Y.StorageEngineGears.ENGINE_NAME, true);
    		}

    		_this.length = _this._keys.length;
    		YL.later(250, _this, function() { // temporary solution so that CE_READY can be subscribed to after this object is created
    			_this.fireEvent(_this.CE_READY);
    		});
    	};

    	YL.extend(Y.StorageEngineGears, Y.StorageEngineKeyed, {

    		/*
    		 * Implementation to clear the values from the storage engine.
    		 * @see YAHOO.util.Storage._clear
    		 */
    		_clear: function() {
    			_engine.execute('BEGIN');
    			_engine.execute('DELETE FROM ' + _TABLE_NAME + ' WHERE location="' + eURI(this._location) + '"');
    			_engine.execute('COMMIT');
    			this._keys = [];
    			this.length = 0;
    		},

    		/*
    		 * Implementation to fetch an item from the storage engine.
    		 * @see YAHOO.util.Storage._getItem
    		 */
    		_getItem: function(key) {
    			var rs = _engine.execute('SELECT value FROM ' + _TABLE_NAME + ' WHERE key="' + eURI(key) + '" AND location="' + eURI(this._location) + '"'),
    				value = '';

    			try {
    				while (rs.isValidRow()) {
    					var temp = rs.field(0);
    					value += rs.field(0);
    					rs.next();
    				}
    			}
    			finally {
    				rs.close();
    			}

    			return value ? dURI(value) : null;
    		},

    		/*
    		 * Implementation to fetch a key from the storage engine.
    		 * @see YAHOO.util.Storage.key
    		 */
    		_key: function(index) {return this._keys[index];},

    		/*
    		 * Implementation to remove an item from the storage engine.
    		 * @see YAHOO.util.Storage._removeItem
    		 */
    		_removeItem: function(key) {
    			YAHOO.log("removing " + key);
    			_engine.execute('BEGIN');
    			_engine.execute('DELETE FROM ' + _TABLE_NAME + ' WHERE key="' + eURI(key) + '" AND location="' + eURI(this._location) + '"');
    			_engine.execute('COMMIT');
    			this._removeKey(key);
    		},

    		/*
    		 * Implementation to remove an item from the storage engine.
    		 * @see YAHOO.util.Storage._setItem
    		 */
    		_setItem: function(key, data) {
    			YAHOO.log("SETTING " + data + " to " + key);

    			if (! this.hasKey(key)) {
    				this._addKey(key);
    			}

    			var _key = eURI(key),
    				_location = eURI(this._location),
    				_value = eURI(data),
    				_values = [],
    				_len = _SQL_STMT_LIMIT - (_key + _location).length;

    			// the length of the value exceeds the available space
    			if (_len < _value.length) {
    				for (var i = 0, j = _value.length; i < j; i += _len) {
    					_values.push(_value.substr(i, _len));
    				}
    			}
    			else {
    				_values.push(_value);
    			}

    			// Google recommends using INSERT instead of update, because it is faster
    			_engine.execute('BEGIN');
    			_engine.execute('DELETE FROM ' + _TABLE_NAME + ' WHERE key="' + eURI(key) + '" AND location="' + eURI(this._location) + '"');
    			for (var m = 0, n = _values.length; m < n; m += 1) {
    				_engine.execute('INSERT INTO ' + _TABLE_NAME + ' VALUES ("' + _key + '", "' + _location + '", "' + _values[m] + '")');
    			}
    			_engine.execute('COMMIT');

    			return true;
    		}
    	});

    	// releases the engine when the page unloads
    	Y.Event.on('unload', function() {
    		if (_engine) {_engine.close();}
    	});
    	Y.StorageEngineGears.ENGINE_NAME = 'gears';
    	Y.StorageEngineGears.GEARS = 'beta.database';
    	Y.StorageEngineGears.DATABASE = 'yui.database';
    	Y.StorageEngineGears.isAvailable = function() {
    		if (window.google && window.google.gears) {
    			try {
    				// this will throw an exception if the user denies gears
    				google.gears.factory.create(Y.StorageEngineGears.GEARS);
    				return true;
    			}
    			catch (e) {
    				// no need to do anything
    			}
    		}

    		return false;
    	};
        Y.StorageManager.register(Y.StorageEngineGears);
    }());

Copyright © 2010 Yahoo! Inc. All rights reserved.