Commit 2ee114f1 authored by Tristan Cavelier's avatar Tristan Cavelier

localstorage updated to new jio design

parent 8bf30d16
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
*/ */
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ /*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'. * JIO Local Storage. Type = 'local'.
...@@ -52,33 +53,17 @@ ...@@ -52,33 +53,17 @@
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
return define(dependencies, module); return define(dependencies, module);
} }
module(jIO, complex_queries); if (typeof exports === 'object') {
}(['jio', 'complex_queries'], function (jIO, complex_queries) { return module(exports, require('jio'), require('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();
} }
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 * Checks if an object has no enumerable keys
...@@ -132,215 +117,203 @@ ...@@ -132,215 +117,203 @@
} }
}; };
jIO.addStorageType('local', function (spec, my) { function LocalStorage(spec) {
if (typeof spec.username !== 'string' && !spec.username) {
spec = spec || {}; throw new TypeError("LocalStorage 'username' must be a string " +
var that, priv; "which contains more than one character.");
that = my.basicStorage(spec, my); }
priv = {}; this._localpath = 'jio/localstorage/' + spec.username + '/' + (
spec.application_name === null || spec.application_name ===
// attributes undefined ? 'untitled' : spec.application_name.toString()
priv.username = spec.username || ''; );
priv.application_name = spec.application_name || 'untitled';
priv.localpath = 'jio/localstorage/' + priv.username + '/' +
priv.application_name;
switch (spec.mode) { switch (spec.mode) {
case "memory": case "memory":
priv.database = ram; this._database = ram;
priv.storage = memorystorage; this._storage = memorystorage;
priv.mode = "memory"; this._mode = "memory";
break; break;
default: default:
priv.database = localStorage; this._database = localStorage;
priv.storage = localstorage; this._storage = localstorage;
priv.mode = "localStorage"; this._mode = "localStorage";
break; break;
} }
// ===================== overrides ======================
that.specToStore = function () {
return {
"application_name": priv.application_name,
"username": priv.username,
"mode": priv.mode
};
};
that.validateState = function () {
if (typeof priv.username === "string" && priv.username !== '') {
return '';
} }
return 'Need at least one parameter: "username".';
};
// ==================== commands ====================
/** /**
* Create a document in local storage. * Create a document in local storage.
*
* @method post * @method post
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} metadata The metadata to store
* @param {Object} options The command options
*/ */
that.post = function (command) { LocalStorage.prototype.post = function (command, metadata) {
setTimeout(function () { var doc, doc_id = metadata._id;
var doc, doc_id = command.getDocId();
if (!doc_id) { if (!doc_id) {
doc_id = generateUuid(); doc_id = jIO.util.generateUuid();
} }
doc = priv.storage.getItem(priv.localpath + "/" + doc_id); doc = this._storage.getItem(this._localpath + "/" + doc_id);
if (doc === null) { if (doc === null) {
// the document does not exist // the document does not exist
doc = command.cloneDoc(); doc = jIO.util.deepClone(metadata);
doc._id = doc_id; doc._id = doc_id;
delete doc._attachments; delete doc._attachments;
priv.storage.setItem(priv.localpath + "/" + doc_id, doc); this._storage.setItem(this._localpath + "/" + doc_id, doc);
that.success({ command.success({"id": doc_id});
"ok": true,
"id": doc_id
});
} else { } else {
// the document already exists // the document already exists
that.error({ command.error(
"status": 409, "conflict",
"statusText": "Conflicts", "document exists",
"error": "conflicts", "Cannot create a new document"
"message": "Cannot create a new document", );
"reason": "Document already exists"
});
} }
});
}; };
/** /**
* Create or update a document in local storage. * Create or update a document in local storage.
*
* @method put * @method put
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} metadata The metadata to store
* @param {Object} options The command options
*/ */
that.put = function (command) { LocalStorage.prototype.put = function (command, metadata) {
setTimeout(function () {
var doc, tmp; var doc, tmp;
doc = priv.storage.getItem(priv.localpath + "/" + command.getDocId()); doc = this._storage.getItem(this._localpath + "/" + metadata._id);
if (doc === null) { if (doc === null) {
// the document does not exist // the document does not exist
doc = command.cloneDoc(); doc = jIO.util.deepClone(metadata);
delete doc._attachments; delete doc._attachments;
} else { } else {
// the document already exists // the document already exists
tmp = command.cloneDoc(); tmp = jIO.util.deepClone(metadata);
tmp._attachments = doc._attachments; tmp._attachments = doc._attachments;
doc = tmp; doc = tmp;
} }
// write // write
priv.storage.setItem(priv.localpath + "/" + command.getDocId(), doc); this._storage.setItem(this._localpath + "/" + metadata._id, doc);
that.success({ command.success();
"ok": true,
"id": command.getDocId()
});
});
}; };
/** /**
* Add an attachment to a document * Add an attachment to a document
*
* @method putAttachment * @method putAttachment
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} param The given parameters
* @param {Object} options The command options
*/ */
that.putAttachment = function (command) { LocalStorage.prototype.putAttachment = function (command, param) {
setTimeout(function () { var that = this, doc;
var doc; doc = this._storage.getItem(this._localpath + "/" + param._id);
doc = priv.storage.getItem(priv.localpath + "/" + command.getDocId());
if (doc === null) { if (doc === null) {
// the document does not exist // the document does not exist
that.error({ return command.error(
"status": 404, "not_found",
"statusText": "Not Found", "missing",
"error": "not_found", "Impossible to add attachment"
"message": "Impossible to add attachment", );
"reason": "Document not found"
});
return;
} }
// the document already exists // the document already exists
// download data
jIO.util.blobAsBinaryString(param._blob).then(function (data) {
doc._attachments = doc._attachments || {}; doc._attachments = doc._attachments || {};
doc._attachments[command.getAttachmentId()] = { doc._attachments[param._attachment] = {
"content_type": command.getAttachmentMimeType(), "content_type": param._blob.type,
"digest": "md5-" + command.md5SumAttachmentData(), "digest": jIO.util.makeBinaryStringDigest(data),
"length": command.getAttachmentLength() "length": param._blob.size
}; };
// upload data that._storage.setItem(that._localpath + "/" + param._id + "/" +
priv.storage.setItem(priv.localpath + "/" + command.getDocId() + "/" + param._attachment, data);
command.getAttachmentId(), that._storage.setItem(that._localpath + "/" + param._id, doc);
command.getAttachmentData()); command.success({"hash": doc._attachments[param._attachment].digest});
// write document }, function () {
priv.storage.setItem(priv.localpath + "/" + command.getDocId(), doc); command.error(
that.success({ "request_timeout",
"ok": true, "blob error",
"id": command.getDocId(), "Unable to download blob content"
"attachment": command.getAttachmentId() );
}); }, function () {
command.notify(50); // XXX get percentage
}); });
}; };
/** /**
* Get a document * Get a document
*
* @method get * @method get
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} param The given parameters
* @param {Object} options The command options
*/ */
that.get = function (command) { LocalStorage.prototype.get = function (command, param) {
setTimeout(function () { var doc = this._storage.getItem(
var doc = priv.storage.getItem( this._localpath + "/" + param._id
priv.localpath + "/" + command.getDocId()
); );
if (doc !== null) { if (doc !== null) {
that.success(doc); command.success({"data": doc});
} else { } else {
that.error({ command.error(
"status": 404, "not_found",
"statusText": "Not Found", "missing",
"error": "not_found", "Cannot find document"
"message": "Cannot find the document", );
"reason": "Document does not exist"
});
} }
});
}; };
/** /**
* Get a attachment * Get an attachment
*
* @method getAttachment * @method getAttachment
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} param The given parameters
* @param {Object} options The command options
*/ */
that.getAttachment = function (command) { LocalStorage.prototype.getAttachment = function (command, param) {
setTimeout(function () { var doc;
var doc = priv.storage.getItem( doc = this._storage.getItem(this._localpath + "/" + param._id);
priv.localpath + "/" + command.getDocId() + if (doc === null) {
"/" + command.getAttachmentId() return command.error(
"not_found",
"missing document",
"Cannot find document"
);
}
if (typeof doc._attachments !== 'object' ||
typeof doc._attachments[param._attachment] !== 'object') {
return command.error(
"not_found",
"missing attachment",
"Cannot find attachment"
); );
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 * Remove a document
*
* @method remove * @method remove
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} param The given parameters
* @param {Object} options The command options
*/ */
that.remove = function (command) { LocalStorage.prototype.remove = function (command, param) {
setTimeout(function () {
var doc, i, attachment_list; var doc, i, attachment_list;
doc = priv.storage.getItem(priv.localpath + "/" + command.getDocId()); doc = this._storage.getItem(this._localpath + "/" + param._id);
attachment_list = []; attachment_list = [];
if (doc !== null && typeof doc === "object") { if (doc !== null && typeof doc === "object") {
if (typeof doc._attachments === "object") { if (typeof doc._attachments === "object") {
...@@ -352,131 +325,117 @@ ...@@ -352,131 +325,117 @@
} }
} }
} else { } else {
return that.error({ return command.error(
"status": 404, "not_found",
"statusText": "Not Found", "missing",
"error": "not_found", "Document not found"
"message": "Document not found", );
"reason": "missing"
});
} }
priv.storage.removeItem(priv.localpath + "/" + command.getDocId()); this._storage.removeItem(this._localpath + "/" + param._id);
// delete all attachments // delete all attachments
for (i = 0; i < attachment_list.length; i += 1) { for (i = 0; i < attachment_list.length; i += 1) {
priv.storage.removeItem(priv.localpath + "/" + command.getDocId() + this._storage.removeItem(this._localpath + "/" + param._id +
"/" + attachment_list[i]); "/" + attachment_list[i]);
} }
that.success({ command.success();
"ok": true,
"id": command.getDocId()
});
});
}; };
/** /**
* Remove an attachment * Remove an attachment
*
* @method removeAttachment * @method removeAttachment
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} param The given parameters
* @param {Object} options The command options
*/ */
that.removeAttachment = function (command) { LocalStorage.prototype.removeAttachment = function (command, param) {
setTimeout(function () { var doc = this._storage.getItem(this._localpath + "/" + param._id);
var doc, error; if (typeof doc !== 'object') {
error = function (word) { return command.error(
that.error({ "not_found",
"status": 404, "missing document",
"statusText": "Not Found", "Document 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(), if (typeof doc._attachments !== "object" ||
doc); typeof doc._attachments[param._attachment] !== "object") {
priv.storage.removeItem(priv.localpath + "/" + command.getDocId() + return command.error(
"/" + command.getAttachmentId()); "not_found",
that.success({ "missing attachment",
"ok": true, "Attachment not found"
"id": command.getDocId(), );
"attachment": command.getAttachmentId()
});
} else {
error("Attachment");
} }
} else {
error("Document"); 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 * Get all filenames belonging to a user from the document index
*
* @method allDocs * @method allDocs
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} param The given parameters
* @param {Object} options The command options
*/ */
that.allDocs = function (command) { LocalStorage.prototype.allDocs = function (command, param, options) {
var i, row, path_re, rows, document_list, option, document_object; var i, row, path_re, rows, document_list, document_object;
rows = []; rows = [];
document_list = []; document_list = [];
path_re = new RegExp( path_re = new RegExp(
"^" + complex_queries.stringEscapeRegexpCharacters(priv.localpath) + "^" + complex_queries.stringEscapeRegexpCharacters(this._localpath) +
"/[^/]+$" "/[^/]+$"
); );
option = command.cloneOption(); if (options.query === undefined && options.sort_on === undefined &&
if (typeof complex_queries !== "object" || options.select_list === undefined &&
(option.query === undefined && option.sort_on === undefined && options.include_docs === undefined) {
option.select_list === undefined &&
option.include_docs === undefined)) {
rows = []; rows = [];
for (i in priv.database) { for (i in this._database) {
if (priv.database.hasOwnProperty(i)) { if (this._database.hasOwnProperty(i)) {
// filter non-documents // filter non-documents
if (path_re.test(i)) { if (path_re.test(i)) {
row = { value: {} }; row = { value: {} };
row.id = i.split('/').slice(-1)[0]; row.id = i.split('/').slice(-1)[0];
row.key = row.id; row.key = row.id;
if (command.getOption('include_docs')) { if (options.include_docs) {
row.doc = JSON.parse(priv.storage.getItem(i)); row.doc = JSON.parse(this._storage.getItem(i));
} }
rows.push(row); rows.push(row);
} }
} }
} }
that.success({"rows": rows, "total_rows": rows.length}); command.success({"data": {"rows": rows, "total_rows": rows.length}});
} else { } else {
// create complex query object from returned results // create complex query object from returned results
for (i in priv.database) { for (i in this._database) {
if (priv.database.hasOwnProperty(i)) { if (this._database.hasOwnProperty(i)) {
if (path_re.test(i)) { if (path_re.test(i)) {
document_list.push(priv.storage.getItem(i)); document_list.push(this._storage.getItem(i));
} }
} }
} }
option.select_list = option.select_list || []; options.select_list = options.select_list || [];
option.select_list.push("_id"); options.select_list.push("_id");
if (option.include_docs === true) { if (options.include_docs === true) {
document_object = {}; document_object = {};
document_list.forEach(function (meta) { document_list.forEach(function (meta) {
document_object[meta._id] = meta; document_object[meta._id] = meta;
}); });
} }
complex_queries.QueryFactory.create(option.query || ""). complex_queries.QueryFactory.create(options.query || "").
exec(document_list, option); exec(document_list, options);
document_list = document_list.map(function (value) { document_list = document_list.map(function (value) {
var o = { var o = {
"id": value._id, "id": value._id,
"key": value._id "key": value._id
}; };
if (option.include_docs === true) { if (options.include_docs === true) {
o.doc = document_object[value._id]; o.doc = document_object[value._id];
delete document_object[value._id]; delete document_object[value._id];
} }
...@@ -484,11 +443,53 @@ ...@@ -484,11 +443,53 @@
o.value = value; o.value = value;
return o; return o;
}); });
that.success({"total_rows": document_list.length, command.success({"data": {
"rows": document_list}); "total_rows": document_list.length,
"rows": document_list
}});
} }
}; };
return that; 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;
})); }));
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment