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