Commit bb18e075 authored by Romain Courteaud's avatar Romain Courteaud

Activate IndexedDB storage.

Simplify storage and tests code.

Change the database structure so that the "attachment" store contains one entry per attachment.
parent 19cff054
...@@ -179,6 +179,7 @@ module.exports = function (grunt) { ...@@ -179,6 +179,7 @@ module.exports = function (grunt) {
'src/jio.storage/querystorage.js', 'src/jio.storage/querystorage.js',
'src/jio.storage/drivetojiomapping.js', 'src/jio.storage/drivetojiomapping.js',
'src/jio.storage/documentstorage.js', 'src/jio.storage/documentstorage.js',
'src/jio.storage/indexeddbstorage.js'
], ],
dest: 'dist/<%= pkg.name %>-<%= pkg.version %>.js' dest: 'dist/<%= pkg.name %>-<%= pkg.version %>.js'
// dest: 'jio.js' // dest: 'jio.js'
......
...@@ -13,8 +13,7 @@ ...@@ -13,8 +13,7 @@
* *
* { * {
* "type": "indexeddb", * "type": "indexeddb",
* "database": <string>, * "database": <string>
* "unite": <integer> //byte
* } * }
* *
* The database name will be prefixed by "jio:", so if the database property is * The database name will be prefixed by "jio:", so if the database property is
...@@ -28,748 +27,389 @@ ...@@ -28,748 +27,389 @@
* - https://developer.mozilla.org/en-US/docs/IndexedDB/Using_IndexedDB * - https://developer.mozilla.org/en-US/docs/IndexedDB/Using_IndexedDB
*/ */
/*jslint indent: 2, maxlen: 120, nomen: true */ /*jslint nomen: true */
/*global indexedDB, jIO, RSVP, Blob, Math*/ /*global indexedDB, jIO, RSVP, Blob, Math*/
(function (jIO) { (function (indexedDB, jIO, RSVP, Blob, Math) {
"use strict"; "use strict";
var generateUuid = jIO.util.generateUuid; // Read only as changing it can lead to data corruption
var UNITE = 2000000;
function metadataObjectToString(value) {
var i, l;
if (Array.isArray(value)) {
for (i = 0, l = value.length; i < l; i += 1) {
value[i] = metadataObjectToString(value[i]);
}
return value;
}
if (typeof value === "object" && value !== null) {
return value.content;
}
return value;
}
/**
* new IndexedDBStorage(description)
*
* Creates a storage object designed for jIO to store documents into
* indexedDB.
*
* @class IndexedDBStorage
* @constructor
*/
function IndexedDBStorage(description) { function IndexedDBStorage(description) {
if (typeof description.database !== "string" || if (typeof description.database !== "string" ||
description.database === "") { description.database === "") {
throw new TypeError("IndexedDBStorage 'database' description property " + throw new TypeError("IndexedDBStorage 'database' description property " +
"must be a non-empty string"); "must be a non-empty string");
} }
if (description.unite !== undefined) {
if (description.unite !== parseInt(description.unite, 10)) {
throw new TypeError("IndexedDBStorage 'unite' description property " +
"must be a integer");
}
} else {
description.unite = 2000000;
}
this._database_name = "jio:" + description.database; this._database_name = "jio:" + description.database;
this._unite = description.unite;
} }
IndexedDBStorage.prototype.hasCapacity = function (name) {
return (name === "list");
};
/** function buildKeyPath(key_list) {
* creat 3 objectStores return key_list.join("_");
* @param {string} the name of the database }
*/
function openIndexedDB(db_name) {
var request;
function resolver(resolve, reject) {
// Open DB //
request = indexedDB.open(db_name);
request.onerror = reject;
// Create DB if necessary // function handleUpgradeNeeded(evt) {
request.onupgradeneeded = function (evt) { var db = evt.target.result,
var db = evt.target.result, store;
store;
store = db.createObjectStore("metadata", { store = db.createObjectStore("metadata", {
"keyPath": "_id" keyPath: "_id",
//"autoIncrement": true autoIncrement: false
}); });
store.createIndex("_id", "_id"); // It is not possible to use openKeyCursor on keypath directly
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=19955
store.createIndex("_id", "_id", {unique: true});
store = db.createObjectStore("attachment", {
"keyPath": "_id" store = db.createObjectStore("attachment", {
//"autoIncrement": true keyPath: "_key_path",
}); autoIncrement: false
store.createIndex("_id", "_id"); });
store.createIndex("_id", "_id", {unique: false});
store = db.createObjectStore("blob", {
"keyPath": ["_id", "_attachment", "_part"] store = db.createObjectStore("blob", {
//"autoIncrement": true keyPath: "_key_path",
}); autoIncrement: false
store.createIndex("_id_attachment_part", });
["_id", "_attachment", "_part"]); store.createIndex("_id_attachment",
}; ["_id", "_attachment"], {unique: false});
request.onsuccess = function () { store.createIndex("_id", "_id", {unique: false});
resolve(request.result);
};
}
return new RSVP.Promise(resolver);
} }
/** function openIndexedDB(jio_storage) {
*put a data into a store object var db_name = jio_storage._database_name;
*@param {ObjectStore} store The objectstore function resolver(resolve, reject) {
*@param {Object} metadata The data to put in // Open DB //
*@return a new promise var request = indexedDB.open(db_name);
*/ request.onerror = function (error) {
function putIndexedDBArrayBuffer(store, metadata) { if (request.result) {
var request, request.result.close();
resolver; }
request = store.put(metadata); reject(error);
resolver = function (resolve, reject) {
request.onerror = function (e) {
reject(e);
};
request.onsuccess = function () {
resolve(metadata);
}; };
};
return new RSVP.Promise(resolver);
}
function putIndexedDB(store, metadata, readData) { request.onabort = function () {
var request, request.result.close();
resolver; reject("Aborting connection to: " + db_name);
try {
request = store.put(metadata);
resolver = function (resolve, reject) {
request.onerror = function (e) {
reject(e);
};
request.onsuccess = function () {
resolve(metadata);
};
}; };
return new RSVP.Promise(resolver);
} catch (e) {
return putIndexedDBArrayBuffer(store,
{"_id" : metadata._id,
"_attachment" : metadata._attachment,
"_part" : metadata._part,
"blob": readData});
}
}
function transactionEnd(transaction) { request.ontimeout = function () {
var resolver; request.result.close();
resolver = function (resolve, reject) { reject("Connection to: " + db_name + " timeout");
transaction.onabort = reject;
transaction.oncomplete = function () {
resolve("end");
}; };
};
return new RSVP.Promise(resolver); request.onblocked = function () {
} request.result.close();
/** reject("Connection to: " + db_name + " was blocked");
* get a data from a store object
* @param {ObjectStore} store The objectstore
* @param {String} id The data id
* return a new promise
*/
function getIndexedDB(store, id) {
function resolver(resolve, reject) {
var request = store.get(id);
request.onerror = reject;
request.onsuccess = function () {
resolve(request.result);
}; };
}
return new RSVP.Promise(resolver);
}
/** // Create DB if necessary //
* delete a data of a store object request.onupgradeneeded = handleUpgradeNeeded;
* @param {ObjectStore} store The objectstore
* @param {String} id The data id request.onversionchange = function () {
* @return a new promise request.result.close();
* reject(db_name + " was upgraded");
*/
function removeIndexedDB(store, id) {
function resolver(resolve, reject) {
var request = store["delete"](id);
request.onerror = function (e) {
reject(e);
}; };
request.onsuccess = function () { request.onsuccess = function () {
resolve(request.result); resolve(request.result);
}; };
} }
return new RSVP.Promise(resolver); // XXX Canceller???
return new RSVP.Queue()
.push(function () {
return new RSVP.Promise(resolver);
});
} }
/** function openTransaction(db, stores, flag, autoclosedb) {
* research an id in a store var tx = db.transaction(stores, flag);
* @param {ObjectStore} store The objectstore if (autoclosedb !== false) {
* @param {String} id The index id tx.oncomplete = function () {
* @param {var} researchID The data id db.close();
* return a new promise
*/
function researchIndexedDB(store, id, researchID) {
function resolver(resolve) {
var index = store.index(researchID);
index.get(id).onsuccess = function (evt) {
resolve({"result" : evt.target.result, "store": store});
}; };
} }
return new RSVP.Promise(resolver); tx.onabort = function () {
db.close();
};
return tx;
} }
function handleCursor(request, callback) {
function resolver(resolve, reject) {
// Open DB //
request.onerror = function (error) {
if (request.transaction) {
request.transaction.abort();
}
reject(error);
};
function promiseResearch(transaction, id, table, researchID) { request.onsuccess = function (evt) {
var store = transaction.objectStore(table); var cursor = evt.target.result;
return researchIndexedDB(store, id, researchID); if (cursor) {
} // XXX Wait for result
try {
/** callback(cursor);
* put or post a metadata into objectstore:metadata,attachment } catch (error) {
* @param {function} open The function to open a basedata reject(error);
* @param {function} research The function to reserach
* @param {function} ongoing The function to process
* @param {function} end The completed function
* @param {Object} metadata The data to put
*/
IndexedDBStorage.prototype._putOrPost =
function (open, research, ongoing, end, metadata) {
var jio_storage = this,
transaction,
global_db,
result;
return new RSVP.Queue()
.push(function () {
//open a database
return open(jio_storage._database_name);
})
.push(function (db) {
global_db = db;
transaction = db.transaction(["metadata",
"attachment"], "readwrite");
//research in metadata
return research(transaction, metadata._id, "metadata", "_id");
})
.push(function (researchResult) {
return ongoing(researchResult);
})
.push(function (ongoingResult) {
//research in attachment
result = ongoingResult;
return research(transaction, metadata._id, "attachment", "_id");
})
.push(function (researchResult) {
//create an id in attachment si necessary
if (researchResult.result === undefined) {
return putIndexedDB(researchResult.store, {"_id": metadata._id});
}
})
.push(function () {
return transactionEnd(transaction);
})
.push(function () {
return end(result);
})
.push(undefined, function (error) {
if (global_db !== undefined) {
global_db.close();
} }
throw error;
});
};
// continue to next iteration
cursor["continue"]();
} else {
resolve();
}
};
}
// XXX Canceller???
return new RSVP.Promise(resolver);
}
IndexedDBStorage.prototype.buildQuery = function () {
var result_list = [];
/** function pushMetadata(cursor) {
* Retrieve data result_list.push({
* "id": cursor.key,
*@param {Object} param The command parameters "value": {}
*/ });
IndexedDBStorage.prototype.get = function (param) { }
var jio_storage = this, return openIndexedDB(this)
transaction,
global_db,
meta;
return new RSVP.Queue()
.push(function () {
return openIndexedDB(jio_storage._database_name);
})
.push(function (db) { .push(function (db) {
global_db = db; var tx = openTransaction(db, ["metadata"], "readonly");
transaction = db.transaction(["metadata", "attachment"], "readonly"); return handleCursor(tx.objectStore("metadata").index("_id")
var store = transaction.objectStore("metadata"); .openKeyCursor(), pushMetadata);
return getIndexedDB(store, param._id);
})
.push(function (result) {
if (result) {
//get a part data from metadata
meta = result;
var store = transaction.objectStore("attachment");
return getIndexedDB(store, param._id);
}
throw new jIO.util.jIOError("Cannot find document", 404);
})
.push(function (result) {
//get the reste data from attachment
if (result._attachment) {
meta._attachments = result._attachment;
}
return transactionEnd(transaction);
}) })
.push(function () { .push(function () {
return meta; return result_list;
})
.push(undefined, function (error) {
if (global_db !== undefined) {
global_db.close();
}
throw error;
}); });
};
};
/** function handleGet(request) {
* Remove a document function resolver(resolve, reject) {
* request.onerror = reject;
* @param {Object} param The command parameters request.onsuccess = function () {
*/ if (request.result) {
IndexedDBStorage.prototype.remove = function (param) { resolve(request.result);
var jio_storage = this, }
transaction, // XXX How to get ID
global_db, reject(new jIO.util.jIOError("Cannot find document", 404));
queue = new RSVP.Queue(); };
function removeAllPart(store, attachment, part, totalLength) {
if (part * jio_storage._unite >= totalLength) {
return;
}
return removeIndexedDB(store, [param._id, attachment, part])
.then(function () {
return removeAllPart(store, attachment, part + 1, totalLength);
});
} }
function removeAll(store, array, index, allAttachment) { return new RSVP.Promise(resolver);
var totalLength = allAttachment[array[index]].length; }
return removeAllPart(store, array[index], 0, totalLength)
.then(function () { IndexedDBStorage.prototype.get = function (param) {
if (index < array.length - 1) { var attachment_dict = {};
return removeAll(store, array, index + 1, allAttachment);
} function addEntry(cursor) {
}); attachment_dict[cursor.value._attachment] = {};
} }
return queue.push(function () {
return openIndexedDB(jio_storage._database_name); return openIndexedDB(this)
}) .push(function (db) {
.push(function (db) { var transaction = openTransaction(db, ["metadata", "attachment"],
global_db = db; "readonly");
transaction = db.transaction(["metadata", return RSVP.all([
"attachment", "blob"], "readwrite"); handleGet(transaction.objectStore("metadata").get(param._id)),
return promiseResearch(transaction, param._id, "metadata", "_id"); handleCursor(transaction.objectStore("attachment").index("_id")
}) .openCursor(), addEntry)
.push(function (resultResearch) { ]);
if (resultResearch.result === undefined) {
throw new jIO.util.jIOError("IndexeddbStorage, unable to get metadata.", 500);
}
//delete metadata
return removeIndexedDB(resultResearch.store, param._id);
})
.push(function () {
var store = transaction.objectStore("attachment");
return getIndexedDB(store, param._id);
})
.push(function (result) {
if (result._attachment) {
var array, store;
array = Object.keys(result._attachment);
store = transaction.objectStore("blob");
return removeAll(store, array, 0, result._attachment);
}
})
.push(function () {
var store = transaction.objectStore("attachment");
//delete attachment
return removeIndexedDB(store, param._id);
})
.push(function () {
return transactionEnd(transaction);
})
.push(function () {
return ({"status": 204});
}) })
.push(undefined, function (error) { .push(function (result_list) {
if (global_db !== undefined) { var result = result_list[0];
global_db.close(); if (Object.getOwnPropertyNames(attachment_dict).length > 0) {
result._attachments = attachment_dict;
} }
throw error; return result;
}); });
}; };
function handleRequest(request) {
function resolver(resolve, reject) {
/** request.onerror = reject;
* Creates a new document if not already existes request.onsuccess = function () {
* @param {Object} metadata The metadata to put resolve(request.result);
*/ };
IndexedDBStorage.prototype.post = function (metadata) {
var that = this;
if (!metadata._id) {
metadata._id = generateUuid();
}
function promiseOngoingPost(researchResult) {
if (researchResult.result === undefined) {
delete metadata._attachment;
return putIndexedDB(researchResult.store, metadata);
}
throw ({"status": 409, "reason": "Document exists"});
}
function promiseEndPost(metadata) {
return metadata._id;
} }
return new RSVP.Promise(resolver);
}
return that._putOrPost(openIndexedDB, promiseResearch,
promiseOngoingPost, promiseEndPost,
metadata);
};
/**
* Creates or updates a document
* @param {Object} metadata The metadata to post
*/
IndexedDBStorage.prototype.put = function (metadata) { IndexedDBStorage.prototype.put = function (metadata) {
var that = this; return openIndexedDB(this)
function promiseOngoingPut(researchResult) { .push(function (db) {
var key; var transaction = openTransaction(db, ["metadata"], "readwrite");
for (key in metadata) { return handleRequest(transaction.objectStore("metadata").put(metadata));
if (metadata.hasOwnProperty(key)) { });
metadata[key] = metadataObjectToString(metadata[key]);
}
}
delete metadata._attachment;
return putIndexedDB(researchResult.store, metadata);
}
function promiseEndPut() {
return metadata._id;
}
return that._putOrPost(openIndexedDB, promiseResearch,
promiseOngoingPut, promiseEndPut,
metadata);
}; };
function deleteEntry(cursor) {
cursor["delete"]();
}
IndexedDBStorage.prototype.remove = function (param) {
return openIndexedDB(this)
.push(function (db) {
/** var transaction = openTransaction(db, ["metadata", "attachment",
* Add an attachment to a document "blob"], "readwrite");
* return RSVP.all([
* @param {Object} metadata The data handleRequest(transaction
* .objectStore("metadata")["delete"](param._id)),
*/ // XXX Why not possible to delete with KeyCursor?
IndexedDBStorage.prototype.putAttachment = function (metadata) { handleCursor(transaction.objectStore("attachment").index("_id")
var jio_storage = this, .openCursor(), deleteEntry),
transaction, handleCursor(transaction.objectStore("blob").index("_id")
global_db, .openCursor(), deleteEntry)
BlobInfo, ]);
readResult;
function putAllPart(store, metadata, readResult, count, part) {
var blob,
readPart,
end;
if (count >= metadata._blob.size) {
return;
}
end = count + jio_storage._unite;
blob = metadata._blob.slice(count, end);
readPart = readResult.slice(count, end);
return putIndexedDB(store, {"_id": metadata._id,
"_attachment" : metadata._attachment,
"_part" : part,
"blob": blob}, readPart)
.then(function () {
return putAllPart(store, metadata, readResult, end, part + 1);
});
}
return jIO.util.readBlobAsArrayBuffer(metadata._blob)
.then(function (event) {
readResult = event.target.result;
BlobInfo = {
"content_type": metadata._blob.type,
"length": metadata._blob.size
};
return new RSVP.Queue()
.push(function () {
return openIndexedDB(jio_storage._database_name);
})
.push(function (db) {
global_db = db;
transaction = db.transaction(["attachment",
"blob"], "readwrite");
return promiseResearch(transaction,
metadata._id, "attachment", "_id");
})
.push(function (researchResult) {
if (researchResult.result === undefined) {
throw new jIO.util.jIOError("IndexeddbStorage unable to put attachment.", 500);
}
//update attachment
researchResult.result._attachment = researchResult.
result._attachment || {};
researchResult.result._attachment[metadata._attachment] =
(BlobInfo === undefined) ? "BlobInfo" : BlobInfo;
return putIndexedDB(researchResult.store, researchResult.result);
})
.push(function () {
//put in blob
var store = transaction.objectStore("blob");
return putAllPart(store, metadata, readResult, 0, 0);
})
.push(function () {
return transactionEnd(transaction);
})
// .push(function () {
// return {"status": 204};
// })
.push(undefined, function (error) {
if (global_db !== undefined) {
global_db.close();
}
throw error;
});
}); });
}; };
/**
* Retriev a document attachment
*
* @param {Object} param The command parameter
*/
IndexedDBStorage.prototype.getAttachment = function (param) { IndexedDBStorage.prototype.getAttachment = function (param) {
var jio_storage = this, var transaction,
transaction, start,
global_db, end;
blob, return openIndexedDB(this)
totalLength;
function getDesirePart(store, start, end) {
if (start > end) {
return;
}
return getIndexedDB(store, [param._id, param._attachment, start])
.then(function (result) {
var blobPart = result.blob;
if (result.blob.byteLength !== undefined) {
blobPart = new Blob([result.blob]);
}
if (blob) {
blob = new Blob([blob, blobPart]);
} else {
blob = blobPart;
}
return getDesirePart(store, start + 1, end);
});
}
return new RSVP.Queue()
.push(function () {
return openIndexedDB(jio_storage._database_name);
})
.push(function (db) { .push(function (db) {
global_db = db; transaction = openTransaction(db, ["attachment", "blob"], "readonly");
transaction = db.transaction(["attachment", "blob"], "readwrite"); // XXX Should raise if key is not good
//check if the attachment exists return handleGet(transaction.objectStore("attachment")
return promiseResearch(transaction, .get(buildKeyPath([param._id, param._attachment])));
param._id, "attachment", "_id");
}) })
.push(function (researchResult) { .push(function (attachment) {
var result = researchResult.result, var total_length = attachment.info.length,
start, i,
end; promise_list = [],
if (result === undefined || store = transaction.objectStore("blob"),
result._attachment[param._attachment] === undefined) { start_index,
throw new jIO.util.jIOError("IndexeddbStorage unable to get attachment.", 404); end_index;
start = param._start || 0;
end = param._end || total_length;
if (end > total_length) {
end = total_length;
} }
totalLength = result._attachment[param._attachment].length;
param._start = param._start === undefined ? 0 : param._start; if (start < 0 || end < 0) {
param._end = param._end === undefined ? totalLength throw new jIO.util.jIOError("_start and _end must be positive",
: param._end; 400);
if (param._end > totalLength) {
param._end = totalLength;
} }
if (param._start < 0 || param._end < 0) { if (start > end) {
throw ({"status": 404, "reason": "invalide _start, _end", throw new jIO.util.jIOError("_start is greater than _end",
"message": "_start and _end must be positive"}); 400);
} }
if (param._start > param._end) {
throw ({"status": 404, "reason": "invalide offset", start_index = Math.floor(start / UNITE);
"message": "start is great then end"}); end_index = Math.floor(end / UNITE);
if (end % UNITE === 0) {
end_index -= 1;
} }
start = Math.floor(param._start / jio_storage._unite);
end = Math.floor(param._end / jio_storage._unite); for (i = start_index; i <= end_index; i += 1) {
if (param._end % jio_storage._unite === 0) { promise_list.push(
end -= 1; handleGet(store.get(buildKeyPath([param._id,
param._attachment, i])))
);
} }
return getDesirePart(transaction.objectStore("blob"), return RSVP.all(promise_list);
start,
end);
}) })
.push(function () { .push(function (result_list) {
var start = param._start % jio_storage._unite, var array_buffer_list = [],
end = start + param._end - param._start; blob,
blob = blob.slice(start, end); i,
return new Blob([blob], {type: "text/plain"}); len = result_list.length;
}) for (i = 0; i < len; i += 1) {
.push(undefined, function (error) { array_buffer_list.push(result_list[i].blob);
// Check if transaction is ongoing, if so, abort it
if (transaction !== undefined) {
transaction.abort();
}
if (global_db !== undefined) {
global_db.close();
} }
throw error; blob = new Blob(array_buffer_list, {type: "application/octet-stream"});
return {data: blob.slice(start, end)};
}); });
}; };
function removeAttachment(transaction, param) {
return RSVP.all([
// XXX How to get the right attachment
handleRequest(transaction.objectStore("attachment")["delete"](
buildKeyPath([param._id, param._attachment])
)),
handleCursor(transaction.objectStore("blob").index("_id_attachment")
.openCursor(), deleteEntry)
]);
}
/** IndexedDBStorage.prototype.putAttachment = function (metadata) {
* Remove an attachment var blob_part = [],
*
* @method removeAttachment
* @param {Object} param The command parameters
*/
IndexedDBStorage.prototype.removeAttachment = function (param) {
var jio_storage = this,
transaction, transaction,
global_db, db;
totalLength;
function removePart(store, part) { return openIndexedDB(this)
if (part * jio_storage._unite >= totalLength) { .push(function (database) {
return; db = database;
}
return removeIndexedDB(store, [param._id, param._attachment, part]) // Split the blob first
.then(function () { return jIO.util.readBlobAsArrayBuffer(metadata._blob);
return removePart(store, part + 1);
});
}
return new RSVP.Queue()
.push(function () {
return openIndexedDB(jio_storage._database_name);
})
.push(function (db) {
global_db = db;
transaction = db.transaction(["attachment", "blob"], "readwrite");
//check if the attachment exists
return promiseResearch(transaction, param._id,
"attachment", "_id");
}) })
.push(function (researchResult) { .push(function (event) {
var result = researchResult.result; var array_buffer = event.target.result,
if (result === undefined || total_size = metadata._blob.size,
result._attachment[param._attachment] === undefined) { handled_size = 0;
throw ({"status": 404, "reason": "missing attachment",
"message": while (handled_size < total_size) {
"IndexeddbStorage, document attachment not found."}); blob_part.push(array_buffer.slice(handled_size,
handled_size + UNITE));
handled_size += UNITE;
} }
totalLength = result._attachment[param._attachment].length;
//updata attachment // Remove previous attachment
delete result._attachment[param._attachment]; transaction = openTransaction(db, ["attachment", "blob"], "readwrite");
return putIndexedDB(researchResult.store, result); return removeAttachment(transaction, metadata);
})
.push(function () {
var store = transaction.objectStore("blob");
return removePart(store, 0);
}) })
.push(function () { .push(function () {
return transactionEnd(transaction);
}) var promise_list = [
.push(undefined, function (error) { handleRequest(transaction.objectStore("attachment").put({
if (global_db !== undefined) { "_key_path": buildKeyPath([metadata._id, metadata._attachment]),
global_db.close(); "_id": metadata._id,
"_attachment": metadata._attachment,
"info": {
"content_type": metadata._blob.type,
"length": metadata._blob.size
}
}))
],
len = blob_part.length,
blob_store = transaction.objectStore("blob"),
i;
for (i = 0; i < len; i += 1) {
promise_list.push(
handleRequest(blob_store.put({
"_key_path": buildKeyPath([metadata._id, metadata._attachment,
i]),
"_id" : metadata._id,
"_attachment" : metadata._attachment,
"_part" : i,
"blob": blob_part[i]
}))
);
} }
throw error; // Store all new data
return RSVP.all(promise_list);
}); });
}; };
IndexedDBStorage.prototype.removeAttachment = function (param) {
IndexedDBStorage.prototype.hasCapacity = function (name) { return openIndexedDB(this)
return (name === "list");
};
IndexedDBStorage.prototype.buildQuery = function () {
var jio_storage = this,
global_db;
return new RSVP.Queue()
.push(function () {
return openIndexedDB(jio_storage._database_name);
})
.push(function (db) { .push(function (db) {
global_db = db; var transaction = openTransaction(db, ["attachment", "blob"],
"readwrite");
var onCancel; return removeAttachment(transaction, param);
return new RSVP.Promise(function (resolve, reject) {
var rows = [], open_req = indexedDB.open(jio_storage._database_name);
open_req.onerror = function () {
if (open_req.result) { open_req.result.close(); }
reject(open_req.error);
};
open_req.onsuccess = function () {
var tx, index_req, db = open_req.result;
try {
tx = db.transaction(["metadata"], "readonly");
onCancel = function () {
tx.abort();
db.close();
};
index_req = tx.objectStore("metadata").index("_id").openCursor();
index_req.onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
rows.push({
"id": cursor.value._id,
"value": {}
});
// continue to next iteration
cursor["continue"]();
} else {
db.close();
resolve(rows);
}
};
} catch (e) {
reject(e);
db.close();
}
};
}, function () {
if (typeof onCancel === "function") {
onCancel();
}
});
})
.push(undefined, function (error) {
if (global_db !== undefined) {
global_db.close();
}
throw error;
}); });
}; };
jIO.addStorage("indexeddb", IndexedDBStorage); jIO.addStorage("indexeddb", IndexedDBStorage);
}(jIO)); }(indexedDB, jIO, RSVP, Blob, Math));
/*jslint maxlen: 120, nomen: true */ /*jslint nomen: true */
/*global indexedDB, test_util, console, Blob, sinon*/ /*global indexedDB, Blob, sinon, IDBDatabase,
(function (jIO, QUnit) { IDBTransaction, IDBIndex, IDBObjectStore, IDBCursor*/
(function (jIO, QUnit, indexedDB, Blob, sinon, IDBDatabase,
IDBTransaction, IDBIndex, IDBObjectStore, IDBCursor) {
"use strict"; "use strict";
var test = QUnit.test, var test = QUnit.test,
stop = QUnit.stop, stop = QUnit.stop,
...@@ -9,26 +11,364 @@ ...@@ -9,26 +11,364 @@
expect = QUnit.expect, expect = QUnit.expect,
deepEqual = QUnit.deepEqual, deepEqual = QUnit.deepEqual,
equal = QUnit.equal, equal = QUnit.equal,
module = QUnit.module; module = QUnit.module,
big_string = "",
j;
module("indexeddbStorage", { for (j = 0; j < 3000000; j += 1) {
big_string += "a";
}
function deleteIndexedDB(storage) {
return new RSVP.Queue()
.push(function () {
function resolver(resolve, reject) {
var request = indexedDB.deleteDatabase(
storage.__storage._database_name
);
request.onerror = reject;
request.onblocked = reject;
request.onsuccess = resolve;
}
return new RSVP.Promise(resolver);
});
}
/////////////////////////////////////////////////////////////////
// indexeddbStorage.constructor
/////////////////////////////////////////////////////////////////
module("indexeddbStorage.constructor");
test("default unite value", function () {
var jio = jIO.createJIO({
type: "indexeddb",
database: "qunit"
});
equal(jio.__type, "indexeddb");
deepEqual(jio.__storage._database_name, "jio:qunit");
});
/////////////////////////////////////////////////////////////////
// documentStorage.hasCapacity
/////////////////////////////////////////////////////////////////
module("indexeddbStorage.hasCapacity");
test("can list documents", function () {
var jio = jIO.createJIO({
type: "indexeddb",
database: "qunit"
});
ok(jio.hasCapacity("list"));
});
/////////////////////////////////////////////////////////////////
// indexeddbStorage.buildQuery
/////////////////////////////////////////////////////////////////
module("indexeddbStorage.buildQuery", {
setup: function () { setup: function () {
// localStorage.clear();
this.jio = jIO.createJIO({ this.jio = jIO.createJIO({
"type": "indexeddb", type: "indexeddb",
"database": "qunit" database: "qunit"
}); });
this.spy_open = sinon.spy(indexedDB, "open");
this.spy_create_store = sinon.spy(IDBDatabase.prototype,
"createObjectStore");
this.spy_transaction = sinon.spy(IDBDatabase.prototype, "transaction");
this.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
this.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
this.spy_create_index = sinon.spy(IDBObjectStore.prototype,
"createIndex");
this.spy_key_cursor = sinon.spy(IDBIndex.prototype, "openKeyCursor");
},
teardown: function () {
this.spy_open.restore();
delete this.spy_open;
this.spy_create_store.restore();
delete this.spy_create_store;
this.spy_transaction.restore();
delete this.spy_transaction;
this.spy_store.restore();
delete this.spy_store;
this.spy_index.restore();
delete this.spy_index;
this.spy_create_index.restore();
delete this.spy_create_index;
this.spy_key_cursor.restore();
delete this.spy_key_cursor;
} }
}); });
test("spy indexedDB usage", function () {
var context = this;
stop();
expect(30);
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.allDocs();
})
.then(function () {
ok(context.spy_open.calledOnce, "open count " +
context.spy_open.callCount);
equal(context.spy_open.firstCall.args[0], "jio:qunit",
"open first argument");
equal(context.spy_create_store.callCount, 3,
"createObjectStore count");
equal(context.spy_create_store.firstCall.args[0], "metadata",
"first createObjectStore first argument");
deepEqual(context.spy_create_store.firstCall.args[1],
{keyPath: "_id", autoIncrement: false},
"first createObjectStore second argument");
equal(context.spy_create_store.secondCall.args[0], "attachment",
"second createObjectStore first argument");
deepEqual(context.spy_create_store.secondCall.args[1],
{keyPath: "_key_path", autoIncrement: false},
"second createObjectStore second argument");
equal(context.spy_create_store.thirdCall.args[0], "blob",
"third createObjectStore first argument");
deepEqual(context.spy_create_store.thirdCall.args[1],
{keyPath: "_key_path", autoIncrement: false},
"third createObjectStore second argument");
equal(context.spy_create_index.callCount, 4, "createIndex count");
equal(context.spy_create_index.firstCall.args[0], "_id",
"first createIndex first argument");
equal(context.spy_create_index.firstCall.args[1], "_id",
"first createIndex second argument");
deepEqual(context.spy_create_index.firstCall.args[2], {unique: true},
"first createIndex third argument");
equal(context.spy_create_index.secondCall.args[0], "_id",
"second createIndex first argument");
equal(context.spy_create_index.secondCall.args[1], "_id",
"second createIndex second argument");
deepEqual(context.spy_create_index.secondCall.args[2], {unique: false},
"second createIndex third argument");
equal(context.spy_create_index.thirdCall.args[0], "_id_attachment",
"third createIndex first argument");
deepEqual(context.spy_create_index.thirdCall.args[1],
["_id", "_attachment"],
"third createIndex second argument");
deepEqual(context.spy_create_index.thirdCall.args[2],
{unique: false},
"third createIndex third argument");
equal(context.spy_create_index.getCall(3).args[0], "_id",
"fourth createIndex first argument");
equal(context.spy_create_index.getCall(3).args[1], "_id",
"fourth createIndex second argument");
deepEqual(context.spy_create_index.getCall(3).args[2], {unique: false},
"fourth createIndex third argument");
ok(context.spy_transaction.calledOnce, "transaction count " +
context.spy_transaction.callCount);
deepEqual(context.spy_transaction.firstCall.args[0], ["metadata"],
"transaction first argument");
equal(context.spy_transaction.firstCall.args[1], "readonly",
"transaction second argument");
ok(context.spy_store.calledOnce, "store count " +
context.spy_store.callCount);
deepEqual(context.spy_store.firstCall.args[0], "metadata",
"store first argument");
ok(context.spy_index.calledOnce, "index count " +
context.spy_index.callCount);
deepEqual(context.spy_index.firstCall.args[0], "_id",
"index first argument");
ok(context.spy_key_cursor.calledOnce, "key_cursor count " +
context.spy_key_cursor.callCount);
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("empty result", function () {
var context = this;
stop();
expect(1);
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.allDocs();
})
.then(function (result) {
deepEqual(result, {
"data": {
"rows": [
],
"total_rows": 0
}
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("list all documents", function () {
var context = this;
stop();
expect(1);
deleteIndexedDB(context.jio)
.then(function () {
return RSVP.all([
context.jio.put({"_id": "2", "title": "title2"}),
context.jio.put({"_id": "1", "title": "title1"})
]);
})
.then(function () {
return context.jio.allDocs();
})
.then(function (result) {
deepEqual(result, {
"data": {
"rows": [{
"id": "1",
"value": {}
}, {
"id": "2",
"value": {}
}],
"total_rows": 2
}
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// indexeddbStorage.get // indexeddbStorage.get
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
module("indexeddbStorage.get", {
setup: function () {
this.jio = jIO.createJIO({
type: "indexeddb",
database: "qunit"
});
}
});
test("spy indexedDB usage", function () {
var context = this;
stop();
expect(15);
deleteIndexedDB(context.jio)
.then(function () {
return context.jio.put({"_id": "foo", "title": "bar"});
})
.then(function () {
context.spy_open = sinon.spy(indexedDB, "open");
context.spy_create_store = sinon.spy(IDBDatabase.prototype,
"createObjectStore");
context.spy_transaction = sinon.spy(IDBDatabase.prototype,
"transaction");
context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
context.spy_get = sinon.spy(IDBObjectStore.prototype, "get");
context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
"createIndex");
context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
return context.jio.get({"_id": "foo"});
})
.then(function () {
ok(context.spy_open.calledOnce, "open count " +
context.spy_open.callCount);
equal(context.spy_open.firstCall.args[0], "jio:qunit",
"open first argument");
equal(context.spy_create_store.callCount, 0,
"createObjectStore count");
equal(context.spy_create_index.callCount, 0, "createIndex count");
ok(context.spy_transaction.calledOnce, "transaction count " +
context.spy_transaction.callCount);
deepEqual(context.spy_transaction.firstCall.args[0],
["metadata", "attachment"], "transaction first argument");
equal(context.spy_transaction.firstCall.args[1], "readonly",
"transaction second argument");
ok(context.spy_store.calledTwice, "store count " +
context.spy_store.callCount);
deepEqual(context.spy_store.firstCall.args[0], "metadata",
"store first argument");
deepEqual(context.spy_store.secondCall.args[0], "attachment",
"store first argument");
ok(context.spy_get.calledOnce, "index count " +
context.spy_get.callCount);
deepEqual(context.spy_get.firstCall.args[0], "foo",
"get first argument");
ok(context.spy_index.calledOnce, "index count " +
context.spy_index.callCount);
deepEqual(context.spy_index.firstCall.args[0], "_id",
"index first argument");
ok(context.spy_cursor.calledOnce, "cursor count " +
context.spy_cursor.callCount);
})
.always(function () {
context.spy_open.restore();
delete context.spy_open;
context.spy_create_store.restore();
delete context.spy_create_store;
context.spy_transaction.restore();
delete context.spy_transaction;
context.spy_store.restore();
delete context.spy_store;
context.spy_get.restore();
delete context.spy_get;
context.spy_index.restore();
delete context.spy_index;
context.spy_create_index.restore();
delete context.spy_create_index;
context.spy_cursor.restore();
delete context.spy_cursor;
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("get inexistent document", function () { test("get inexistent document", function () {
var context = this;
stop(); stop();
expect(3); expect(3);
this.jio.get({"_id": "inexistent"}) deleteIndexedDB(context.jio)
.then(function () {
return context.jio.get({"_id": "inexistent"});
})
.fail(function (error) { .fail(function (error) {
ok(error instanceof jIO.util.jIOError); ok(error instanceof jIO.util.jIOError);
equal(error.message, "Cannot find document"); equal(error.message, "Cannot find document");
...@@ -42,861 +382,881 @@ ...@@ -42,861 +382,881 @@
}); });
}); });
test("get document", function () { test("get document without attachment", function () {
var id = "post1", var id = "/",
// myAPI, context = this;
indexedDB, stop();
mock; expect(1);
// localStorage[id] = JSON.stringify({
// title: "myPost1" deleteIndexedDB(context.jio)
// }); .then(function () {
return context.jio.put({"_id": id, "title": "bar"});
indexedDB = { })
open: function () { .then(function () {
var result = { return context.jio.get({"_id": id});
result: "taboulet" })
}; .then(function (result) {
RSVP.delay().then(function () { deepEqual(result, {
result.onsuccess(); "_id": "/",
}); "title": "bar"
return result; }, "Check document");
} })
// return RSVP.success("taboulet"); .fail(function (error) {
}; ok(false, error);
})
mock = sinon.mock(indexedDB); .always(function () {
// mock = sinon.mock(indexedDB.open, "open", function () { start();
// var result = { });
// result: "taboulet" });
// };
// RSVP.delay().then(function () {
// result.onsuccess();
// });
// return result;
// // return RSVP.success("taboulet");
// });
mock.expects("open").once().withArgs("couscous");
test("get document with attachment", function () {
var id = "/",
attachment = "foo",
context = this;
stop(); stop();
expect(1); expect(1);
this.jio.get({"_id": id}) deleteIndexedDB(context.jio)
.then(function () {
return context.jio.put({"_id": id, "title": "bar"});
})
.then(function () {
return context.jio.putAttachment({"_id": id, "_attachment": attachment,
"_data": "bar"});
})
.then(function () {
return context.jio.get({"_id": id});
})
.then(function (result) { .then(function (result) {
deepEqual(result, { deepEqual(result, {
"title": "myPost1" "_id": id,
"title": "bar",
"_attachments": {
"foo": {}
}
}, "Check document"); }, "Check document");
mock.verify();
}) })
.fail(function (error) { .fail(function (error) {
ok(false, error); ok(false, error);
}) })
.always(function () { .always(function () {
start(); start();
mock.restore();
}); });
}); });
}(jIO, QUnit)); /////////////////////////////////////////////////////////////////
// indexeddbStorage.put
// /*jslint indent: 2, maxlen: 80, nomen: true */ /////////////////////////////////////////////////////////////////
// /*global module, test, stop, start, expect, ok, deepEqual, location, sinon, module("indexeddbStorage.put", {
// davstorage_spec, RSVP, jIO, test_util, dav_storage, btoa, define, setup: function () {
// setTimeout, clearTimeout, indexedDB */ this.jio = jIO.createJIO({
// type: "indexeddb",
// // define([module_name], [dependencies], module); database: "qunit"
// (function (dependencies, module) { });
// "use strict"; }
// if (typeof define === 'function' && define.amd) { });
// return define(dependencies, module);
// } test("spy indexedDB usage", function () {
// module(test_util, RSVP, jIO); var context = this;
// }([ stop();
// 'test_util', expect(31);
// 'rsvp',
// 'jio', deleteIndexedDB(context.jio)
// 'indexeddbstorage', .then(function () {
// 'qunit' context.spy_open = sinon.spy(indexedDB, "open");
// ], function (util, RSVP, jIO) { context.spy_create_store = sinon.spy(IDBDatabase.prototype,
// "use strict"; "createObjectStore");
// module("indexeddbStorage"); context.spy_transaction = sinon.spy(IDBDatabase.prototype,
// function success(promise) { "transaction");
// return new RSVP.Promise(function (resolve, notify) { context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
// promise.then(resolve, resolve, notify); context.spy_put = sinon.spy(IDBObjectStore.prototype, "put");
// }, function () { context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
// promise.cancel(); context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
// }); "createIndex");
// } context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
//
// test("Scenario", 46, function () { return context.jio.put({"_id": "foo", "title": "bar"});
// indexedDB.deleteDatabase("jio:test"); })
// var server, shared = {}, jio = jIO.createJIO( .then(function () {
// {"type" : "indexeddb",
// "database" : "test" ok(context.spy_open.calledOnce, "open count " +
// }, context.spy_open.callCount);
// {"workspace": {}} equal(context.spy_open.firstCall.args[0], "jio:qunit",
// ); "open first argument");
// stop();
// server = {restore: function () { equal(context.spy_create_store.callCount, 3,
// return; "createObjectStore count");
// }};
// equal(context.spy_create_store.firstCall.args[0], "metadata",
// function postNewDocument() { "first createObjectStore first argument");
// return jio.post({"title": "Unique ID"}); deepEqual(context.spy_create_store.firstCall.args[1],
// } {keyPath: "_id", autoIncrement: false},
// "first createObjectStore second argument");
// function postNewDocumentTest(answer) {
// var uuid = answer.id; equal(context.spy_create_store.secondCall.args[0], "attachment",
// answer.id = "<uuid>"; "second createObjectStore first argument");
// deepEqual(answer, { deepEqual(context.spy_create_store.secondCall.args[1],
// "id": "<uuid>", {keyPath: "_key_path", autoIncrement: false},
// "method": "post", "second createObjectStore second argument");
// "result": "success",
// "status": 201, equal(context.spy_create_store.thirdCall.args[0], "blob",
// "statusText": "Created" "third createObjectStore first argument");
// }, "Post a new document"); deepEqual(context.spy_create_store.thirdCall.args[1],
// ok(util.isUuid(uuid), "New document id should look like " + {keyPath: "_key_path", autoIncrement: false},
// "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + uuid); "third createObjectStore second argument");
// shared.created_document_id = uuid;
// } equal(context.spy_create_index.callCount, 4, "createIndex count");
//
// function getCreatedDocument() { equal(context.spy_create_index.firstCall.args[0], "_id",
// return jio.get({"_id": shared.created_document_id}); "first createIndex first argument");
// } equal(context.spy_create_index.firstCall.args[1], "_id",
// "first createIndex second argument");
// function getCreatedDocumentTest(answer) { deepEqual(context.spy_create_index.firstCall.args[2], {unique: true},
// deepEqual(answer, { "first createIndex third argument");
// "data": {
// "_id": shared.created_document_id, equal(context.spy_create_index.secondCall.args[0], "_id",
// "title": "Unique ID" "second createIndex first argument");
// }, equal(context.spy_create_index.secondCall.args[1], "_id",
// "id": shared.created_document_id, "second createIndex second argument");
// "method": "get", deepEqual(context.spy_create_index.secondCall.args[2],
// "result": "success", {unique: false},
// "status": 200, "second createIndex third argument");
// "statusText": "Ok"
// }, "Get new document"); equal(context.spy_create_index.thirdCall.args[0], "_id_attachment",
// } "third createIndex first argument");
// deepEqual(context.spy_create_index.thirdCall.args[1],
// function postSpecificDocument() { ["_id", "_attachment"],
// return jio.post({"_id": "b", "title": "Bee"}); "third createIndex second argument");
// } deepEqual(context.spy_create_index.thirdCall.args[2], {unique: false},
// "third createIndex third argument");
// function postSpecificDocumentTest(answer) {
// deepEqual(answer, { equal(context.spy_create_index.getCall(3).args[0], "_id",
// "id": "b", "fourth createIndex first argument");
// "method": "post", equal(context.spy_create_index.getCall(3).args[1], "_id",
// "result": "success", "fourth createIndex second argument");
// "status": 201, deepEqual(context.spy_create_index.getCall(3).args[2], {unique: false},
// "statusText": "Created" "fourth createIndex third argument");
// }, "Post specific document");
// } ok(context.spy_transaction.calledOnce, "transaction count " +
// context.spy_transaction.callCount);
// function listDocument() { deepEqual(context.spy_transaction.firstCall.args[0], ["metadata"],
// return jio.allDocs(); "transaction first argument");
// } equal(context.spy_transaction.firstCall.args[1], "readwrite",
// "transaction second argument");
// function list2DocumentsTest(answer) {
// if (answer && answer.data && Array.isArray(answer.data.rows)) { ok(context.spy_store.calledOnce, "store count " +
// answer.data.rows.sort(function (a) { context.spy_store.callCount);
// return a.id === "b" ? 1 : 0; deepEqual(context.spy_store.firstCall.args[0], "metadata",
// }); "store first argument");
// }
// deepEqual(answer, { ok(context.spy_put.calledOnce, "put count " +
// "data": { context.spy_put.callCount);
// "total_rows": 2, deepEqual(context.spy_put.firstCall.args[0],
// "rows": [{ {"_id": "foo", title: "bar"},
// "id": shared.created_document_id, "put first argument");
// "value": {}
// }, { ok(!context.spy_index.called, "index count " +
// "id": "b", context.spy_index.callCount);
// "value": {}
// }] ok(!context.spy_cursor.called, "cursor count " +
// }, context.spy_cursor.callCount);
// "method": "allDocs",
// "result": "success", })
// "status": 200, .always(function () {
// "statusText": "Ok" context.spy_open.restore();
// }, "List 2 documents"); delete context.spy_open;
// } context.spy_create_store.restore();
// delete context.spy_create_store;
// function listDocumentsWithMetadata() { context.spy_transaction.restore();
// return jio.allDocs({"include_docs": true}); delete context.spy_transaction;
// } context.spy_store.restore();
// delete context.spy_store;
// function list2DocumentsWithMetadataTest(answer) { context.spy_put.restore();
// if (answer && answer.data && Array.isArray(answer.data.rows)) { delete context.spy_put;
// answer.data.rows.sort(function (a) { context.spy_index.restore();
// return a.id === "b" ? 1 : 0; delete context.spy_index;
// }); context.spy_create_index.restore();
// } delete context.spy_create_index;
// deepEqual(answer, { context.spy_cursor.restore();
// "data": { delete context.spy_cursor;
// "total_rows": 2, })
// "rows": [{ .fail(function (error) {
// "id": shared.created_document_id, ok(false, error);
// "value": {}, })
// "doc": { .always(function () {
// "_id": shared.created_document_id, start();
// "title": "Unique ID" });
// } });
// }, {
// "id": "b", test("put document", function () {
// "value": {}, var context = this;
// "doc": { stop();
// "_id": "b", expect(1);
// "title": "Bee"
// } deleteIndexedDB(context.jio)
// }] .then(function () {
// }, return context.jio.put({"_id": "inexistent"});
// "method": "allDocs", })
// "result": "success", .then(function (result) {
// "status": 200, equal(result, "inexistent");
// "statusText": "Ok" })
// }, "List 2 documents with their metadata"); .fail(function (error) {
// } ok(false, error);
// })
// function removeCreatedDocument() { .always(function () {
// return jio.remove({"_id": shared.created_document_id}); start();
// } });
// });
// function removeCreatedDocumentTest(answer) {
// deepEqual(answer, { /////////////////////////////////////////////////////////////////
// "id": shared.created_document_id, // indexeddbStorage.remove
// "method": "remove", /////////////////////////////////////////////////////////////////
// "result": "success", module("indexeddbStorage.remove", {
// "status": 204, setup: function () {
// "statusText": "No Content" this.jio = jIO.createJIO({
// }, "Remove first document."); type: "indexeddb",
// } database: "qunit"
// });
// function removeSpecificDocument() { }
// return jio.remove({"_id": "b"}); });
// }
// test("spy indexedDB usage with one document", function () {
// function removeSpecificDocumentTest(answer) { var context = this;
// deepEqual(answer, { stop();
// "id": "b", expect(18);
// "method": "remove",
// "result": "success", deleteIndexedDB(context.jio)
// "status": 204, .then(function () {
// "statusText": "No Content" return context.jio.put({"_id": "foo", "title": "bar"});
// }, "Remove second document."); })
// } .then(function () {
// context.spy_open = sinon.spy(indexedDB, "open");
// function listEmptyStorage() { context.spy_create_store = sinon.spy(IDBDatabase.prototype,
// return jio.allDocs(); "createObjectStore");
// } context.spy_transaction = sinon.spy(IDBDatabase.prototype,
// "transaction");
// function listEmptyStorageTest(answer) { context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
// deepEqual(answer, { context.spy_delete = sinon.spy(IDBObjectStore.prototype, "delete");
// "data": { context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
// "total_rows": 0, context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
// "rows": [] "createIndex");
// }, context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
// "method": "allDocs", context.spy_cursor_delete = sinon.spy(IDBCursor.prototype, "delete");
// "result": "success",
// "status": 200, return context.jio.remove({"_id": "foo"});
// "statusText": "Ok" })
// }, "List empty storage"); .then(function () {
// }
// ok(context.spy_open.calledOnce, "open count " +
// function putNewDocument() { context.spy_open.callCount);
// return jio.put({"_id": "a", "title": "Hey"}); equal(context.spy_open.firstCall.args[0], "jio:qunit",
// } "open first argument");
//
// function putNewDocumentTest(answer) { equal(context.spy_create_store.callCount, 0,
// deepEqual(answer, { "createObjectStore count");
// "id": "a", equal(context.spy_create_index.callCount, 0, "createIndex count");
// "method": "put",
// "result": "success", ok(context.spy_transaction.calledOnce, "transaction count " +
// "status": 201, context.spy_transaction.callCount);
// "statusText": "Created" deepEqual(context.spy_transaction.firstCall.args[0],
// }, "Put new document"); ["metadata", "attachment", "blob"],
// } "transaction first argument");
// equal(context.spy_transaction.firstCall.args[1], "readwrite",
// function getCreatedDocument2() { "transaction second argument");
// return jio.get({"_id": "a"});
// } equal(context.spy_store.callCount, 3, "store count " +
// context.spy_store.callCount);
// function getCreatedDocument2Test(answer) { deepEqual(context.spy_store.firstCall.args[0], "metadata",
// deepEqual(answer, { "store first argument");
// "data": { deepEqual(context.spy_store.secondCall.args[0], "attachment",
// "_id": "a", "store first argument");
// "title": "Hey" deepEqual(context.spy_store.thirdCall.args[0], "blob",
// }, "store first argument");
// "id": "a",
// "method": "get", ok(context.spy_delete.calledOnce, "delete count " +
// "result": "success", context.spy_delete.callCount);
// "status": 200, deepEqual(context.spy_delete.firstCall.args[0], "foo",
// "statusText": "Ok" "delete first argument");
// }, "Get new document");
// } ok(context.spy_index.calledTwice, "index count " +
// context.spy_index.callCount);
// function postSameDocument() { deepEqual(context.spy_index.firstCall.args[0], "_id",
// return success(jio.post({"_id": "a", "title": "Hoo"})); "index first argument");
// } deepEqual(context.spy_index.secondCall.args[0], "_id",
// "index first argument");
// function postSameDocumentTest(answer) {
// deepEqual(answer, { ok(context.spy_cursor.calledTwice, "cursor count " +
// "error": "conflict", context.spy_cursor.callCount);
// "id": "a", equal(context.spy_cursor_delete.callCount, 0, "cursor count " +
// "message": "Command failed", context.spy_cursor_delete.callCount);
// "method": "post",
// "reason": "Document exists", })
// "result": "error", .always(function () {
// "status": 409, context.spy_open.restore();
// "statusText": "Conflict" delete context.spy_open;
// }, "Unable to post the same document (conflict)"); context.spy_create_store.restore();
// } delete context.spy_create_store;
// context.spy_transaction.restore();
// function putAttachmentToNonExistentDocument() { delete context.spy_transaction;
// return success(jio.putAttachment({ context.spy_store.restore();
// "_id": "ahaha", delete context.spy_store;
// "_attachment": "aa", context.spy_delete.restore();
// "_data": "aaa", delete context.spy_delete;
// "_content_type": "text/plain" context.spy_index.restore();
// })); delete context.spy_index;
// } context.spy_create_index.restore();
// delete context.spy_create_index;
// function putAttachmentToNonExistentDocumentTest(answer) { context.spy_cursor.restore();
// deepEqual(answer, { delete context.spy_cursor;
// "attachment": "aa", context.spy_cursor_delete.restore();
// "error": "not_found", delete context.spy_cursor_delete;
// "id": "ahaha", })
// "message": "indexeddbStorage unable to put attachment", .fail(function (error) {
// "method": "putAttachment", ok(false, error);
// "reason": "Not Found", })
// "result": "error", .always(function () {
// "status": 404, start();
// "statusText": "Not Found" });
// }, "Put attachment to a non existent document -> 404 Not Found"); });
// }
// test("spy indexedDB usage with 2 attachments", function () {
// function createAttachment() { var context = this;
// return jio.putAttachment({ stop();
// "_id": "a", expect(18);
// "_attachment": "aa",
// "_data": "aaa", deleteIndexedDB(context.jio)
// "_content_type": "text/plain" .then(function () {
// }); return context.jio.put({"_id": "foo", "title": "bar"});
// } })
// .then(function () {
// function createAttachmentTest(answer) { return RSVP.all([
// deepEqual(answer, { context.jio.putAttachment({"_id": "foo",
// "attachment": "aa", "_attachment": "attachment1",
// "id": "a", "_data": "bar"}),
// "method": "putAttachment", context.jio.putAttachment({"_id": "foo",
// "result": "success", "_attachment": "attachment2",
// "status": 204, "_data": "bar2"})
// "statusText": "No Content" ]);
// }, "Create new attachment"); })
// } .then(function () {
// context.spy_open = sinon.spy(indexedDB, "open");
// function updateAttachment() { context.spy_create_store = sinon.spy(IDBDatabase.prototype,
// return jio.putAttachment({ "createObjectStore");
// "_id": "a", context.spy_transaction = sinon.spy(IDBDatabase.prototype,
// "_attachment": "aa", "transaction");
// "_data": "aab", context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
// "_content_type": "text/plain" context.spy_delete = sinon.spy(IDBObjectStore.prototype, "delete");
// }); context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
// } context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
// "createIndex");
// function updateAttachmentTest(answer) { context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
// deepEqual(answer, { context.spy_cursor_delete = sinon.spy(IDBCursor.prototype, "delete");
// "attachment": "aa",
// "id": "a", return context.jio.remove({"_id": "foo"});
// "method": "putAttachment", })
// "result": "success", .then(function () {
// "status": 204,
// "statusText": "No Content" ok(context.spy_open.calledOnce, "open count " +
// }, "Update last attachment"); context.spy_open.callCount);
// } equal(context.spy_open.firstCall.args[0], "jio:qunit",
// "open first argument");
// function createAnotherAttachment() {
// return jio.putAttachment({ equal(context.spy_create_store.callCount, 0, "createObjectStore count");
// "_id": "a", equal(context.spy_create_index.callCount, 0, "createIndex count");
// "_attachment": "ab",
// "_data": "aba", ok(context.spy_transaction.calledOnce, "transaction count " +
// "_content_type": "text/plain" context.spy_transaction.callCount);
// }); deepEqual(context.spy_transaction.firstCall.args[0],
// } ["metadata", "attachment", "blob"],
// "transaction first argument");
// function createAnotherAttachmentTest(answer) { equal(context.spy_transaction.firstCall.args[1], "readwrite",
// deepEqual(answer, { "transaction second argument");
// "attachment": "ab",
// "id": "a", equal(context.spy_store.callCount, 3, "store count " +
// "method": "putAttachment", context.spy_store.callCount);
// "result": "success", deepEqual(context.spy_store.firstCall.args[0], "metadata",
// "status": 204, "store first argument");
// "statusText": "No Content" deepEqual(context.spy_store.secondCall.args[0], "attachment",
// }, "Create another attachment"); "store first argument");
// } deepEqual(context.spy_store.thirdCall.args[0], "blob",
// "store first argument");
//
// function updateLastDocument() { equal(context.spy_delete.callCount, 1, "delete count " +
// return jio.put({"_id": "a", "title": "Hoo"}); context.spy_delete.callCount);
// } deepEqual(context.spy_delete.firstCall.args[0], "foo",
// "delete first argument");
// function updateLastDocumentTest(answer) {
// deepEqual(answer, { ok(context.spy_index.calledTwice, "index count " +
// "id": "a", context.spy_index.callCount);
// "method": "put", deepEqual(context.spy_index.firstCall.args[0], "_id",
// "result": "success", "index first argument");
// "status": 204, deepEqual(context.spy_index.secondCall.args[0], "_id",
// "statusText": "No Content" "index first argument");
// }, "Update document metadata");
// } ok(context.spy_cursor.calledTwice, "cursor count " +
// context.spy_cursor.callCount);
// function getFirstAttachment() {
// return jio.getAttachment({"_id": "a", "_attachment": "aa"}); equal(context.spy_cursor_delete.callCount, 3, "cursor count " +
// } context.spy_cursor_delete.callCount);
//
// function getFirstAttachmentTest(answer) { })
// var blob = answer.data; .always(function () {
// answer.data = "<blob>"; context.spy_open.restore();
// return jIO.util.readBlobAsText(blob).then(function (e) { delete context.spy_open;
// deepEqual(blob.type, "text/plain", "Check blob type"); context.spy_create_store.restore();
// deepEqual(e.target.result, "aab", "Check blob text content"); delete context.spy_create_store;
// deepEqual(answer, { context.spy_transaction.restore();
// "attachment": "aa", delete context.spy_transaction;
// "data": "<blob>", context.spy_store.restore();
// "id": "a", delete context.spy_store;
// "method": "getAttachment", context.spy_delete.restore();
// "result": "success", delete context.spy_delete;
// "status": 200, context.spy_index.restore();
// "statusText": "Ok" delete context.spy_index;
// }, "Get first attachment"); context.spy_create_index.restore();
// }, function (err) { delete context.spy_create_index;
// deepEqual(err, "no error", "Check blob text content"); context.spy_cursor.restore();
// }); delete context.spy_cursor;
// } context.spy_cursor_delete.restore();
// delete context.spy_cursor_delete;
// function getFirstAttachmentRange1() { })
// return jio.getAttachment({"_id": "a", .fail(function (error) {
// "_attachment": "aa", ok(false, error);
// "_start": 0}); })
// } .always(function () {
// start();
// function getFirstAttachmentRangeTest1(answer) { });
// var blob = answer.data; });
// answer.data = "<blob>";
// return jIO.util.readBlobAsText(blob).then(function (e) { /////////////////////////////////////////////////////////////////
// deepEqual(blob.type, "text/plain", "Check blob type"); // indexeddbStorage.getAttachment
// deepEqual(e.target.result, "aab", "Check blob text content"); /////////////////////////////////////////////////////////////////
// deepEqual(answer, { module("indexeddbStorage.getAttachment", {
// "attachment": "aa", setup: function () {
// "data": "<blob>", this.jio = jIO.createJIO({
// "id": "a", type: "indexeddb",
// "method": "getAttachment", database: "qunit"
// "result": "success", });
// "status": 200, }
// "statusText": "Ok" });
// }, "Get first attachment with range :_start:0, _end:undefined");
// }, function (err) { test("spy indexedDB usage", function () {
// deepEqual(err, "no error", "Check blob text content"); var context = this,
// }); attachment = "attachment";
// } stop();
// expect(15);
//
// function getFirstAttachmentRange2() {
// return jio.getAttachment({"_id": "a", deleteIndexedDB(context.jio)
// "_attachment": "aa", .then(function () {
// "_start": 0, return context.jio.put({"_id": "foo", "title": "bar"});
// "_end": 1}); })
// } .then(function () {
// return context.jio.putAttachment({"_id": "foo",
// function getFirstAttachmentRangeTest2(answer) { "_attachment": attachment,
// var blob = answer.data; "_data": big_string});
// answer.data = "<blob>"; })
// return jIO.util.readBlobAsText(blob).then(function (e) { .then(function () {
// deepEqual(blob.type, "text/plain", "Check blob type"); context.spy_open = sinon.spy(indexedDB, "open");
// deepEqual(e.target.result, "a", "Check blob text content"); context.spy_create_store = sinon.spy(IDBDatabase.prototype,
// deepEqual(answer, { "createObjectStore");
// "attachment": "aa", context.spy_transaction = sinon.spy(IDBDatabase.prototype,
// "data": "<blob>", "transaction");
// "id": "a", context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
// "method": "getAttachment", context.spy_get = sinon.spy(IDBObjectStore.prototype, "get");
// "result": "success", context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
// "status": 200, context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
// "statusText": "Ok" "createIndex");
// }, "Get first attachment with range :_start:0, _end:1");
// }, function (err) { return context.jio.getAttachment({"_id": "foo",
// deepEqual(err, "no error", "Check blob text content"); "_attachment": attachment});
// }); })
// } .then(function () {
//
// function getFirstAttachmentRange3() { ok(context.spy_open.calledOnce, "open count " +
// return jio.getAttachment({"_id": "a", context.spy_open.callCount);
// "_attachment": "aa", equal(context.spy_open.firstCall.args[0], "jio:qunit",
// "_start": 1, "open first argument");
// "_end": 3});
// } equal(context.spy_create_store.callCount, 0,
// function getFirstAttachmentRangeTest3(answer) { "createObjectStore count");
// var blob = answer.data; equal(context.spy_create_index.callCount, 0, "createIndex count");
// answer.data = "<blob>";
// return jIO.util.readBlobAsText(blob).then(function (e) { ok(context.spy_transaction.calledOnce, "transaction count " +
// deepEqual(blob.type, "text/plain", "Check blob type"); context.spy_transaction.callCount);
// deepEqual(e.target.result, "ab", "Check blob text content"); deepEqual(context.spy_transaction.firstCall.args[0],
// deepEqual(answer, { ["attachment", "blob"],
// "attachment": "aa", "transaction first argument");
// "data": "<blob>", equal(context.spy_transaction.firstCall.args[1], "readonly",
// "id": "a", "transaction second argument");
// "method": "getAttachment",
// "result": "success", equal(context.spy_store.callCount, 2, "store count " +
// "status": 200, context.spy_store.callCount);
// "statusText": "Ok" deepEqual(context.spy_store.firstCall.args[0], "attachment",
// }, "Get first attachment with range :_start:1, _end:3"); "store first argument");
// }, function (err) { deepEqual(context.spy_store.secondCall.args[0], "blob",
// deepEqual(err, "no error", "Check blob text content"); "store first argument");
// });
// } equal(context.spy_get.callCount, 3, "get count " +
// context.spy_get.callCount);
// deepEqual(context.spy_get.firstCall.args[0], "foo_attachment",
// function getSecondAttachment() { "get first argument");
// return jio.getAttachment({"_id": "a", "_attachment": "ab"}); deepEqual(context.spy_get.secondCall.args[0], "foo_attachment_0",
// } "get first argument");
// deepEqual(context.spy_get.thirdCall.args[0], "foo_attachment_1",
// function getSecondAttachmentTest(answer) { "get first argument");
// var blob = answer.data;
// answer.data = "<blob>"; ok(!context.spy_index.called, "index count " +
// return jIO.util.readBlobAsText(blob).then(function (e) { context.spy_index.callCount);
// deepEqual(blob.type, "text/plain", "Check blob type"); })
// deepEqual(e.target.result, "aba", "Check blob text content"); .always(function () {
// deepEqual(answer, { context.spy_open.restore();
// "attachment": "ab", delete context.spy_open;
// "data": "<blob>", context.spy_create_store.restore();
// "id": "a", delete context.spy_create_store;
// "method": "getAttachment", context.spy_transaction.restore();
// "result": "success", delete context.spy_transaction;
// "status": 200, context.spy_store.restore();
// "statusText": "Ok" delete context.spy_store;
// }, "Get second attachment"); context.spy_get.restore();
// }, function (err) { delete context.spy_get;
// deepEqual(err, "no error", "Check blob text content"); context.spy_index.restore();
// }); delete context.spy_index;
// } context.spy_create_index.restore();
// delete context.spy_create_index;
// })
// .fail(function (error) {
// ok(false, error);
// })
// function getSecondAttachmentRange1() { .always(function () {
// return success(jio.getAttachment({"_id": "a", start();
// "_attachment": "ab", });
// "_start": -1})); });
// }
// function getSecondAttachmentRangeTest1(answer) { test("check result", function () {
// deepEqual(answer, { var context = this,
// "attachment": "ab", attachment = "attachment";
// "error": "not_found", stop();
// "id": "a", expect(2);
// "message": "_start and _end must be positive",
// "method": "getAttachment", deleteIndexedDB(context.jio)
// "reason": "invalide _start, _end", .then(function () {
// "result": "error", return context.jio.put({"_id": "foo", "title": "bar"});
// "status": 404, })
// "statusText": "Not Found" .then(function () {
// }, "get attachment with _start or _end negative -> 404 Not Found"); return context.jio.putAttachment({"_id": "foo",
// } "_attachment": attachment,
// "_data": big_string});
// })
// .then(function () {
// function getSecondAttachmentRange2() { return context.jio.getAttachment({"_id": "foo",
// return success(jio.getAttachment({"_id": "a", "_attachment": attachment});
// "_attachment": "ab", })
// "_start": 1, .then(function (result) {
// "_end": 0})); ok(result.data instanceof Blob, "Data is Blob");
// } return jIO.util.readBlobAsText(result.data);
// function getSecondAttachmentRangeTest2(answer) { })
// deepEqual(answer, { .then(function (result) {
// "attachment": "ab", equal(result.target.result, big_string,
// "error": "not_found", "Attachment correctly fetched");
// "id": "a", })
// "message": "start is great then end", .fail(function (error) {
// "method": "getAttachment", ok(false, error);
// "reason": "invalide offset", })
// "result": "error", .always(function () {
// "status": 404, start();
// "statusText": "Not Found" });
// }, "get attachment with _start > _end -> 404 Not Found"); });
// }
// function getSecondAttachmentRange3() { test("streaming", function () {
// return jio.getAttachment({"_id": "a", var context = this,
// "_attachment": "ab", attachment = "attachment";
// "_start": 1, stop();
// "_end": 2}); expect(2);
// }
// function getSecondAttachmentRangeTest3(answer) { deleteIndexedDB(context.jio)
// var blob = answer.data; .then(function () {
// answer.data = "<blob>"; return context.jio.put({"_id": "foo", "title": "bar"});
// return jIO.util.readBlobAsText(blob).then(function (e) { })
// deepEqual(blob.type, "text/plain", "Check blob type"); .then(function () {
// deepEqual(e.target.result, "b", "Check blob text content"); return context.jio.putAttachment({"_id": "foo",
// deepEqual(answer, { "_attachment": attachment,
// "attachment": "ab", "_data": big_string});
// "data": "<blob>", })
// "id": "a", .then(function () {
// "method": "getAttachment", return context.jio.getAttachment({"_id": "foo",
// "result": "success", "_attachment": attachment,
// "status": 200, "_start": 1999995, "_end": 2000005});
// "statusText": "Ok" })
// }, "Get second attachment with range :_start:1, _end:3"); .then(function (result) {
// }, function (err) { ok(result.data instanceof Blob, "Data is Blob");
// deepEqual(err, "no error", "Check blob text content"); return jIO.util.readBlobAsText(result.data);
// }); })
// } .then(function (result) {
// var expected = "aaaaaaaaaa";
// equal(result.target.result, expected, "Attachment correctly fetched");
// })
// function getLastDocument() { .fail(function (error) {
// return jio.get({"_id": "a"}); ok(false, error);
// } })
// .always(function () {
// function getLastDocumentTest(answer) { start();
// deepEqual(answer, { });
// "data": { });
// "_id": "a",
// "title": "Hoo", /////////////////////////////////////////////////////////////////
// "_attachment": { // indexeddbStorage.removeAttachment
// "aa": { /////////////////////////////////////////////////////////////////
// "content_type": "text/plain", module("indexeddbStorage.removeAttachment", {
// "length": 3 setup: function () {
// }, this.jio = jIO.createJIO({
// "ab": { type: "indexeddb",
// "content_type": "text/plain", database: "qunit"
// "length": 3 });
// } }
// } });
// },
// "id": "a", test("spy indexedDB usage", function () {
// "method": "get", var context = this,
// "result": "success", attachment = "attachment";
// "status": 200, stop();
// "statusText": "Ok" expect(15);
// }, "Get last document metadata");
// } deleteIndexedDB(context.jio)
// .then(function () {
// function removeSecondAttachment() { return context.jio.put({"_id": "foo", "title": "bar"});
// return jio.removeAttachment({"_id": "a", "_attachment": "ab"}); })
// } .then(function () {
// return context.jio.putAttachment({"_id": "foo",
// function removeSecondAttachmentTest(answer) { "_attachment": attachment,
// deepEqual(answer, { "_data": big_string});
// "attachment": "ab", })
// "id": "a", .then(function () {
// "method": "removeAttachment", context.spy_open = sinon.spy(indexedDB, "open");
// "result": "success", context.spy_create_store = sinon.spy(IDBDatabase.prototype,
// "status": 204, "createObjectStore");
// "statusText": "No Content" context.spy_transaction = sinon.spy(IDBDatabase.prototype,
// }, "Remove second document"); "transaction");
// } context.spy_store = sinon.spy(IDBTransaction.prototype,
// "objectStore");
// function getInexistentSecondAttachment() { context.spy_delete = sinon.spy(IDBObjectStore.prototype, "delete");
// return success(jio.getAttachment({"_id": "a", "_attachment": "ab"})); context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
// } context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
// "createIndex");
// function getInexistentSecondAttachmentTest(answer) { context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
// deepEqual(answer, { context.spy_cursor_delete = sinon.spy(IDBCursor.prototype, "delete");
// "attachment": "ab",
// "error": "not_found", return context.jio.removeAttachment({"_id": "foo",
// "id": "a", "_attachment": attachment});
// "message": "IndexeddbStorage, unable to get attachment.", })
// "method": "getAttachment", .then(function () {
// "reason": "missing attachment",
// "result": "error", ok(context.spy_open.calledOnce, "open count " +
// "status": 404, context.spy_open.callCount);
// "statusText": "Not Found" equal(context.spy_open.firstCall.args[0], "jio:qunit",
// }, "Get inexistent second attachment"); "open first argument");
// }
// equal(context.spy_create_store.callCount, 0,
// function getOneAttachmentDocument() { "createObjectStore count");
// return jio.get({"_id": "a"}); equal(context.spy_create_index.callCount, 0,
// } "createIndex count");
//
// function getOneAttachmentDocumentTest(answer) { ok(context.spy_transaction.calledOnce, "transaction count " +
// deepEqual(answer, { context.spy_transaction.callCount);
// "data": { deepEqual(context.spy_transaction.firstCall.args[0],
// "_attachment": { ["attachment", "blob"],
// "aa": { "transaction first argument");
// "content_type": "text/plain", equal(context.spy_transaction.firstCall.args[1], "readwrite",
// "length": 3 "transaction second argument");
// }
// }, equal(context.spy_store.callCount, 2, "store count " +
// "_id": "a", context.spy_store.callCount);
// "title": "Hoo" deepEqual(context.spy_store.firstCall.args[0], "attachment",
// }, "store first argument");
// "id": "a", deepEqual(context.spy_store.secondCall.args[0], "blob",
// "method": "get", "store first argument");
// "result": "success",
// "status": 200, equal(context.spy_delete.callCount, 1, "delete count " +
// "statusText": "Ok" context.spy_delete.callCount);
// }, "Get document metadata"); deepEqual(context.spy_delete.firstCall.args[0], "foo_attachment",
// } "delete first argument");
//
// function removeSecondAttachmentAgain() { ok(context.spy_index.calledOnce, "index count " +
// return success(jio.removeAttachment({"_id": "a", "_attachment": "ab"})); context.spy_index.callCount);
// }
// ok(context.spy_cursor.calledOnce, "cursor count " +
// function removeSecondAttachmentAgainTest(answer) { context.spy_cursor.callCount);
// deepEqual(answer, { equal(context.spy_cursor_delete.callCount, 2, "cursor count " +
// "attachment": "ab", context.spy_cursor_delete.callCount);
// "error": "not_found", })
// "id": "a", .always(function () {
// "message": "IndexeddbStorage, document attachment not found.", context.spy_open.restore();
// "method": "removeAttachment", delete context.spy_open;
// "reason": "missing attachment", context.spy_create_store.restore();
// "result": "error", delete context.spy_create_store;
// "status": 404, context.spy_transaction.restore();
// "statusText": "Not Found" delete context.spy_transaction;
// }, "Remove inexistent attachment"); context.spy_store.restore();
// } delete context.spy_store;
// context.spy_delete.restore();
// function removeDocument() { delete context.spy_delete;
// return jio.remove({"_id": "a"}); context.spy_index.restore();
// } delete context.spy_index;
// context.spy_create_index.restore();
// function removeDocumentTest(answer) { delete context.spy_create_index;
// deepEqual(answer, { context.spy_cursor.restore();
// "id": "a", delete context.spy_cursor;
// "method": "remove", context.spy_cursor_delete.restore();
// "result": "success", delete context.spy_cursor_delete;
// "status": 204, })
// "statusText": "No Content" .fail(function (error) {
// }, "Remove document and its attachments"); ok(false, error);
// } })
// .always(function () {
// function getInexistentFirstAttachment() { start();
// return success(jio.getAttachment({"_id": "a", "_attachment": "aa"})); });
// } });
//
// function getInexistentFirstAttachmentTest(answer) { /////////////////////////////////////////////////////////////////
// deepEqual(answer, { // indexeddbStorage.putAttachment
// "attachment": "aa", /////////////////////////////////////////////////////////////////
// "error": "not_found", module("indexeddbStorage.putAttachment", {
// "id": "a", setup: function () {
// "message": "IndexeddbStorage, unable to get attachment.", this.jio = jIO.createJIO({
// "method": "getAttachment", type: "indexeddb",
// "reason": "missing attachment", database: "qunit"
// "result": "error", });
// "status": 404, }
// "statusText": "Not Found" });
// }, "Get inexistent first attachment");
// } test("spy indexedDB usage", function () {
// var context = this,
// function getInexistentDocument() { attachment = "attachment";
// return success(jio.get({"_id": "a"})); stop();
// } expect(21);
//
// function getInexistentDocumentTest(answer) { deleteIndexedDB(context.jio)
// deepEqual(answer, { .then(function () {
// "error": "not_found", return context.jio.put({"_id": "foo", "title": "bar"});
// "id": "a", })
// "message": "IndexeddbStorage, unable to get document.", .then(function () {
// "method": "get", context.spy_open = sinon.spy(indexedDB, "open");
// "reason": "Not Found", context.spy_create_store = sinon.spy(IDBDatabase.prototype,
// "result": "error", "createObjectStore");
// "status": 404, context.spy_transaction = sinon.spy(IDBDatabase.prototype,
// "statusText": "Not Found" "transaction");
// }, "Get inexistent document"); context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
// } context.spy_delete = sinon.spy(IDBObjectStore.prototype, "delete");
// context.spy_put = sinon.spy(IDBObjectStore.prototype, "put");
// function removeInexistentDocument() { context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
// return success(jio.remove({"_id": "a"})); context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
// } "createIndex");
// context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
// function removeInexistentDocumentTest(answer) { context.spy_cursor_delete = sinon.spy(IDBCursor.prototype, "delete");
// deepEqual(answer, {
// "error": "not_found", return context.jio.putAttachment({"_id": "foo",
// "id": "a", "_attachment": attachment,
// "message": "IndexeddbStorage, unable to get metadata.", "_data": big_string});
// "method": "remove", })
// "reason": "Not Found", .then(function () {
// "result": "error",
// "status": 404, ok(context.spy_open.calledOnce, "open count " +
// "statusText": "Not Found" context.spy_open.callCount);
// }, "Remove already removed document"); equal(context.spy_open.firstCall.args[0], "jio:qunit",
// } "open first argument");
//
// function unexpectedError(error) { equal(context.spy_create_store.callCount, 0,
// if (error instanceof Error) { "createObjectStore count");
// deepEqual([ equal(context.spy_create_index.callCount, 0,
// error.name + ": " + error.message, "createIndex count");
// error
// ], "UNEXPECTED ERROR", "Unexpected error"); ok(context.spy_transaction.calledOnce, "transaction count " +
// } else { context.spy_transaction.callCount);
// deepEqual(error, "UNEXPECTED ERROR", "Unexpected error"); deepEqual(context.spy_transaction.firstCall.args[0],
// } ["attachment", "blob"],
// } "transaction first argument");
// equal(context.spy_transaction.firstCall.args[1], "readwrite",
// // # Post new documents, list them and remove them "transaction second argument");
// // post a 201
// postNewDocument().then(postNewDocumentTest). equal(context.spy_store.callCount, 4, "store count " +
// // get 200 context.spy_store.callCount);
// then(getCreatedDocument).then(getCreatedDocumentTest). deepEqual(context.spy_store.firstCall.args[0], "attachment",
// // post b 201 "store first argument");
// then(postSpecificDocument).then(postSpecificDocumentTest). deepEqual(context.spy_store.secondCall.args[0], "blob",
// // allD 200 2 documents "store first argument");
// then(listDocument).then(list2DocumentsTest). deepEqual(context.spy_store.thirdCall.args[0], "attachment",
// // allD+include_docs 200 2 documents "store first argument");
// then(listDocumentsWithMetadata).then(list2DocumentsWithMetadataTest). deepEqual(context.spy_store.getCall(3).args[0], "blob",
// // remove a 204 "store first argument");
// then(removeCreatedDocument).then(removeCreatedDocumentTest).
// // remove b 204 equal(context.spy_delete.callCount, 1, "delete count " +
// then(removeSpecificDocument).then(removeSpecificDocumentTest). context.spy_delete.callCount);
// // allD 200 empty storage deepEqual(context.spy_delete.firstCall.args[0], "foo_attachment",
// then(listEmptyStorage).then(listEmptyStorageTest). "delete first argument");
// // # Create and update documents, and some attachment and remove them
// // put 201 ok(context.spy_index.calledOnce, "index count " +
// then(putNewDocument).then(putNewDocumentTest). context.spy_index.callCount);
// // get 200
// then(getCreatedDocument2).then(getCreatedDocument2Test). ok(context.spy_cursor.calledOnce, "cursor count " +
// // post 409 context.spy_cursor.callCount);
// then(postSameDocument).then(postSameDocumentTest). equal(context.spy_cursor_delete.callCount, 0, "delete count " +
// // putA 404 context.spy_cursor_delete.callCount);
// then(putAttachmentToNonExistentDocument).
// then(putAttachmentToNonExistentDocumentTest). equal(context.spy_put.callCount, 3, "put count " +
// // putA a 204 context.spy_put.callCount);
// then(createAttachment).then(createAttachmentTest). deepEqual(context.spy_put.firstCall.args[0], {
// // putA a 204 "_attachment": "attachment",
// then(updateAttachment).then(updateAttachmentTest). "_id": "foo",
// // putA b 204 "_key_path": "foo_attachment",
// then(createAnotherAttachment).then(createAnotherAttachmentTest). "info": {
// // put 204 "content_type": "",
// then(updateLastDocument).then(updateLastDocumentTest). "length": 3000000
// // getA a 200 }
// then(getFirstAttachment).then(getFirstAttachmentTest). }, "put first argument");
// then(getFirstAttachmentRange1).then(getFirstAttachmentRangeTest1). delete context.spy_put.secondCall.args[0].blob;
// then(getFirstAttachmentRange2).then(getFirstAttachmentRangeTest2). // XXX Check blob content
// then(getFirstAttachmentRange3).then(getFirstAttachmentRangeTest3). deepEqual(context.spy_put.secondCall.args[0], {
// // getA b 200 "_attachment": "attachment",
// then(getSecondAttachment).then(getSecondAttachmentTest). "_id": "foo",
// then(getSecondAttachmentRange1).then(getSecondAttachmentRangeTest1). "_part": 0,
// then(getSecondAttachmentRange2).then(getSecondAttachmentRangeTest2). "_key_path": "foo_attachment_0"
// then(getSecondAttachmentRange3).then(getSecondAttachmentRangeTest3). }, "put first argument");
// // get 200 delete context.spy_put.thirdCall.args[0].blob;
// then(getLastDocument).then(getLastDocumentTest). // XXX Check blob content
// // removeA b 204 deepEqual(context.spy_put.thirdCall.args[0], {
// then(removeSecondAttachment).then(removeSecondAttachmentTest). "_attachment": "attachment",
// // getA b 404 "_id": "foo",
// then(getInexistentSecondAttachment). "_part": 1,
// then(getInexistentSecondAttachmentTest). "_key_path": "foo_attachment_1"
// // get 200 }, "put first argument");
// then(getOneAttachmentDocument).then(getOneAttachmentDocumentTest). })
// // removeA b 404 .always(function () {
// then(removeSecondAttachmentAgain).then(removeSecondAttachmentAgainTest). context.spy_open.restore();
// // remove 204 delete context.spy_open;
// then(removeDocument).then(removeDocumentTest). context.spy_create_store.restore();
// // getA a 404 delete context.spy_create_store;
// then(getInexistentFirstAttachment).then(getInexistentFirstAttachmentTest). context.spy_transaction.restore();
// // get 404 delete context.spy_transaction;
// then(getInexistentDocument).then(getInexistentDocumentTest). context.spy_store.restore();
// // remove 404 delete context.spy_store;
// then(removeInexistentDocument).then(removeInexistentDocumentTest). context.spy_delete.restore();
// // end delete context.spy_delete;
// fail(unexpectedError). context.spy_index.restore();
// always(start). delete context.spy_index;
// always(function () { context.spy_create_index.restore();
// server.restore(); delete context.spy_create_index;
// }); context.spy_cursor.restore();
// }); delete context.spy_cursor;
// })); context.spy_cursor_delete.restore();
delete context.spy_cursor_delete;
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
}(jIO, QUnit, indexedDB, Blob, sinon, IDBDatabase,
IDBTransaction, IDBIndex, IDBObjectStore, IDBCursor));
...@@ -10,6 +10,9 @@ ...@@ -10,6 +10,9 @@
<script src="../node_modules/grunt-contrib-qunit/test/libs/qunit.js" type="text/javascript"></script> <script src="../node_modules/grunt-contrib-qunit/test/libs/qunit.js" type="text/javascript"></script>
<script src="../node_modules/sinon/pkg/sinon.js" type="text/javascript"></script> <script src="../node_modules/sinon/pkg/sinon.js" type="text/javascript"></script>
<script>
QUnit.config.testTimeout = 5000;
</script>
<!--script src="html5.js"></script--> <!--script src="html5.js"></script-->
<!--script src="jio/util.js"></script--> <!--script src="jio/util.js"></script-->
<!--script src="jio/fakestorage.js"></script> <!--script src="jio/fakestorage.js"></script>
...@@ -33,8 +36,8 @@ ...@@ -33,8 +36,8 @@
<script src="jio.storage/drivetojiomapping.tests.js"></script> <script src="jio.storage/drivetojiomapping.tests.js"></script>
<script src="jio.storage/unionstorage.tests.js"></script> <script src="jio.storage/unionstorage.tests.js"></script>
<script src="jio.storage/erp5storage.tests.js"></script> <script src="jio.storage/erp5storage.tests.js"></script>
<script src="jio.storage/indexeddbstorage.tests.js"></script>
<!--script src="jio.storage/indexeddbstorage.tests.js"></script-->
<!--script src="jio.storage/indexstorage.tests.js"></script--> <!--script src="jio.storage/indexstorage.tests.js"></script-->
<!--script src="jio.storage/dropboxstorage.tests.js"></script--> <!--script src="jio.storage/dropboxstorage.tests.js"></script-->
......
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