From 2ee114f169cb7632ce4cd3b70401b67f504699a8 Mon Sep 17 00:00:00 2001 From: Tristan Cavelier <tristan.cavelier@tiolive.com> Date: Wed, 28 Aug 2013 18:28:30 +0200 Subject: [PATCH] localstorage updated to new jio design --- src/jio.storage/localstorage.js | 711 ++++++++++++++++---------------- 1 file changed, 356 insertions(+), 355 deletions(-) diff --git a/src/jio.storage/localstorage.js b/src/jio.storage/localstorage.js index 700aad5..24c59bc 100644 --- a/src/jio.storage/localstorage.js +++ b/src/jio.storage/localstorage.js @@ -5,7 +5,8 @@ */ /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ -/*global jIO, localStorage, setTimeout, complex_queries, define */ +/*global jIO, localStorage, setTimeout, complex_queries, window, define, + exports, require */ /** * JIO Local Storage. Type = 'local'. @@ -52,33 +53,17 @@ if (typeof define === 'function' && define.amd) { return define(dependencies, module); } - module(jIO, complex_queries); -}(['jio', 'complex_queries'], function (jIO, complex_queries) { - "use strict"; - - /** - * Returns 4 hexadecimal random characters. - * - * @return {String} The characters - */ - function S4() { - return ('0000' + Math.floor( - Math.random() * 0x10000 /* 65536 */ - ).toString(16)).slice(-4); - } - - /** - * An Universal Unique ID generator - * - * @return {String} The new UUID. - */ - function generateUuid() { - return S4() + S4() + "-" + - S4() + "-" + - S4() + "-" + - S4() + "-" + - S4() + S4() + S4(); + if (typeof exports === 'object') { + return module(exports, require('jio'), require('complex_queries')); } + window.local_storage = {}; + module(window.local_storage, jIO, complex_queries); +}([ + 'exports', + 'jio', + 'complex_queries' +], function (exports, jIO, complex_queries) { + "use strict"; /** * Checks if an object has no enumerable keys @@ -132,363 +117,379 @@ } }; - jIO.addStorageType('local', function (spec, my) { - - spec = spec || {}; - var that, priv; - that = my.basicStorage(spec, my); - priv = {}; - - // attributes - priv.username = spec.username || ''; - priv.application_name = spec.application_name || 'untitled'; - - priv.localpath = 'jio/localstorage/' + priv.username + '/' + - priv.application_name; - + function LocalStorage(spec) { + if (typeof spec.username !== 'string' && !spec.username) { + throw new TypeError("LocalStorage 'username' must be a string " + + "which contains more than one character."); + } + this._localpath = 'jio/localstorage/' + spec.username + '/' + ( + spec.application_name === null || spec.application_name === + undefined ? 'untitled' : spec.application_name.toString() + ); switch (spec.mode) { case "memory": - priv.database = ram; - priv.storage = memorystorage; - priv.mode = "memory"; + this._database = ram; + this._storage = memorystorage; + this._mode = "memory"; break; default: - priv.database = localStorage; - priv.storage = localstorage; - priv.mode = "localStorage"; + this._database = localStorage; + this._storage = localstorage; + this._mode = "localStorage"; break; } + } - // ===================== overrides ====================== - that.specToStore = function () { - return { - "application_name": priv.application_name, - "username": priv.username, - "mode": priv.mode - }; - }; + /** + * Create a document in local storage. + * + * @method post + * @param {Object} command The JIO command + * @param {Object} metadata The metadata to store + * @param {Object} options The command options + */ + LocalStorage.prototype.post = function (command, metadata) { + var doc, doc_id = metadata._id; + if (!doc_id) { + doc_id = jIO.util.generateUuid(); + } + doc = this._storage.getItem(this._localpath + "/" + doc_id); + if (doc === null) { + // the document does not exist + doc = jIO.util.deepClone(metadata); + doc._id = doc_id; + delete doc._attachments; + this._storage.setItem(this._localpath + "/" + doc_id, doc); + command.success({"id": doc_id}); + } else { + // the document already exists + command.error( + "conflict", + "document exists", + "Cannot create a new document" + ); + } + }; - that.validateState = function () { - if (typeof priv.username === "string" && priv.username !== '') { - return ''; - } - return 'Need at least one parameter: "username".'; - }; + /** + * Create or update a document in local storage. + * + * @method put + * @param {Object} command The JIO command + * @param {Object} metadata The metadata to store + * @param {Object} options The command options + */ + LocalStorage.prototype.put = function (command, metadata) { + var doc, tmp; + doc = this._storage.getItem(this._localpath + "/" + metadata._id); + if (doc === null) { + // the document does not exist + doc = jIO.util.deepClone(metadata); + delete doc._attachments; + } else { + // the document already exists + tmp = jIO.util.deepClone(metadata); + tmp._attachments = doc._attachments; + doc = tmp; + } + // write + this._storage.setItem(this._localpath + "/" + metadata._id, doc); + command.success(); + }; - // ==================== commands ==================== - /** - * Create a document in local storage. - * @method post - * @param {object} command The JIO command - */ - that.post = function (command) { - setTimeout(function () { - var doc, doc_id = command.getDocId(); - if (!doc_id) { - doc_id = generateUuid(); - } - doc = priv.storage.getItem(priv.localpath + "/" + doc_id); - if (doc === null) { - // the document does not exist - doc = command.cloneDoc(); - doc._id = doc_id; - delete doc._attachments; - priv.storage.setItem(priv.localpath + "/" + doc_id, doc); - that.success({ - "ok": true, - "id": doc_id - }); - } else { - // the document already exists - that.error({ - "status": 409, - "statusText": "Conflicts", - "error": "conflicts", - "message": "Cannot create a new document", - "reason": "Document already exists" - }); - } - }); - }; + /** + * Add an attachment to a document + * + * @method putAttachment + * @param {Object} command The JIO command + * @param {Object} param The given parameters + * @param {Object} options The command options + */ + LocalStorage.prototype.putAttachment = function (command, param) { + var that = this, doc; + doc = this._storage.getItem(this._localpath + "/" + param._id); + if (doc === null) { + // the document does not exist + return command.error( + "not_found", + "missing", + "Impossible to add attachment" + ); + } - /** - * Create or update a document in local storage. - * @method put - * @param {object} command The JIO command - */ - that.put = function (command) { - setTimeout(function () { - var doc, tmp; - doc = priv.storage.getItem(priv.localpath + "/" + command.getDocId()); - if (doc === null) { - // the document does not exist - doc = command.cloneDoc(); - delete doc._attachments; - } else { - // the document already exists - tmp = command.cloneDoc(); - tmp._attachments = doc._attachments; - doc = tmp; - } - // write - priv.storage.setItem(priv.localpath + "/" + command.getDocId(), doc); - that.success({ - "ok": true, - "id": command.getDocId() - }); - }); - }; + // the document already exists + // download data + jIO.util.blobAsBinaryString(param._blob).then(function (data) { + doc._attachments = doc._attachments || {}; + doc._attachments[param._attachment] = { + "content_type": param._blob.type, + "digest": jIO.util.makeBinaryStringDigest(data), + "length": param._blob.size + }; - /** - * Add an attachment to a document - * @method putAttachment - * @param {object} command The JIO command - */ - that.putAttachment = function (command) { - setTimeout(function () { - var doc; - doc = priv.storage.getItem(priv.localpath + "/" + command.getDocId()); - if (doc === null) { - // the document does not exist - that.error({ - "status": 404, - "statusText": "Not Found", - "error": "not_found", - "message": "Impossible to add attachment", - "reason": "Document not found" - }); - return; - } + that._storage.setItem(that._localpath + "/" + param._id + "/" + + param._attachment, data); + that._storage.setItem(that._localpath + "/" + param._id, doc); + command.success({"hash": doc._attachments[param._attachment].digest}); + }, function () { + command.error( + "request_timeout", + "blob error", + "Unable to download blob content" + ); + }, function () { + command.notify(50); // XXX get percentage + }); + }; - // the document already exists - doc._attachments = doc._attachments || {}; - doc._attachments[command.getAttachmentId()] = { - "content_type": command.getAttachmentMimeType(), - "digest": "md5-" + command.md5SumAttachmentData(), - "length": command.getAttachmentLength() - }; + /** + * Get a document + * + * @method get + * @param {Object} command The JIO command + * @param {Object} param The given parameters + * @param {Object} options The command options + */ + LocalStorage.prototype.get = function (command, param) { + var doc = this._storage.getItem( + this._localpath + "/" + param._id + ); + if (doc !== null) { + command.success({"data": doc}); + } else { + command.error( + "not_found", + "missing", + "Cannot find document" + ); + } + }; - // upload data - priv.storage.setItem(priv.localpath + "/" + command.getDocId() + "/" + - command.getAttachmentId(), - command.getAttachmentData()); - // write document - priv.storage.setItem(priv.localpath + "/" + command.getDocId(), doc); - that.success({ - "ok": true, - "id": command.getDocId(), - "attachment": command.getAttachmentId() - }); - }); - }; + /** + * Get an attachment + * + * @method getAttachment + * @param {Object} command The JIO command + * @param {Object} param The given parameters + * @param {Object} options The command options + */ + LocalStorage.prototype.getAttachment = function (command, param) { + var doc; + doc = this._storage.getItem(this._localpath + "/" + param._id); + if (doc === null) { + return command.error( + "not_found", + "missing document", + "Cannot find document" + ); + } - /** - * Get a document - * @method get - * @param {object} command The JIO command - */ - that.get = function (command) { - setTimeout(function () { - var doc = priv.storage.getItem( - priv.localpath + "/" + command.getDocId() - ); - if (doc !== null) { - that.success(doc); - } else { - that.error({ - "status": 404, - "statusText": "Not Found", - "error": "not_found", - "message": "Cannot find the document", - "reason": "Document does not exist" - }); - } - }); - }; + if (typeof doc._attachments !== 'object' || + typeof doc._attachments[param._attachment] !== 'object') { + return command.error( + "not_found", + "missing attachment", + "Cannot find attachment" + ); + } - /** - * Get a attachment - * @method getAttachment - * @param {object} command The JIO command - */ - that.getAttachment = function (command) { - setTimeout(function () { - var doc = priv.storage.getItem( - priv.localpath + "/" + command.getDocId() + - "/" + command.getAttachmentId() - ); - if (doc !== null) { - that.success(doc); - } else { - that.error({ - "status": 404, - "statusText": "Not Found", - "error": "not_found", - "message": "Cannot find the attachment", - "reason": "Attachment does not exist" - }); - } - }); - }; + command.success({ + "data": this._storage.getItem( + this._localpath + "/" + param._id + + "/" + param._attachment + ) || "", + "content_type": doc._attachments[param._attachment].content_type || "" + }); + }; - /** - * Remove a document - * @method remove - * @param {object} command The JIO command - */ - that.remove = function (command) { - setTimeout(function () { - var doc, i, attachment_list; - doc = priv.storage.getItem(priv.localpath + "/" + command.getDocId()); - attachment_list = []; - if (doc !== null && typeof doc === "object") { - if (typeof doc._attachments === "object") { - // prepare list of attachments - for (i in doc._attachments) { - if (doc._attachments.hasOwnProperty(i)) { - attachment_list.push(i); - } - } + /** + * Remove a document + * + * @method remove + * @param {Object} command The JIO command + * @param {Object} param The given parameters + * @param {Object} options The command options + */ + LocalStorage.prototype.remove = function (command, param) { + var doc, i, attachment_list; + doc = this._storage.getItem(this._localpath + "/" + param._id); + attachment_list = []; + if (doc !== null && typeof doc === "object") { + if (typeof doc._attachments === "object") { + // prepare list of attachments + for (i in doc._attachments) { + if (doc._attachments.hasOwnProperty(i)) { + attachment_list.push(i); } - } else { - return that.error({ - "status": 404, - "statusText": "Not Found", - "error": "not_found", - "message": "Document not found", - "reason": "missing" - }); } - priv.storage.removeItem(priv.localpath + "/" + command.getDocId()); - // delete all attachments - for (i = 0; i < attachment_list.length; i += 1) { - priv.storage.removeItem(priv.localpath + "/" + command.getDocId() + - "/" + attachment_list[i]); - } - that.success({ - "ok": true, - "id": command.getDocId() - }); - }); - }; + } + } else { + return command.error( + "not_found", + "missing", + "Document not found" + ); + } + this._storage.removeItem(this._localpath + "/" + param._id); + // delete all attachments + for (i = 0; i < attachment_list.length; i += 1) { + this._storage.removeItem(this._localpath + "/" + param._id + + "/" + attachment_list[i]); + } + command.success(); + }; - /** - * Remove an attachment - * @method removeAttachment - * @param {object} command The JIO command - */ - that.removeAttachment = function (command) { - setTimeout(function () { - var doc, error; - error = function (word) { - that.error({ - "status": 404, - "statusText": "Not Found", - "error": "not_found", - "message": word + " not found", - "reason": "missing" - }); - }; - doc = priv.storage.getItem(priv.localpath + "/" + command.getDocId()); - // remove attachment from document - if (doc !== null && typeof doc === "object" && - typeof doc._attachments === "object") { - if (typeof doc._attachments[command.getAttachmentId()] === - "object") { - delete doc._attachments[command.getAttachmentId()]; - if (objectIsEmpty(doc._attachments)) { - delete doc._attachments; - } - priv.storage.setItem(priv.localpath + "/" + command.getDocId(), - doc); - priv.storage.removeItem(priv.localpath + "/" + command.getDocId() + - "/" + command.getAttachmentId()); - that.success({ - "ok": true, - "id": command.getDocId(), - "attachment": command.getAttachmentId() - }); - } else { - error("Attachment"); - } - } else { - error("Document"); - } - }); - }; + /** + * Remove an attachment + * + * @method removeAttachment + * @param {Object} command The JIO command + * @param {Object} param The given parameters + * @param {Object} options The command options + */ + LocalStorage.prototype.removeAttachment = function (command, param) { + var doc = this._storage.getItem(this._localpath + "/" + param._id); + if (typeof doc !== 'object') { + return command.error( + "not_found", + "missing document", + "Document not found" + ); + } + if (typeof doc._attachments !== "object" || + typeof doc._attachments[param._attachment] !== "object") { + return command.error( + "not_found", + "missing attachment", + "Attachment not found" + ); + } - /** - * Get all filenames belonging to a user from the document index - * @method allDocs - * @param {object} command The JIO command - */ - that.allDocs = function (command) { - var i, row, path_re, rows, document_list, option, document_object; + delete doc._attachments[param._attachment]; + if (objectIsEmpty(doc._attachments)) { + delete doc._attachments; + } + this._storage.setItem(this._localpath + "/" + param._id, doc); + this._storage.removeItem(this._localpath + "/" + param._id + + "/" + param._attachment); + command.success(); + }; + + /** + * Get all filenames belonging to a user from the document index + * + * @method allDocs + * @param {Object} command The JIO command + * @param {Object} param The given parameters + * @param {Object} options The command options + */ + LocalStorage.prototype.allDocs = function (command, param, options) { + var i, row, path_re, rows, document_list, document_object; + rows = []; + document_list = []; + path_re = new RegExp( + "^" + complex_queries.stringEscapeRegexpCharacters(this._localpath) + + "/[^/]+$" + ); + if (options.query === undefined && options.sort_on === undefined && + options.select_list === undefined && + options.include_docs === undefined) { rows = []; - document_list = []; - path_re = new RegExp( - "^" + complex_queries.stringEscapeRegexpCharacters(priv.localpath) + - "/[^/]+$" - ); - option = command.cloneOption(); - if (typeof complex_queries !== "object" || - (option.query === undefined && option.sort_on === undefined && - option.select_list === undefined && - option.include_docs === undefined)) { - rows = []; - for (i in priv.database) { - if (priv.database.hasOwnProperty(i)) { - // filter non-documents - if (path_re.test(i)) { - row = { value: {} }; - row.id = i.split('/').slice(-1)[0]; - row.key = row.id; - if (command.getOption('include_docs')) { - row.doc = JSON.parse(priv.storage.getItem(i)); - } - rows.push(row); + for (i in this._database) { + if (this._database.hasOwnProperty(i)) { + // filter non-documents + if (path_re.test(i)) { + row = { value: {} }; + row.id = i.split('/').slice(-1)[0]; + row.key = row.id; + if (options.include_docs) { + row.doc = JSON.parse(this._storage.getItem(i)); } + rows.push(row); } } - that.success({"rows": rows, "total_rows": rows.length}); - } else { - // create complex query object from returned results - for (i in priv.database) { - if (priv.database.hasOwnProperty(i)) { - if (path_re.test(i)) { - document_list.push(priv.storage.getItem(i)); - } + } + command.success({"data": {"rows": rows, "total_rows": rows.length}}); + } else { + // create complex query object from returned results + for (i in this._database) { + if (this._database.hasOwnProperty(i)) { + if (path_re.test(i)) { + document_list.push(this._storage.getItem(i)); } } - option.select_list = option.select_list || []; - option.select_list.push("_id"); - if (option.include_docs === true) { - document_object = {}; - document_list.forEach(function (meta) { - document_object[meta._id] = meta; - }); - } - complex_queries.QueryFactory.create(option.query || ""). - exec(document_list, option); - document_list = document_list.map(function (value) { - var o = { - "id": value._id, - "key": value._id - }; - if (option.include_docs === true) { - o.doc = document_object[value._id]; - delete document_object[value._id]; - } - delete value._id; - o.value = value; - return o; + } + options.select_list = options.select_list || []; + options.select_list.push("_id"); + if (options.include_docs === true) { + document_object = {}; + document_list.forEach(function (meta) { + document_object[meta._id] = meta; }); - that.success({"total_rows": document_list.length, - "rows": document_list}); } + complex_queries.QueryFactory.create(options.query || ""). + exec(document_list, options); + document_list = document_list.map(function (value) { + var o = { + "id": value._id, + "key": value._id + }; + if (options.include_docs === true) { + o.doc = document_object[value._id]; + delete document_object[value._id]; + } + delete value._id; + o.value = value; + return o; + }); + command.success({"data": { + "total_rows": document_list.length, + "rows": document_list + }}); + } + }; + + jIO.addStorage('local', LocalStorage); + + ////////////////////////////////////////////////////////////////////// + // Tools + + /** + * Tool to help users to create local storage description for JIO + * + * @param {String} username The username + * @param {String} [application_name] The application_name + * @return {Object} The storage description + */ + function createDescription(username, application_name) { + var description = { + "type": "local", + "username": username.toString() }; + if (application_name !== undefined) { + description.application_name = application_name.toString(); + } + return description; + } + exports.createDescription = createDescription; + + function clear() { + var k; + for (k in localStorage) { + if (localStorage.hasOwnProperty(k)) { + if (/^jio\/localstorage\//.test(k)) { + localStorage.removeItem(k); + } + } + } + } + exports.clear = clear; + exports.clearLocalStorage = clear; + + function clearMemoryStorage() { + jIO.util.dictClear(ram); + } + exports.clearMemoryStorage = clearMemoryStorage; - return that; - }); })); -- 2.30.9