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