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", { store = db.createObjectStore("attachment", {
"keyPath": "_id" keyPath: "_key_path",
//"autoIncrement": true autoIncrement: false
}); });
store.createIndex("_id", "_id"); store.createIndex("_id", "_id", {unique: false});
store = db.createObjectStore("blob", { store = db.createObjectStore("blob", {
"keyPath": ["_id", "_attachment", "_part"] keyPath: "_key_path",
//"autoIncrement": true autoIncrement: false
}); });
store.createIndex("_id_attachment_part", store.createIndex("_id_attachment",
["_id", "_attachment", "_part"]); ["_id", "_attachment"], {unique: false});
}; store.createIndex("_id", "_id", {unique: false});
request.onsuccess = function () {
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);
resolver = function (resolve, reject) {
request.onerror = function (e) {
reject(e);
};
request.onsuccess = function () {
resolve(metadata);
};
};
return new RSVP.Promise(resolver);
} }
reject(error);
function putIndexedDB(store, metadata, readData) {
var request,
resolver;
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.onabort = function () {
var resolver; request.result.close();
resolver = function (resolve, reject) { reject("Aborting connection to: " + db_name);
transaction.onabort = reject;
transaction.oncomplete = function () {
resolve("end");
}; };
request.ontimeout = function () {
request.result.close();
reject("Connection to: " + db_name + " timeout");
}; };
return new RSVP.Promise(resolver);
} request.onblocked = function () {
/** request.result.close();
* get a data from a store object reject("Connection to: " + db_name + " was blocked");
* @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);
}; };
} }
// XXX Canceller???
return new RSVP.Queue()
.push(function () {
return new RSVP.Promise(resolver); 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 promiseResearch(transaction, id, table, researchID) { function resolver(resolve, reject) {
var store = transaction.objectStore(table); // Open DB //
return researchIndexedDB(store, id, researchID); request.onerror = function (error) {
if (request.transaction) {
request.transaction.abort();
} }
reject(error);
};
/** request.onsuccess = function (evt) {
* put or post a metadata into objectstore:metadata,attachment var cursor = evt.target.result;
* @param {function} open The function to open a basedata if (cursor) {
* @param {function} research The function to reserach // XXX Wait for result
* @param {function} ongoing The function to process try {
* @param {function} end The completed function callback(cursor);
* @param {Object} metadata The data to put } catch (error) {
*/ reject(error);
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 () { // continue to next iteration
return transactionEnd(transaction); cursor["continue"]();
}) } else {
.push(function () { resolve();
return end(result);
})
.push(undefined, function (error) {
if (global_db !== undefined) {
global_db.close();
} }
throw error;
});
}; };
/**
* Retrieve data
*
*@param {Object} param The command parameters
*/
IndexedDBStorage.prototype.get = function (param) {
var jio_storage = this,
transaction,
global_db,
meta;
return new RSVP.Queue()
.push(function () {
return openIndexedDB(jio_storage._database_name);
})
.push(function (db) {
global_db = db;
transaction = db.transaction(["metadata", "attachment"], "readonly");
var store = transaction.objectStore("metadata");
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); // XXX Canceller???
}) return new RSVP.Promise(resolver);
.push(function () {
return meta;
})
.push(undefined, function (error) {
if (global_db !== undefined) {
global_db.close();
} }
throw error;
});
};
IndexedDBStorage.prototype.buildQuery = function () {
var result_list = [];
/** function pushMetadata(cursor) {
* Remove a document result_list.push({
* "id": cursor.key,
* @param {Object} param The command parameters "value": {}
*/
IndexedDBStorage.prototype.remove = function (param) {
var jio_storage = this,
transaction,
global_db,
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) {
var totalLength = allAttachment[array[index]].length;
return removeAllPart(store, array[index], 0, totalLength)
.then(function () {
if (index < array.length - 1) {
return removeAll(store, array, index + 1, allAttachment);
}
}); });
} }
return queue.push(function () { return openIndexedDB(this)
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", return handleCursor(tx.objectStore("metadata").index("_id")
"attachment", "blob"], "readwrite"); .openKeyCursor(), pushMetadata);
return promiseResearch(transaction, param._id, "metadata", "_id");
})
.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 () { .push(function () {
var store = transaction.objectStore("attachment"); return result_list;
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) {
if (global_db !== undefined) {
global_db.close();
}
throw error;
}); });
};
};
/** function handleGet(request) {
* Creates a new document if not already existes function resolver(resolve, reject) {
* @param {Object} metadata The metadata to put request.onerror = reject;
*/ request.onsuccess = function () {
IndexedDBStorage.prototype.post = function (metadata) { if (request.result) {
var that = this; resolve(request.result);
if (!metadata._id) {
metadata._id = generateUuid();
} }
function promiseOngoingPost(researchResult) { // XXX How to get ID
if (researchResult.result === undefined) { reject(new jIO.util.jIOError("Cannot find document", 404));
delete metadata._attachment; };
return putIndexedDB(researchResult.store, metadata);
} }
throw ({"status": 409, "reason": "Document exists"}); return new RSVP.Promise(resolver);
} }
function promiseEndPost(metadata) { IndexedDBStorage.prototype.get = function (param) {
return metadata._id; var attachment_dict = {};
function addEntry(cursor) {
attachment_dict[cursor.value._attachment] = {};
} }
return that._putOrPost(openIndexedDB, promiseResearch, return openIndexedDB(this)
promiseOngoingPost, promiseEndPost, .push(function (db) {
metadata); var transaction = openTransaction(db, ["metadata", "attachment"],
"readonly");
return RSVP.all([
handleGet(transaction.objectStore("metadata").get(param._id)),
handleCursor(transaction.objectStore("attachment").index("_id")
.openCursor(), addEntry)
]);
})
.push(function (result_list) {
var result = result_list[0];
if (Object.getOwnPropertyNames(attachment_dict).length > 0) {
result._attachments = attachment_dict;
}
return result;
});
};
function handleRequest(request) {
function resolver(resolve, reject) {
request.onerror = reject;
request.onsuccess = function () {
resolve(request.result);
}; };
/**
* Creates or updates a document
* @param {Object} metadata The metadata to post
*/
IndexedDBStorage.prototype.put = function (metadata) {
var that = this;
function promiseOngoingPut(researchResult) {
var key;
for (key in metadata) {
if (metadata.hasOwnProperty(key)) {
metadata[key] = metadataObjectToString(metadata[key]);
}
} }
delete metadata._attachment; return new RSVP.Promise(resolver);
return putIndexedDB(researchResult.store, metadata);
} }
function promiseEndPut() { IndexedDBStorage.prototype.put = function (metadata) {
return metadata._id; return openIndexedDB(this)
} .push(function (db) {
return that._putOrPost(openIndexedDB, promiseResearch, var transaction = openTransaction(db, ["metadata"], "readwrite");
promiseOngoingPut, promiseEndPut, return handleRequest(transaction.objectStore("metadata").put(metadata));
metadata); });
}; };
function deleteEntry(cursor) {
cursor["delete"]();
/**
* Add an attachment to a document
*
* @param {Object} metadata The data
*
*/
IndexedDBStorage.prototype.putAttachment = function (metadata) {
var jio_storage = this,
transaction,
global_db,
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); IndexedDBStorage.prototype.remove = function (param) {
readPart = readResult.slice(count, end); return openIndexedDB(this)
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) { .push(function (db) {
global_db = db; var transaction = openTransaction(db, ["metadata", "attachment",
transaction = db.transaction(["attachment",
"blob"], "readwrite"); "blob"], "readwrite");
return promiseResearch(transaction, return RSVP.all([
metadata._id, "attachment", "_id"); handleRequest(transaction
}) .objectStore("metadata")["delete"](param._id)),
.push(function (researchResult) { // XXX Why not possible to delete with KeyCursor?
if (researchResult.result === undefined) { handleCursor(transaction.objectStore("attachment").index("_id")
throw new jIO.util.jIOError("IndexeddbStorage unable to put attachment.", 500); .openCursor(), deleteEntry),
} handleCursor(transaction.objectStore("blob").index("_id")
//update attachment .openCursor(), deleteEntry)
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,
global_db,
blob,
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) {
global_db = db;
transaction = db.transaction(["attachment", "blob"], "readwrite");
//check if the attachment exists
return promiseResearch(transaction,
param._id, "attachment", "_id");
})
.push(function (researchResult) {
var result = researchResult.result,
start, start,
end; end;
if (result === undefined || return openIndexedDB(this)
result._attachment[param._attachment] === undefined) { .push(function (db) {
throw new jIO.util.jIOError("IndexeddbStorage unable to get attachment.", 404); transaction = openTransaction(db, ["attachment", "blob"], "readonly");
} // XXX Should raise if key is not good
totalLength = result._attachment[param._attachment].length; return handleGet(transaction.objectStore("attachment")
param._start = param._start === undefined ? 0 : param._start; .get(buildKeyPath([param._id, param._attachment])));
param._end = param._end === undefined ? totalLength
: param._end;
if (param._end > totalLength) {
param._end = totalLength;
}
if (param._start < 0 || param._end < 0) {
throw ({"status": 404, "reason": "invalide _start, _end",
"message": "_start and _end must be positive"});
}
if (param._start > param._end) {
throw ({"status": 404, "reason": "invalide offset",
"message": "start is great then end"});
}
start = Math.floor(param._start / jio_storage._unite);
end = Math.floor(param._end / jio_storage._unite);
if (param._end % jio_storage._unite === 0) {
end -= 1;
}
return getDesirePart(transaction.objectStore("blob"),
start,
end);
})
.push(function () {
var start = param._start % jio_storage._unite,
end = start + param._end - param._start;
blob = blob.slice(start, end);
return new Blob([blob], {type: "text/plain"});
}) })
.push(undefined, function (error) { .push(function (attachment) {
// Check if transaction is ongoing, if so, abort it var total_length = attachment.info.length,
if (transaction !== undefined) { i,
transaction.abort(); promise_list = [],
store = transaction.objectStore("blob"),
start_index,
end_index;
start = param._start || 0;
end = param._end || total_length;
if (end > total_length) {
end = total_length;
} }
if (global_db !== undefined) {
global_db.close(); if (start < 0 || end < 0) {
throw new jIO.util.jIOError("_start and _end must be positive",
400);
}
if (start > end) {
throw new jIO.util.jIOError("_start is greater than _end",
400);
} }
throw error;
});
};
start_index = Math.floor(start / UNITE);
end_index = Math.floor(end / UNITE);
if (end % UNITE === 0) {
end_index -= 1;
}
/** for (i = start_index; i <= end_index; i += 1) {
* Remove an attachment promise_list.push(
* handleGet(store.get(buildKeyPath([param._id,
* @method removeAttachment param._attachment, i])))
* @param {Object} param The command parameters );
*/
IndexedDBStorage.prototype.removeAttachment = function (param) {
var jio_storage = this,
transaction,
global_db,
totalLength;
function removePart(store, part) {
if (part * jio_storage._unite >= totalLength) {
return;
}
return removeIndexedDB(store, [param._id, param._attachment, part])
.then(function () {
return removePart(store, part + 1);
});
} }
return new RSVP.Queue() return RSVP.all(promise_list);
.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) {
var result = researchResult.result;
if (result === undefined ||
result._attachment[param._attachment] === undefined) {
throw ({"status": 404, "reason": "missing attachment",
"message":
"IndexeddbStorage, document attachment not found."});
}
totalLength = result._attachment[param._attachment].length;
//updata attachment
delete result._attachment[param._attachment];
return putIndexedDB(researchResult.store, result);
}) })
.push(function () { .push(function (result_list) {
var store = transaction.objectStore("blob"); var array_buffer_list = [],
return removePart(store, 0); blob,
}) i,
.push(function () { len = result_list.length;
return transactionEnd(transaction); for (i = 0; i < len; i += 1) {
}) array_buffer_list.push(result_list[i].blob);
.push(undefined, function (error) {
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.hasCapacity = function (name) { IndexedDBStorage.prototype.putAttachment = function (metadata) {
return (name === "list"); var blob_part = [],
}; transaction,
db;
IndexedDBStorage.prototype.buildQuery = function () { return openIndexedDB(this)
var jio_storage = this, .push(function (database) {
global_db; db = database;
return new RSVP.Queue() // Split the blob first
.push(function () { return jIO.util.readBlobAsArrayBuffer(metadata._blob);
return openIndexedDB(jio_storage._database_name);
}) })
.push(function (db) { .push(function (event) {
global_db = db; var array_buffer = event.target.result,
total_size = metadata._blob.size,
var onCancel; handled_size = 0;
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 while (handled_size < total_size) {
cursor["continue"](); blob_part.push(array_buffer.slice(handled_size,
} else { handled_size + UNITE));
db.close(); handled_size += UNITE;
resolve(rows);
} }
};
} catch (e) { // Remove previous attachment
reject(e); transaction = openTransaction(db, ["attachment", "blob"], "readwrite");
db.close(); return removeAttachment(transaction, metadata);
})
.push(function () {
var promise_list = [
handleRequest(transaction.objectStore("attachment").put({
"_key_path": buildKeyPath([metadata._id, metadata._attachment]),
"_id": metadata._id,
"_attachment": metadata._attachment,
"info": {
"content_type": metadata._blob.type,
"length": metadata._blob.size
} }
}; }))
}, function () { ],
if (typeof onCancel === "function") { len = blob_part.length,
onCancel(); 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]
}))
);
} }
// Store all new data
return RSVP.all(promise_list);
}); });
};
IndexedDBStorage.prototype.removeAttachment = function (param) {
}) return openIndexedDB(this)
.push(undefined, function (error) { .push(function (db) {
if (global_db !== undefined) { var transaction = openTransaction(db, ["attachment", "blob"],
global_db.close(); "readwrite");
} return removeAttachment(transaction, param);
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"
// });
indexedDB = { deleteIndexedDB(context.jio)
open: function () { .then(function () {
var result = { return context.jio.put({"_id": id, "title": "bar"});
result: "taboulet" })
}; .then(function () {
RSVP.delay().then(function () { return context.jio.get({"_id": id});
result.onsuccess(); })
.then(function (result) {
deepEqual(result, {
"_id": "/",
"title": "bar"
}, "Check document");
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
}); });
return result;
}
// return RSVP.success("taboulet");
};
mock = sinon.mock(indexedDB);
// mock = sinon.mock(indexedDB.open, "open", function () {
// 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 */ module("indexeddbStorage.put", {
// /*global module, test, stop, start, expect, ok, deepEqual, location, sinon, setup: function () {
// davstorage_spec, RSVP, jIO, test_util, dav_storage, btoa, define, this.jio = jIO.createJIO({
// setTimeout, clearTimeout, indexedDB */ type: "indexeddb",
// database: "qunit"
// // define([module_name], [dependencies], module); });
// (function (dependencies, module) { }
// "use strict"; });
// if (typeof define === 'function' && define.amd) {
// return define(dependencies, module); test("spy indexedDB usage", function () {
// } var context = this;
// module(test_util, RSVP, jIO); stop();
// }([ expect(31);
// 'test_util',
// 'rsvp', deleteIndexedDB(context.jio)
// 'jio', .then(function () {
// 'indexeddbstorage', context.spy_open = sinon.spy(indexedDB, "open");
// 'qunit' context.spy_create_store = sinon.spy(IDBDatabase.prototype,
// ], function (util, RSVP, jIO) { "createObjectStore");
// "use strict"; context.spy_transaction = sinon.spy(IDBDatabase.prototype,
// module("indexeddbStorage"); "transaction");
// function success(promise) { context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
// return new RSVP.Promise(function (resolve, notify) { context.spy_put = sinon.spy(IDBObjectStore.prototype, "put");
// promise.then(resolve, resolve, notify); context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
// }, function () { context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
// promise.cancel(); "createIndex");
// }); context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
// }
// return context.jio.put({"_id": "foo", "title": "bar"});
// test("Scenario", 46, function () { })
// indexedDB.deleteDatabase("jio:test"); .then(function () {
// var server, shared = {}, jio = jIO.createJIO(
// {"type" : "indexeddb", ok(context.spy_open.calledOnce, "open count " +
// "database" : "test" context.spy_open.callCount);
// }, equal(context.spy_open.firstCall.args[0], "jio:qunit",
// {"workspace": {}} "open first argument");
// );
// stop(); equal(context.spy_create_store.callCount, 3,
// server = {restore: function () { "createObjectStore count");
// return;
// }}; equal(context.spy_create_store.firstCall.args[0], "metadata",
// "first createObjectStore first argument");
// function postNewDocument() { deepEqual(context.spy_create_store.firstCall.args[1],
// return jio.post({"title": "Unique ID"}); {keyPath: "_id", autoIncrement: false},
// } "first createObjectStore second argument");
//
// function postNewDocumentTest(answer) { equal(context.spy_create_store.secondCall.args[0], "attachment",
// var uuid = answer.id; "second createObjectStore first argument");
// answer.id = "<uuid>"; deepEqual(context.spy_create_store.secondCall.args[1],
// deepEqual(answer, { {keyPath: "_key_path", autoIncrement: false},
// "id": "<uuid>", "second createObjectStore second argument");
// "method": "post",
// "result": "success", equal(context.spy_create_store.thirdCall.args[0], "blob",
// "status": 201, "third createObjectStore first argument");
// "statusText": "Created" deepEqual(context.spy_create_store.thirdCall.args[1],
// }, "Post a new document"); {keyPath: "_key_path", autoIncrement: false},
// ok(util.isUuid(uuid), "New document id should look like " + "third createObjectStore second argument");
// "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + uuid);
// shared.created_document_id = uuid; equal(context.spy_create_index.callCount, 4, "createIndex count");
// }
// equal(context.spy_create_index.firstCall.args[0], "_id",
// function getCreatedDocument() { "first createIndex first argument");
// return jio.get({"_id": shared.created_document_id}); equal(context.spy_create_index.firstCall.args[1], "_id",
// } "first createIndex second argument");
// deepEqual(context.spy_create_index.firstCall.args[2], {unique: true},
// function getCreatedDocumentTest(answer) { "first createIndex third argument");
// deepEqual(answer, {
// "data": { equal(context.spy_create_index.secondCall.args[0], "_id",
// "_id": shared.created_document_id, "second createIndex first argument");
// "title": "Unique ID" equal(context.spy_create_index.secondCall.args[1], "_id",
// }, "second createIndex second argument");
// "id": shared.created_document_id, deepEqual(context.spy_create_index.secondCall.args[2],
// "method": "get", {unique: false},
// "result": "success", "second createIndex third argument");
// "status": 200,
// "statusText": "Ok" equal(context.spy_create_index.thirdCall.args[0], "_id_attachment",
// }, "Get new document"); "third createIndex first argument");
// } deepEqual(context.spy_create_index.thirdCall.args[1],
// ["_id", "_attachment"],
// function postSpecificDocument() { "third createIndex second argument");
// return jio.post({"_id": "b", "title": "Bee"}); deepEqual(context.spy_create_index.thirdCall.args[2], {unique: false},
// } "third createIndex third argument");
//
// function postSpecificDocumentTest(answer) { equal(context.spy_create_index.getCall(3).args[0], "_id",
// deepEqual(answer, { "fourth createIndex first argument");
// "id": "b", equal(context.spy_create_index.getCall(3).args[1], "_id",
// "method": "post", "fourth createIndex second argument");
// "result": "success", deepEqual(context.spy_create_index.getCall(3).args[2], {unique: false},
// "status": 201, "fourth createIndex third argument");
// "statusText": "Created"
// }, "Post specific document"); ok(context.spy_transaction.calledOnce, "transaction count " +
// } context.spy_transaction.callCount);
// deepEqual(context.spy_transaction.firstCall.args[0], ["metadata"],
// function listDocument() { "transaction first argument");
// return jio.allDocs(); equal(context.spy_transaction.firstCall.args[1], "readwrite",
// } "transaction second argument");
//
// function list2DocumentsTest(answer) { ok(context.spy_store.calledOnce, "store count " +
// if (answer && answer.data && Array.isArray(answer.data.rows)) { context.spy_store.callCount);
// answer.data.rows.sort(function (a) { deepEqual(context.spy_store.firstCall.args[0], "metadata",
// return a.id === "b" ? 1 : 0; "store first argument");
// });
// } ok(context.spy_put.calledOnce, "put count " +
// deepEqual(answer, { context.spy_put.callCount);
// "data": { deepEqual(context.spy_put.firstCall.args[0],
// "total_rows": 2, {"_id": "foo", title: "bar"},
// "rows": [{ "put first argument");
// "id": shared.created_document_id,
// "value": {} ok(!context.spy_index.called, "index count " +
// }, { context.spy_index.callCount);
// "id": "b",
// "value": {} ok(!context.spy_cursor.called, "cursor count " +
// }] context.spy_cursor.callCount);
// },
// "method": "allDocs", })
// "result": "success", .always(function () {
// "status": 200, context.spy_open.restore();
// "statusText": "Ok" delete context.spy_open;
// }, "List 2 documents"); context.spy_create_store.restore();
// } delete context.spy_create_store;
// context.spy_transaction.restore();
// function listDocumentsWithMetadata() { delete context.spy_transaction;
// return jio.allDocs({"include_docs": true}); context.spy_store.restore();
// } delete context.spy_store;
// context.spy_put.restore();
// function list2DocumentsWithMetadataTest(answer) { delete context.spy_put;
// if (answer && answer.data && Array.isArray(answer.data.rows)) { context.spy_index.restore();
// answer.data.rows.sort(function (a) { delete context.spy_index;
// return a.id === "b" ? 1 : 0; context.spy_create_index.restore();
// }); delete context.spy_create_index;
// } context.spy_cursor.restore();
// deepEqual(answer, { delete context.spy_cursor;
// "data": { })
// "total_rows": 2, .fail(function (error) {
// "rows": [{ ok(false, error);
// "id": shared.created_document_id, })
// "value": {}, .always(function () {
// "doc": { start();
// "_id": shared.created_document_id, });
// "title": "Unique ID" });
// }
// }, { test("put document", function () {
// "id": "b", var context = this;
// "value": {}, stop();
// "doc": { expect(1);
// "_id": "b",
// "title": "Bee" deleteIndexedDB(context.jio)
// } .then(function () {
// }] return context.jio.put({"_id": "inexistent"});
// }, })
// "method": "allDocs", .then(function (result) {
// "result": "success", equal(result, "inexistent");
// "status": 200, })
// "statusText": "Ok" .fail(function (error) {
// }, "List 2 documents with their metadata"); ok(false, error);
// } })
// .always(function () {
// function removeCreatedDocument() { start();
// return jio.remove({"_id": shared.created_document_id}); });
// } });
//
// function removeCreatedDocumentTest(answer) { /////////////////////////////////////////////////////////////////
// deepEqual(answer, { // indexeddbStorage.remove
// "id": shared.created_document_id, /////////////////////////////////////////////////////////////////
// "method": "remove", module("indexeddbStorage.remove", {
// "result": "success", setup: function () {
// "status": 204, this.jio = jIO.createJIO({
// "statusText": "No Content" type: "indexeddb",
// }, "Remove first document."); database: "qunit"
// } });
// }
// function removeSpecificDocument() { });
// return jio.remove({"_id": "b"});
// } test("spy indexedDB usage with one document", function () {
// var context = this;
// function removeSpecificDocumentTest(answer) { stop();
// deepEqual(answer, { expect(18);
// "id": "b",
// "method": "remove", deleteIndexedDB(context.jio)
// "result": "success", .then(function () {
// "status": 204, return context.jio.put({"_id": "foo", "title": "bar"});
// "statusText": "No Content" })
// }, "Remove second document."); .then(function () {
// } context.spy_open = sinon.spy(indexedDB, "open");
// context.spy_create_store = sinon.spy(IDBDatabase.prototype,
// function listEmptyStorage() { "createObjectStore");
// return jio.allDocs(); context.spy_transaction = sinon.spy(IDBDatabase.prototype,
// } "transaction");
// context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
// function listEmptyStorageTest(answer) { context.spy_delete = sinon.spy(IDBObjectStore.prototype, "delete");
// deepEqual(answer, { context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
// "data": { context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
// "total_rows": 0, "createIndex");
// "rows": [] context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
// }, context.spy_cursor_delete = sinon.spy(IDBCursor.prototype, "delete");
// "method": "allDocs",
// "result": "success", return context.jio.remove({"_id": "foo"});
// "status": 200, })
// "statusText": "Ok" .then(function () {
// }, "List empty storage");
// } ok(context.spy_open.calledOnce, "open count " +
// context.spy_open.callCount);
// function putNewDocument() { equal(context.spy_open.firstCall.args[0], "jio:qunit",
// return jio.put({"_id": "a", "title": "Hey"}); "open first argument");
// }
// equal(context.spy_create_store.callCount, 0,
// function putNewDocumentTest(answer) { "createObjectStore count");
// deepEqual(answer, { equal(context.spy_create_index.callCount, 0, "createIndex count");
// "id": "a",
// "method": "put", ok(context.spy_transaction.calledOnce, "transaction count " +
// "result": "success", context.spy_transaction.callCount);
// "status": 201, deepEqual(context.spy_transaction.firstCall.args[0],
// "statusText": "Created" ["metadata", "attachment", "blob"],
// }, "Put new document"); "transaction first argument");
// } equal(context.spy_transaction.firstCall.args[1], "readwrite",
// "transaction second argument");
// function getCreatedDocument2() {
// return jio.get({"_id": "a"}); equal(context.spy_store.callCount, 3, "store count " +
// } context.spy_store.callCount);
// deepEqual(context.spy_store.firstCall.args[0], "metadata",
// function getCreatedDocument2Test(answer) { "store first argument");
// deepEqual(answer, { deepEqual(context.spy_store.secondCall.args[0], "attachment",
// "data": { "store first argument");
// "_id": "a", deepEqual(context.spy_store.thirdCall.args[0], "blob",
// "title": "Hey" "store first argument");
// },
// "id": "a", ok(context.spy_delete.calledOnce, "delete count " +
// "method": "get", context.spy_delete.callCount);
// "result": "success", deepEqual(context.spy_delete.firstCall.args[0], "foo",
// "status": 200, "delete first argument");
// "statusText": "Ok"
// }, "Get new document"); ok(context.spy_index.calledTwice, "index count " +
// } context.spy_index.callCount);
// deepEqual(context.spy_index.firstCall.args[0], "_id",
// function postSameDocument() { "index first argument");
// return success(jio.post({"_id": "a", "title": "Hoo"})); deepEqual(context.spy_index.secondCall.args[0], "_id",
// } "index first argument");
//
// function postSameDocumentTest(answer) { ok(context.spy_cursor.calledTwice, "cursor count " +
// deepEqual(answer, { context.spy_cursor.callCount);
// "error": "conflict", equal(context.spy_cursor_delete.callCount, 0, "cursor count " +
// "id": "a", context.spy_cursor_delete.callCount);
// "message": "Command failed",
// "method": "post", })
// "reason": "Document exists", .always(function () {
// "result": "error", context.spy_open.restore();
// "status": 409, delete context.spy_open;
// "statusText": "Conflict" context.spy_create_store.restore();
// }, "Unable to post the same document (conflict)"); delete context.spy_create_store;
// } context.spy_transaction.restore();
// delete context.spy_transaction;
// function putAttachmentToNonExistentDocument() { context.spy_store.restore();
// return success(jio.putAttachment({ delete context.spy_store;
// "_id": "ahaha", context.spy_delete.restore();
// "_attachment": "aa", delete context.spy_delete;
// "_data": "aaa", context.spy_index.restore();
// "_content_type": "text/plain" delete context.spy_index;
// })); context.spy_create_index.restore();
// } delete context.spy_create_index;
// context.spy_cursor.restore();
// function putAttachmentToNonExistentDocumentTest(answer) { delete context.spy_cursor;
// deepEqual(answer, { context.spy_cursor_delete.restore();
// "attachment": "aa", delete context.spy_cursor_delete;
// "error": "not_found", })
// "id": "ahaha", .fail(function (error) {
// "message": "indexeddbStorage unable to put attachment", ok(false, error);
// "method": "putAttachment", })
// "reason": "Not Found", .always(function () {
// "result": "error", start();
// "status": 404, });
// "statusText": "Not Found" });
// }, "Put attachment to a non existent document -> 404 Not Found");
// } test("spy indexedDB usage with 2 attachments", function () {
// var context = this;
// function createAttachment() { stop();
// return jio.putAttachment({ expect(18);
// "_id": "a",
// "_attachment": "aa", deleteIndexedDB(context.jio)
// "_data": "aaa", .then(function () {
// "_content_type": "text/plain" return context.jio.put({"_id": "foo", "title": "bar"});
// }); })
// } .then(function () {
// return RSVP.all([
// function createAttachmentTest(answer) { context.jio.putAttachment({"_id": "foo",
// deepEqual(answer, { "_attachment": "attachment1",
// "attachment": "aa", "_data": "bar"}),
// "id": "a", context.jio.putAttachment({"_id": "foo",
// "method": "putAttachment", "_attachment": "attachment2",
// "result": "success", "_data": "bar2"})
// "status": 204, ]);
// "statusText": "No Content" })
// }, "Create new attachment"); .then(function () {
// } context.spy_open = sinon.spy(indexedDB, "open");
// context.spy_create_store = sinon.spy(IDBDatabase.prototype,
// function updateAttachment() { "createObjectStore");
// return jio.putAttachment({ context.spy_transaction = sinon.spy(IDBDatabase.prototype,
// "_id": "a", "transaction");
// "_attachment": "aa", context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
// "_data": "aab", context.spy_delete = sinon.spy(IDBObjectStore.prototype, "delete");
// "_content_type": "text/plain" 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");
// function updateAttachmentTest(answer) { context.spy_cursor_delete = sinon.spy(IDBCursor.prototype, "delete");
// deepEqual(answer, {
// "attachment": "aa", return context.jio.remove({"_id": "foo"});
// "id": "a", })
// "method": "putAttachment", .then(function () {
// "result": "success",
// "status": 204, ok(context.spy_open.calledOnce, "open count " +
// "statusText": "No Content" context.spy_open.callCount);
// }, "Update last attachment"); equal(context.spy_open.firstCall.args[0], "jio:qunit",
// } "open first argument");
//
// function createAnotherAttachment() { equal(context.spy_create_store.callCount, 0, "createObjectStore count");
// return jio.putAttachment({ equal(context.spy_create_index.callCount, 0, "createIndex count");
// "_id": "a",
// "_attachment": "ab", ok(context.spy_transaction.calledOnce, "transaction count " +
// "_data": "aba", context.spy_transaction.callCount);
// "_content_type": "text/plain" deepEqual(context.spy_transaction.firstCall.args[0],
// }); ["metadata", "attachment", "blob"],
// } "transaction first argument");
// equal(context.spy_transaction.firstCall.args[1], "readwrite",
// function createAnotherAttachmentTest(answer) { "transaction second argument");
// deepEqual(answer, {
// "attachment": "ab", equal(context.spy_store.callCount, 3, "store count " +
// "id": "a", context.spy_store.callCount);
// "method": "putAttachment", deepEqual(context.spy_store.firstCall.args[0], "metadata",
// "result": "success", "store first argument");
// "status": 204, deepEqual(context.spy_store.secondCall.args[0], "attachment",
// "statusText": "No Content" "store first argument");
// }, "Create another attachment"); deepEqual(context.spy_store.thirdCall.args[0], "blob",
// } "store first argument");
//
// equal(context.spy_delete.callCount, 1, "delete count " +
// function updateLastDocument() { context.spy_delete.callCount);
// return jio.put({"_id": "a", "title": "Hoo"}); deepEqual(context.spy_delete.firstCall.args[0], "foo",
// } "delete first argument");
//
// function updateLastDocumentTest(answer) { ok(context.spy_index.calledTwice, "index count " +
// deepEqual(answer, { context.spy_index.callCount);
// "id": "a", deepEqual(context.spy_index.firstCall.args[0], "_id",
// "method": "put", "index first argument");
// "result": "success", deepEqual(context.spy_index.secondCall.args[0], "_id",
// "status": 204, "index first argument");
// "statusText": "No Content"
// }, "Update document metadata"); ok(context.spy_cursor.calledTwice, "cursor count " +
// } context.spy_cursor.callCount);
//
// function getFirstAttachment() { equal(context.spy_cursor_delete.callCount, 3, "cursor count " +
// return jio.getAttachment({"_id": "a", "_attachment": "aa"}); context.spy_cursor_delete.callCount);
// }
// })
// function getFirstAttachmentTest(answer) { .always(function () {
// var blob = answer.data; context.spy_open.restore();
// answer.data = "<blob>"; delete context.spy_open;
// return jIO.util.readBlobAsText(blob).then(function (e) { context.spy_create_store.restore();
// deepEqual(blob.type, "text/plain", "Check blob type"); delete context.spy_create_store;
// deepEqual(e.target.result, "aab", "Check blob text content"); context.spy_transaction.restore();
// deepEqual(answer, { delete context.spy_transaction;
// "attachment": "aa", context.spy_store.restore();
// "data": "<blob>", delete context.spy_store;
// "id": "a", context.spy_delete.restore();
// "method": "getAttachment", delete context.spy_delete;
// "result": "success", context.spy_index.restore();
// "status": 200, delete context.spy_index;
// "statusText": "Ok" context.spy_create_index.restore();
// }, "Get first attachment"); delete context.spy_create_index;
// }, function (err) { context.spy_cursor.restore();
// deepEqual(err, "no error", "Check blob text content"); delete context.spy_cursor;
// }); context.spy_cursor_delete.restore();
// } delete context.spy_cursor_delete;
// })
// function getFirstAttachmentRange1() { .fail(function (error) {
// return jio.getAttachment({"_id": "a", ok(false, error);
// "_attachment": "aa", })
// "_start": 0}); .always(function () {
// } start();
// });
// function getFirstAttachmentRangeTest1(answer) { });
// var blob = answer.data;
// answer.data = "<blob>"; /////////////////////////////////////////////////////////////////
// return jIO.util.readBlobAsText(blob).then(function (e) { // indexeddbStorage.getAttachment
// deepEqual(blob.type, "text/plain", "Check blob type"); /////////////////////////////////////////////////////////////////
// deepEqual(e.target.result, "aab", "Check blob text content"); module("indexeddbStorage.getAttachment", {
// deepEqual(answer, { setup: function () {
// "attachment": "aa", this.jio = jIO.createJIO({
// "data": "<blob>", type: "indexeddb",
// "id": "a", database: "qunit"
// "method": "getAttachment", });
// "result": "success", }
// "status": 200, });
// "statusText": "Ok"
// }, "Get first attachment with range :_start:0, _end:undefined"); test("spy indexedDB usage", function () {
// }, function (err) { var context = this,
// deepEqual(err, "no error", "Check blob text content"); attachment = "attachment";
// }); stop();
// } expect(15);
//
//
// function getFirstAttachmentRange2() { deleteIndexedDB(context.jio)
// return jio.getAttachment({"_id": "a", .then(function () {
// "_attachment": "aa", return context.jio.put({"_id": "foo", "title": "bar"});
// "_start": 0, })
// "_end": 1}); .then(function () {
// } return context.jio.putAttachment({"_id": "foo",
// "_attachment": attachment,
// function getFirstAttachmentRangeTest2(answer) { "_data": big_string});
// var blob = answer.data; })
// answer.data = "<blob>"; .then(function () {
// return jIO.util.readBlobAsText(blob).then(function (e) { context.spy_open = sinon.spy(indexedDB, "open");
// deepEqual(blob.type, "text/plain", "Check blob type"); context.spy_create_store = sinon.spy(IDBDatabase.prototype,
// deepEqual(e.target.result, "a", "Check blob text content"); "createObjectStore");
// deepEqual(answer, { context.spy_transaction = sinon.spy(IDBDatabase.prototype,
// "attachment": "aa", "transaction");
// "data": "<blob>", context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
// "id": "a", context.spy_get = sinon.spy(IDBObjectStore.prototype, "get");
// "method": "getAttachment", context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
// "result": "success", context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
// "status": 200, "createIndex");
// "statusText": "Ok"
// }, "Get first attachment with range :_start:0, _end:1"); return context.jio.getAttachment({"_id": "foo",
// }, function (err) { "_attachment": attachment});
// deepEqual(err, "no error", "Check blob text content"); })
// }); .then(function () {
// }
// ok(context.spy_open.calledOnce, "open count " +
// function getFirstAttachmentRange3() { context.spy_open.callCount);
// return jio.getAttachment({"_id": "a", equal(context.spy_open.firstCall.args[0], "jio:qunit",
// "_attachment": "aa", "open first argument");
// "_start": 1,
// "_end": 3}); equal(context.spy_create_store.callCount, 0,
// } "createObjectStore count");
// function getFirstAttachmentRangeTest3(answer) { equal(context.spy_create_index.callCount, 0, "createIndex count");
// var blob = answer.data;
// answer.data = "<blob>"; ok(context.spy_transaction.calledOnce, "transaction count " +
// return jIO.util.readBlobAsText(blob).then(function (e) { context.spy_transaction.callCount);
// deepEqual(blob.type, "text/plain", "Check blob type"); deepEqual(context.spy_transaction.firstCall.args[0],
// deepEqual(e.target.result, "ab", "Check blob text content"); ["attachment", "blob"],
// deepEqual(answer, { "transaction first argument");
// "attachment": "aa", equal(context.spy_transaction.firstCall.args[1], "readonly",
// "data": "<blob>", "transaction second argument");
// "id": "a",
// "method": "getAttachment", equal(context.spy_store.callCount, 2, "store count " +
// "result": "success", context.spy_store.callCount);
// "status": 200, deepEqual(context.spy_store.firstCall.args[0], "attachment",
// "statusText": "Ok" "store first argument");
// }, "Get first attachment with range :_start:1, _end:3"); deepEqual(context.spy_store.secondCall.args[0], "blob",
// }, function (err) { "store first argument");
// deepEqual(err, "no error", "Check blob text content");
// }); equal(context.spy_get.callCount, 3, "get count " +
// } context.spy_get.callCount);
// deepEqual(context.spy_get.firstCall.args[0], "foo_attachment",
// "get first argument");
// function getSecondAttachment() { deepEqual(context.spy_get.secondCall.args[0], "foo_attachment_0",
// return jio.getAttachment({"_id": "a", "_attachment": "ab"}); "get first argument");
// } deepEqual(context.spy_get.thirdCall.args[0], "foo_attachment_1",
// "get first argument");
// function getSecondAttachmentTest(answer) {
// var blob = answer.data; ok(!context.spy_index.called, "index count " +
// answer.data = "<blob>"; context.spy_index.callCount);
// return jIO.util.readBlobAsText(blob).then(function (e) { })
// deepEqual(blob.type, "text/plain", "Check blob type"); .always(function () {
// deepEqual(e.target.result, "aba", "Check blob text content"); context.spy_open.restore();
// deepEqual(answer, { delete context.spy_open;
// "attachment": "ab", context.spy_create_store.restore();
// "data": "<blob>", delete context.spy_create_store;
// "id": "a", context.spy_transaction.restore();
// "method": "getAttachment", delete context.spy_transaction;
// "result": "success", context.spy_store.restore();
// "status": 200, delete context.spy_store;
// "statusText": "Ok" context.spy_get.restore();
// }, "Get second attachment"); delete context.spy_get;
// }, function (err) { context.spy_index.restore();
// deepEqual(err, "no error", "Check blob text content"); delete context.spy_index;
// }); context.spy_create_index.restore();
// } delete context.spy_create_index;
// })
// .fail(function (error) {
// ok(false, error);
// })
// .always(function () {
// function getSecondAttachmentRange1() { start();
// return success(jio.getAttachment({"_id": "a", });
// "_attachment": "ab", });
// "_start": -1}));
// } test("check result", function () {
// function getSecondAttachmentRangeTest1(answer) { var context = this,
// deepEqual(answer, { attachment = "attachment";
// "attachment": "ab", stop();
// "error": "not_found", expect(2);
// "id": "a",
// "message": "_start and _end must be positive", deleteIndexedDB(context.jio)
// "method": "getAttachment", .then(function () {
// "reason": "invalide _start, _end", return context.jio.put({"_id": "foo", "title": "bar"});
// "result": "error", })
// "status": 404, .then(function () {
// "statusText": "Not Found" return context.jio.putAttachment({"_id": "foo",
// }, "get attachment with _start or _end negative -> 404 Not Found"); "_attachment": attachment,
// } "_data": big_string});
// })
// .then(function () {
// return context.jio.getAttachment({"_id": "foo",
// function getSecondAttachmentRange2() { "_attachment": attachment});
// return success(jio.getAttachment({"_id": "a", })
// "_attachment": "ab", .then(function (result) {
// "_start": 1, ok(result.data instanceof Blob, "Data is Blob");
// "_end": 0})); return jIO.util.readBlobAsText(result.data);
// } })
// function getSecondAttachmentRangeTest2(answer) { .then(function (result) {
// deepEqual(answer, { equal(result.target.result, big_string,
// "attachment": "ab", "Attachment correctly fetched");
// "error": "not_found", })
// "id": "a", .fail(function (error) {
// "message": "start is great then end", ok(false, error);
// "method": "getAttachment", })
// "reason": "invalide offset", .always(function () {
// "result": "error", start();
// "status": 404, });
// "statusText": "Not Found" });
// }, "get attachment with _start > _end -> 404 Not Found");
// } test("streaming", function () {
// function getSecondAttachmentRange3() { var context = this,
// return jio.getAttachment({"_id": "a", attachment = "attachment";
// "_attachment": "ab", stop();
// "_start": 1, expect(2);
// "_end": 2});
// } deleteIndexedDB(context.jio)
// function getSecondAttachmentRangeTest3(answer) { .then(function () {
// var blob = answer.data; return context.jio.put({"_id": "foo", "title": "bar"});
// answer.data = "<blob>"; })
// return jIO.util.readBlobAsText(blob).then(function (e) { .then(function () {
// deepEqual(blob.type, "text/plain", "Check blob type"); return context.jio.putAttachment({"_id": "foo",
// deepEqual(e.target.result, "b", "Check blob text content"); "_attachment": attachment,
// deepEqual(answer, { "_data": big_string});
// "attachment": "ab", })
// "data": "<blob>", .then(function () {
// "id": "a", return context.jio.getAttachment({"_id": "foo",
// "method": "getAttachment", "_attachment": attachment,
// "result": "success", "_start": 1999995, "_end": 2000005});
// "status": 200, })
// "statusText": "Ok" .then(function (result) {
// }, "Get second attachment with range :_start:1, _end:3"); ok(result.data instanceof Blob, "Data is Blob");
// }, function (err) { return jIO.util.readBlobAsText(result.data);
// deepEqual(err, "no error", "Check blob text content"); })
// }); .then(function (result) {
// } var expected = "aaaaaaaaaa";
// equal(result.target.result, expected, "Attachment correctly fetched");
// })
// .fail(function (error) {
// function getLastDocument() { ok(false, error);
// return jio.get({"_id": "a"}); })
// } .always(function () {
// start();
// function getLastDocumentTest(answer) { });
// deepEqual(answer, { });
// "data": {
// "_id": "a", /////////////////////////////////////////////////////////////////
// "title": "Hoo", // indexeddbStorage.removeAttachment
// "_attachment": { /////////////////////////////////////////////////////////////////
// "aa": { module("indexeddbStorage.removeAttachment", {
// "content_type": "text/plain", setup: function () {
// "length": 3 this.jio = jIO.createJIO({
// }, type: "indexeddb",
// "ab": { database: "qunit"
// "content_type": "text/plain", });
// "length": 3 }
// } });
// }
// }, test("spy indexedDB usage", function () {
// "id": "a", var context = this,
// "method": "get", attachment = "attachment";
// "result": "success", stop();
// "status": 200, expect(15);
// "statusText": "Ok"
// }, "Get last document metadata"); deleteIndexedDB(context.jio)
// } .then(function () {
// return context.jio.put({"_id": "foo", "title": "bar"});
// function removeSecondAttachment() { })
// return jio.removeAttachment({"_id": "a", "_attachment": "ab"}); .then(function () {
// } return context.jio.putAttachment({"_id": "foo",
// "_attachment": attachment,
// function removeSecondAttachmentTest(answer) { "_data": big_string});
// deepEqual(answer, { })
// "attachment": "ab", .then(function () {
// "id": "a", context.spy_open = sinon.spy(indexedDB, "open");
// "method": "removeAttachment", context.spy_create_store = sinon.spy(IDBDatabase.prototype,
// "result": "success", "createObjectStore");
// "status": 204, context.spy_transaction = sinon.spy(IDBDatabase.prototype,
// "statusText": "No Content" "transaction");
// }, "Remove second document"); context.spy_store = sinon.spy(IDBTransaction.prototype,
// } "objectStore");
// context.spy_delete = sinon.spy(IDBObjectStore.prototype, "delete");
// function getInexistentSecondAttachment() { context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
// return success(jio.getAttachment({"_id": "a", "_attachment": "ab"})); context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
// } "createIndex");
// context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
// function getInexistentSecondAttachmentTest(answer) { context.spy_cursor_delete = sinon.spy(IDBCursor.prototype, "delete");
// deepEqual(answer, {
// "attachment": "ab", return context.jio.removeAttachment({"_id": "foo",
// "error": "not_found", "_attachment": attachment});
// "id": "a", })
// "message": "IndexeddbStorage, unable to get attachment.", .then(function () {
// "method": "getAttachment",
// "reason": "missing attachment", ok(context.spy_open.calledOnce, "open count " +
// "result": "error", context.spy_open.callCount);
// "status": 404, equal(context.spy_open.firstCall.args[0], "jio:qunit",
// "statusText": "Not Found" "open first argument");
// }, "Get inexistent second attachment");
// } equal(context.spy_create_store.callCount, 0,
// "createObjectStore count");
// function getOneAttachmentDocument() { equal(context.spy_create_index.callCount, 0,
// return jio.get({"_id": "a"}); "createIndex count");
// }
// ok(context.spy_transaction.calledOnce, "transaction count " +
// function getOneAttachmentDocumentTest(answer) { context.spy_transaction.callCount);
// deepEqual(answer, { deepEqual(context.spy_transaction.firstCall.args[0],
// "data": { ["attachment", "blob"],
// "_attachment": { "transaction first argument");
// "aa": { equal(context.spy_transaction.firstCall.args[1], "readwrite",
// "content_type": "text/plain", "transaction second argument");
// "length": 3
// } equal(context.spy_store.callCount, 2, "store count " +
// }, context.spy_store.callCount);
// "_id": "a", deepEqual(context.spy_store.firstCall.args[0], "attachment",
// "title": "Hoo" "store first argument");
// }, deepEqual(context.spy_store.secondCall.args[0], "blob",
// "id": "a", "store first argument");
// "method": "get",
// "result": "success", equal(context.spy_delete.callCount, 1, "delete count " +
// "status": 200, context.spy_delete.callCount);
// "statusText": "Ok" deepEqual(context.spy_delete.firstCall.args[0], "foo_attachment",
// }, "Get document metadata"); "delete first argument");
// }
// ok(context.spy_index.calledOnce, "index count " +
// function removeSecondAttachmentAgain() { context.spy_index.callCount);
// return success(jio.removeAttachment({"_id": "a", "_attachment": "ab"}));
// } ok(context.spy_cursor.calledOnce, "cursor count " +
// context.spy_cursor.callCount);
// function removeSecondAttachmentAgainTest(answer) { equal(context.spy_cursor_delete.callCount, 2, "cursor count " +
// deepEqual(answer, { context.spy_cursor_delete.callCount);
// "attachment": "ab", })
// "error": "not_found", .always(function () {
// "id": "a", context.spy_open.restore();
// "message": "IndexeddbStorage, document attachment not found.", delete context.spy_open;
// "method": "removeAttachment", context.spy_create_store.restore();
// "reason": "missing attachment", delete context.spy_create_store;
// "result": "error", context.spy_transaction.restore();
// "status": 404, delete context.spy_transaction;
// "statusText": "Not Found" context.spy_store.restore();
// }, "Remove inexistent attachment"); delete context.spy_store;
// } context.spy_delete.restore();
// delete context.spy_delete;
// function removeDocument() { context.spy_index.restore();
// return jio.remove({"_id": "a"}); delete context.spy_index;
// } context.spy_create_index.restore();
// delete context.spy_create_index;
// function removeDocumentTest(answer) { context.spy_cursor.restore();
// deepEqual(answer, { delete context.spy_cursor;
// "id": "a", context.spy_cursor_delete.restore();
// "method": "remove", delete context.spy_cursor_delete;
// "result": "success", })
// "status": 204, .fail(function (error) {
// "statusText": "No Content" ok(false, error);
// }, "Remove document and its attachments"); })
// } .always(function () {
// start();
// function getInexistentFirstAttachment() { });
// return success(jio.getAttachment({"_id": "a", "_attachment": "aa"})); });
// }
// /////////////////////////////////////////////////////////////////
// function getInexistentFirstAttachmentTest(answer) { // indexeddbStorage.putAttachment
// deepEqual(answer, { /////////////////////////////////////////////////////////////////
// "attachment": "aa", module("indexeddbStorage.putAttachment", {
// "error": "not_found", setup: function () {
// "id": "a", this.jio = jIO.createJIO({
// "message": "IndexeddbStorage, unable to get attachment.", type: "indexeddb",
// "method": "getAttachment", database: "qunit"
// "reason": "missing attachment", });
// "result": "error", }
// "status": 404, });
// "statusText": "Not Found"
// }, "Get inexistent first attachment"); test("spy indexedDB usage", function () {
// } var context = this,
// attachment = "attachment";
// function getInexistentDocument() { stop();
// return success(jio.get({"_id": "a"})); expect(21);
// }
// deleteIndexedDB(context.jio)
// function getInexistentDocumentTest(answer) { .then(function () {
// deepEqual(answer, { return context.jio.put({"_id": "foo", "title": "bar"});
// "error": "not_found", })
// "id": "a", .then(function () {
// "message": "IndexeddbStorage, unable to get document.", context.spy_open = sinon.spy(indexedDB, "open");
// "method": "get", context.spy_create_store = sinon.spy(IDBDatabase.prototype,
// "reason": "Not Found", "createObjectStore");
// "result": "error", context.spy_transaction = sinon.spy(IDBDatabase.prototype,
// "status": 404, "transaction");
// "statusText": "Not Found" context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
// }, "Get inexistent document"); context.spy_delete = sinon.spy(IDBObjectStore.prototype, "delete");
// } context.spy_put = sinon.spy(IDBObjectStore.prototype, "put");
// context.spy_index = sinon.spy(IDBObjectStore.prototype, "index");
// function removeInexistentDocument() { context.spy_create_index = sinon.spy(IDBObjectStore.prototype,
// return success(jio.remove({"_id": "a"})); "createIndex");
// } context.spy_cursor = sinon.spy(IDBIndex.prototype, "openCursor");
// context.spy_cursor_delete = sinon.spy(IDBCursor.prototype, "delete");
// function removeInexistentDocumentTest(answer) {
// deepEqual(answer, { return context.jio.putAttachment({"_id": "foo",
// "error": "not_found", "_attachment": attachment,
// "id": "a", "_data": big_string});
// "message": "IndexeddbStorage, unable to get metadata.", })
// "method": "remove", .then(function () {
// "reason": "Not Found",
// "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",
// }, "Remove already removed document"); "open first argument");
// }
// equal(context.spy_create_store.callCount, 0,
// function unexpectedError(error) { "createObjectStore count");
// if (error instanceof Error) { equal(context.spy_create_index.callCount, 0,
// deepEqual([ "createIndex count");
// error.name + ": " + error.message,
// error ok(context.spy_transaction.calledOnce, "transaction count " +
// ], "UNEXPECTED ERROR", "Unexpected error"); context.spy_transaction.callCount);
// } else { deepEqual(context.spy_transaction.firstCall.args[0],
// deepEqual(error, "UNEXPECTED ERROR", "Unexpected error"); ["attachment", "blob"],
// } "transaction first argument");
// } equal(context.spy_transaction.firstCall.args[1], "readwrite",
// "transaction second argument");
// // # Post new documents, list them and remove them
// // post a 201 equal(context.spy_store.callCount, 4, "store count " +
// postNewDocument().then(postNewDocumentTest). context.spy_store.callCount);
// // get 200 deepEqual(context.spy_store.firstCall.args[0], "attachment",
// then(getCreatedDocument).then(getCreatedDocumentTest). "store first argument");
// // post b 201 deepEqual(context.spy_store.secondCall.args[0], "blob",
// then(postSpecificDocument).then(postSpecificDocumentTest). "store first argument");
// // allD 200 2 documents deepEqual(context.spy_store.thirdCall.args[0], "attachment",
// then(listDocument).then(list2DocumentsTest). "store first argument");
// // allD+include_docs 200 2 documents deepEqual(context.spy_store.getCall(3).args[0], "blob",
// then(listDocumentsWithMetadata).then(list2DocumentsWithMetadataTest). "store first argument");
// // remove a 204
// then(removeCreatedDocument).then(removeCreatedDocumentTest). equal(context.spy_delete.callCount, 1, "delete count " +
// // remove b 204 context.spy_delete.callCount);
// then(removeSpecificDocument).then(removeSpecificDocumentTest). deepEqual(context.spy_delete.firstCall.args[0], "foo_attachment",
// // allD 200 empty storage "delete first argument");
// then(listEmptyStorage).then(listEmptyStorageTest).
// // # Create and update documents, and some attachment and remove them ok(context.spy_index.calledOnce, "index count " +
// // put 201 context.spy_index.callCount);
// then(putNewDocument).then(putNewDocumentTest).
// // get 200 ok(context.spy_cursor.calledOnce, "cursor count " +
// then(getCreatedDocument2).then(getCreatedDocument2Test). context.spy_cursor.callCount);
// // post 409 equal(context.spy_cursor_delete.callCount, 0, "delete count " +
// then(postSameDocument).then(postSameDocumentTest). context.spy_cursor_delete.callCount);
// // putA 404
// then(putAttachmentToNonExistentDocument). equal(context.spy_put.callCount, 3, "put count " +
// then(putAttachmentToNonExistentDocumentTest). context.spy_put.callCount);
// // putA a 204 deepEqual(context.spy_put.firstCall.args[0], {
// then(createAttachment).then(createAttachmentTest). "_attachment": "attachment",
// // putA a 204 "_id": "foo",
// then(updateAttachment).then(updateAttachmentTest). "_key_path": "foo_attachment",
// // putA b 204 "info": {
// then(createAnotherAttachment).then(createAnotherAttachmentTest). "content_type": "",
// // put 204 "length": 3000000
// then(updateLastDocument).then(updateLastDocumentTest). }
// // getA a 200 }, "put first argument");
// then(getFirstAttachment).then(getFirstAttachmentTest). delete context.spy_put.secondCall.args[0].blob;
// then(getFirstAttachmentRange1).then(getFirstAttachmentRangeTest1). // XXX Check blob content
// then(getFirstAttachmentRange2).then(getFirstAttachmentRangeTest2). deepEqual(context.spy_put.secondCall.args[0], {
// then(getFirstAttachmentRange3).then(getFirstAttachmentRangeTest3). "_attachment": "attachment",
// // getA b 200 "_id": "foo",
// then(getSecondAttachment).then(getSecondAttachmentTest). "_part": 0,
// then(getSecondAttachmentRange1).then(getSecondAttachmentRangeTest1). "_key_path": "foo_attachment_0"
// then(getSecondAttachmentRange2).then(getSecondAttachmentRangeTest2). }, "put first argument");
// then(getSecondAttachmentRange3).then(getSecondAttachmentRangeTest3). delete context.spy_put.thirdCall.args[0].blob;
// // get 200 // XXX Check blob content
// then(getLastDocument).then(getLastDocumentTest). deepEqual(context.spy_put.thirdCall.args[0], {
// // removeA b 204 "_attachment": "attachment",
// then(removeSecondAttachment).then(removeSecondAttachmentTest). "_id": "foo",
// // getA b 404 "_part": 1,
// then(getInexistentSecondAttachment). "_key_path": "foo_attachment_1"
// then(getInexistentSecondAttachmentTest). }, "put first argument");
// // get 200 })
// then(getOneAttachmentDocument).then(getOneAttachmentDocumentTest). .always(function () {
// // removeA b 404 context.spy_open.restore();
// then(removeSecondAttachmentAgain).then(removeSecondAttachmentAgainTest). delete context.spy_open;
// // remove 204 context.spy_create_store.restore();
// then(removeDocument).then(removeDocumentTest). delete context.spy_create_store;
// // getA a 404 context.spy_transaction.restore();
// then(getInexistentFirstAttachment).then(getInexistentFirstAttachmentTest). delete context.spy_transaction;
// // get 404 context.spy_store.restore();
// then(getInexistentDocument).then(getInexistentDocumentTest). delete context.spy_store;
// // remove 404 context.spy_delete.restore();
// then(removeInexistentDocument).then(removeInexistentDocumentTest). delete context.spy_delete;
// // end context.spy_index.restore();
// fail(unexpectedError). delete context.spy_index;
// always(start). context.spy_create_index.restore();
// always(function () { delete context.spy_create_index;
// server.restore(); 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