Commit 64b99388 authored by preetwinder's avatar preetwinder

add index keys

parent b08e246c
...@@ -43,10 +43,10 @@ ...@@ -43,10 +43,10 @@
/*jslint nomen: true */ /*jslint nomen: true */
/*global indexedDB, jIO, RSVP, Blob, Math, IDBKeyRange, IDBOpenDBRequest, /*global indexedDB, jIO, RSVP, Blob, Math, IDBKeyRange, IDBOpenDBRequest,
DOMError, Event*/ DOMError, Event, Set, parseStringToObject*/
(function (indexedDB, jIO, RSVP, Blob, Math, IDBKeyRange, IDBOpenDBRequest, (function (indexedDB, jIO, RSVP, Blob, Math, IDBKeyRange, IDBOpenDBRequest,
DOMError) { DOMError, parseStringToObject) {
"use strict"; "use strict";
// Read only as changing it can lead to data corruption // Read only as changing it can lead to data corruption
...@@ -59,9 +59,14 @@ ...@@ -59,9 +59,14 @@
"must be a non-empty string"); "must be a non-empty string");
} }
this._database_name = "jio:" + description.database; this._database_name = "jio:" + description.database;
this._version = description.version;
this._index_keys = description.index_keys || [];
} }
IndexedDBStorage.prototype.hasCapacity = function (name) { IndexedDBStorage.prototype.hasCapacity = function (name) {
if (name === "subquery") {
return this._index_keys;
}
return ((name === "list") || (name === "include")); return ((name === "list") || (name === "include"));
}; };
...@@ -69,34 +74,60 @@ ...@@ -69,34 +74,60 @@
return key_list.join("_"); return key_list.join("_");
} }
function handleUpgradeNeeded(evt) { function handleUpgradeNeeded(evt, index_keys) {
var db = evt.target.result, var db = evt.target.result,
store; store,
current_stores = Array.from(db.objectStoreNames),
current_indices,
i;
if (current_stores.indexOf("metadata") === -1) {
store = db.createObjectStore("metadata", {
keyPath: "_id",
autoIncrement: false
});
// 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});
} else {
store = evt.target.transaction.objectStore("metadata");
}
store = db.createObjectStore("metadata", { current_indices = new Set(store.indexNames);
keyPath: "_id", current_indices.delete("_id");
autoIncrement: false for (i = 0; i < index_keys.length; i += 1) {
}); if (current_indices.has(index_keys[i])) {
// It is not possible to use openKeyCursor on keypath directly current_indices.delete(index_keys[i]);
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=19955 } else {
store.createIndex("_id", "_id", {unique: true}); store.createIndex(index_keys[i], "doc." + index_keys[i],
{unique: false});
}
}
current_indices = Array.from(current_indices);
for (i = 0; i < current_indices.length; i += 1) {
store.deleteIndex(current_indices[i]);
}
store = db.createObjectStore("attachment", { if (current_stores.indexOf("attachment") === -1) {
keyPath: "_key_path", store = db.createObjectStore("attachment", {
autoIncrement: false keyPath: "_key_path",
}); autoIncrement: false
store.createIndex("_id", "_id", {unique: false}); });
store.createIndex("_id", "_id", {unique: false});
}
store = db.createObjectStore("blob", { if (current_stores.indexOf("blob") === -1) {
keyPath: "_key_path", store = db.createObjectStore("blob", {
autoIncrement: false keyPath: "_key_path",
}); autoIncrement: false
store.createIndex("_id_attachment", });
["_id", "_attachment"], {unique: false}); store.createIndex("_id_attachment",
store.createIndex("_id", "_id", {unique: false}); ["_id", "_attachment"], {unique: false});
store.createIndex("_id", "_id", {unique: false});
}
} }
function waitForOpenIndexedDB(db_name, callback) { function waitForOpenIndexedDB(db_name, version, index_keys, callback) {
var request; var request;
function canceller() { function canceller() {
...@@ -107,7 +138,7 @@ ...@@ -107,7 +138,7 @@
function resolver(resolve, reject) { function resolver(resolve, reject) {
// Open DB // // Open DB //
request = indexedDB.open(db_name); request = indexedDB.open(db_name, version);
request.onerror = function (error) { request.onerror = function (error) {
canceller(); canceller();
if ((error !== undefined) && if ((error !== undefined) &&
...@@ -135,7 +166,9 @@ ...@@ -135,7 +166,9 @@
}; };
// Create DB if necessary // // Create DB if necessary //
request.onupgradeneeded = handleUpgradeNeeded; request.onupgradeneeded = function (evt) {
handleUpgradeNeeded(evt, index_keys);
};
request.onversionchange = function () { request.onversionchange = function () {
canceller(); canceller();
...@@ -235,11 +268,14 @@ ...@@ -235,11 +268,14 @@
IndexedDBStorage.prototype.buildQuery = function (options) { IndexedDBStorage.prototype.buildQuery = function (options) {
var result_list = [], var result_list = [],
context = this; context = this,
query,
key,
value;
function pushIncludedMetadata(cursor) { function pushIncludedMetadata(cursor) {
result_list.push({ result_list.push({
"id": cursor.key, "id": cursor.primaryKey,
"value": {}, "value": {},
"doc": cursor.value.doc "doc": cursor.value.doc
}); });
...@@ -247,28 +283,35 @@ ...@@ -247,28 +283,35 @@
function pushMetadata(cursor) { function pushMetadata(cursor) {
result_list.push({ result_list.push({
"id": cursor.key, "id": cursor.primaryKey,
"value": {} "value": {}
}); });
} }
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return waitForOpenIndexedDB(context._database_name, function (db) { return waitForOpenIndexedDB(context._database_name, context._version,
return waitForTransaction(db, ["metadata"], "readonly", context._index_keys, function (db) {
function (tx) { return waitForTransaction(db, ["metadata"], "readonly",
if (options.include_docs === true) { function (tx) {
key = "_id";
if (options.subquery) {
query = parseStringToObject(options.subquery);
key = query.key;
value = query.value;
}
if (options.include_docs === true) {
return waitForAllSynchronousCursor(
tx.objectStore("metadata").index(key).openCursor(value),
pushIncludedMetadata
);
}
return waitForAllSynchronousCursor( return waitForAllSynchronousCursor(
tx.objectStore("metadata").index("_id").openCursor(), tx.objectStore("metadata").index(key).openKeyCursor(value),
pushIncludedMetadata pushMetadata
); );
} });
return waitForAllSynchronousCursor( });
tx.objectStore("metadata").index("_id").openKeyCursor(),
pushMetadata
);
});
});
}) })
.push(function () { .push(function () {
return result_list; return result_list;
...@@ -279,12 +322,13 @@ ...@@ -279,12 +322,13 @@
var context = this; var context = this;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return waitForOpenIndexedDB(context._database_name, function (db) { return waitForOpenIndexedDB(context._database_name, context._version,
return waitForTransaction(db, ["metadata"], "readonly", context._index_keys, function (db) {
function (tx) { return waitForTransaction(db, ["metadata"], "readonly",
return waitForIDBRequest(tx.objectStore("metadata").get(id)); function (tx) {
}); return waitForIDBRequest(tx.objectStore("metadata").get(id));
}); });
});
}) })
.push(function (evt) { .push(function (evt) {
if (evt.target.result) { if (evt.target.result) {
...@@ -307,19 +351,20 @@ ...@@ -307,19 +351,20 @@
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return waitForOpenIndexedDB(context._database_name, function (db) { return waitForOpenIndexedDB(context._database_name, context._version,
return waitForTransaction(db, ["metadata", "attachment"], "readonly", context._index_keys, function (db) {
function (tx) { return waitForTransaction(db, ["metadata", "attachment"],
return RSVP.all([ "readonly", function (tx) {
waitForIDBRequest(tx.objectStore("metadata").get(id)), return RSVP.all([
waitForAllSynchronousCursor( waitForIDBRequest(tx.objectStore("metadata").get(id)),
tx.objectStore("attachment").index("_id") waitForAllSynchronousCursor(
.openKeyCursor(IDBKeyRange.only(id)), tx.objectStore("attachment").index("_id")
addEntry .openKeyCursor(IDBKeyRange.only(id)),
) addEntry
]); )
}); ]);
}); });
});
}) })
.push(function (result_list) { .push(function (result_list) {
var evt = result_list[0]; var evt = result_list[0];
...@@ -336,56 +381,58 @@ ...@@ -336,56 +381,58 @@
}; };
IndexedDBStorage.prototype.put = function (id, metadata) { IndexedDBStorage.prototype.put = function (id, metadata) {
return waitForOpenIndexedDB(this._database_name, function (db) { return waitForOpenIndexedDB(this._database_name, this._version,
return waitForTransaction(db, ["metadata"], "readwrite", this._index_keys, function (db) {
function (tx) { return waitForTransaction(db, ["metadata"], "readwrite",
return waitForIDBRequest(tx.objectStore("metadata").put({ function (tx) {
"_id": id, return waitForIDBRequest(tx.objectStore("metadata").put({
"doc": metadata "_id": id,
})); "doc": metadata
}); }));
}); });
});
}; };
IndexedDBStorage.prototype.remove = function (id) { IndexedDBStorage.prototype.remove = function (id) {
return waitForOpenIndexedDB(this._database_name, function (db) { return waitForOpenIndexedDB(this._database_name, this._version,
return waitForTransaction(db, ["metadata", "attachment", "blob"], this._index_keys, function (db) {
"readwrite", function (tx) { return waitForTransaction(db, ["metadata", "attachment", "blob"],
"readwrite", function (tx) {
var promise_list = [],
metadata_store = tx.objectStore("metadata"), var promise_list = [],
attachment_store = tx.objectStore("attachment"), metadata_store = tx.objectStore("metadata"),
blob_store = tx.objectStore("blob"); attachment_store = tx.objectStore("attachment"),
blob_store = tx.objectStore("blob");
function deleteAttachment(cursor) {
promise_list.push(
waitForIDBRequest(attachment_store.delete(cursor.primaryKey))
);
}
function deleteBlob(cursor) {
promise_list.push(
waitForIDBRequest(blob_store.delete(cursor.primaryKey))
);
}
return RSVP.all([ function deleteAttachment(cursor) {
waitForIDBRequest(metadata_store.delete(id)), promise_list.push(
waitForAllSynchronousCursor( waitForIDBRequest(attachment_store.delete(cursor.primaryKey))
attachment_store.index("_id") );
.openKeyCursor(IDBKeyRange.only(id)), }
deleteAttachment function deleteBlob(cursor) {
), promise_list.push(
waitForAllSynchronousCursor( waitForIDBRequest(blob_store.delete(cursor.primaryKey))
blob_store.index("_id") );
.openKeyCursor(IDBKeyRange.only(id)), }
deleteBlob
), return RSVP.all([
]) waitForIDBRequest(metadata_store.delete(id)),
.then(function () { waitForAllSynchronousCursor(
return RSVP.all(promise_list); attachment_store.index("_id")
}); .openKeyCursor(IDBKeyRange.only(id)),
}); deleteAttachment
}); ),
waitForAllSynchronousCursor(
blob_store.index("_id")
.openKeyCursor(IDBKeyRange.only(id)),
deleteBlob
),
])
.then(function () {
return RSVP.all(promise_list);
});
});
});
}; };
IndexedDBStorage.prototype.getAttachment = function (id, name, options) { IndexedDBStorage.prototype.getAttachment = function (id, name, options) {
...@@ -395,7 +442,8 @@ ...@@ -395,7 +442,8 @@
var db_name = this._database_name, var db_name = this._database_name,
start, start,
end, end,
array_buffer_list = []; array_buffer_list = [],
context = this;
start = options.start || 0; start = options.start || 0;
end = options.end; end = options.end;
...@@ -416,65 +464,66 @@ ...@@ -416,65 +464,66 @@
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return waitForOpenIndexedDB(db_name, function (db) { return waitForOpenIndexedDB(db_name, context._version,
return waitForTransaction(db, ["blob"], "readonly", context._index_keys, function (db) {
function (tx) { return waitForTransaction(db, ["blob"], "readonly",
var key_path = buildKeyPath([id, name]), function (tx) {
blob_store = tx.objectStore("blob"), var key_path = buildKeyPath([id, name]),
start_index, blob_store = tx.objectStore("blob"),
end_index, start_index,
promise_list = []; end_index,
promise_list = [];
start_index = Math.floor(start / UNITE);
if (end !== undefined) { start_index = Math.floor(start / UNITE);
end_index = Math.floor(end / UNITE); if (end !== undefined) {
if (end % UNITE === 0) { end_index = Math.floor(end / UNITE);
end_index -= 1; if (end % UNITE === 0) {
end_index -= 1;
}
} }
}
function getBlobKey(cursor) {
var index = parseInt(
cursor.primaryKey.slice(key_path.length + 1),
10
),
i;
if ((start !== 0) && (index < start_index)) { function getBlobKey(cursor) {
// No need to fetch blobs at the start var index = parseInt(
return; cursor.primaryKey.slice(key_path.length + 1),
} 10
if ((end !== undefined) && (index > end_index)) { ),
// No need to fetch blobs at the end i;
return;
if ((start !== 0) && (index < start_index)) {
// No need to fetch blobs at the start
return;
}
if ((end !== undefined) && (index > end_index)) {
// No need to fetch blobs at the end
return;
}
i = index - start_index;
// Extend array size
while (i > promise_list.length) {
promise_list.push(null);
i -= 1;
}
// Sort the blob by their index
promise_list.splice(
index - start_index,
0,
waitForIDBRequest(blob_store.get(cursor.primaryKey))
);
} }
i = index - start_index; // Get all blob keys to check if they must be fetched
// Extend array size return waitForAllSynchronousCursor(
while (i > promise_list.length) { blob_store.index("_id_attachment")
promise_list.push(null); .openKeyCursor(IDBKeyRange.only([id, name])),
i -= 1; getBlobKey
} )
// Sort the blob by their index .then(function () {
promise_list.splice( return RSVP.all(promise_list);
index - start_index, });
0, });
waitForIDBRequest(blob_store.get(cursor.primaryKey)) });
);
}
// Get all blob keys to check if they must be fetched
return waitForAllSynchronousCursor(
blob_store.index("_id_attachment")
.openKeyCursor(IDBKeyRange.only([id, name])),
getBlobKey
)
.then(function () {
return RSVP.all(promise_list);
});
});
});
}) })
.push(function (result_list) { .push(function (result_list) {
// No need to keep the IDB open // No need to keep the IDB open
...@@ -501,46 +550,47 @@ ...@@ -501,46 +550,47 @@
// Request the full blob // Request the full blob
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return waitForOpenIndexedDB(db_name, function (db) { return waitForOpenIndexedDB(db_name, context._version,
return waitForTransaction(db, ["attachment", "blob"], "readonly", context._index_keys, function (db) {
function (tx) { return waitForTransaction(db, ["attachment", "blob"], "readonly",
var key_path = buildKeyPath([id, name]), function (tx) {
attachment_store = tx.objectStore("attachment"), var key_path = buildKeyPath([id, name]),
blob_store = tx.objectStore("blob"); attachment_store = tx.objectStore("attachment"),
blob_store = tx.objectStore("blob");
function getBlob(cursor) { function getBlob(cursor) {
var index = parseInt( var index = parseInt(
cursor.primaryKey.slice(key_path.length + 1), cursor.primaryKey.slice(key_path.length + 1),
10 10
), ),
i = index; i = index;
// Extend array size // Extend array size
while (i > array_buffer_list.length) { while (i > array_buffer_list.length) {
array_buffer_list.push(null); array_buffer_list.push(null);
i -= 1; i -= 1;
}
// Sort the blob by their index
array_buffer_list.splice(
index,
0,
cursor.value.blob
);
} }
// Sort the blob by their index
array_buffer_list.splice( return RSVP.all([
index, // Get the attachment info (mime type)
0, waitForIDBRequest(attachment_store.get(
cursor.value.blob key_path
); )),
} // Get all needed blobs
waitForAllSynchronousCursor(
return RSVP.all([ blob_store.index("_id_attachment")
// Get the attachment info (mime type) .openCursor(IDBKeyRange.only([id, name])),
waitForIDBRequest(attachment_store.get( getBlob
key_path )
)), ]);
// Get all needed blobs });
waitForAllSynchronousCursor( });
blob_store.index("_id_attachment")
.openCursor(IDBKeyRange.only([id, name])),
getBlob
)
]);
});
});
}) })
.push(function (result_list) { .push(function (result_list) {
...@@ -573,7 +623,7 @@ ...@@ -573,7 +623,7 @@
}; };
IndexedDBStorage.prototype.putAttachment = function (id, name, blob) { IndexedDBStorage.prototype.putAttachment = function (id, name, blob) {
var db_name = this._database_name; var db_name = this._database_name, context = this;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
// Split the blob first // Split the blob first
...@@ -591,103 +641,106 @@ ...@@ -591,103 +641,106 @@
handled_size += UNITE; handled_size += UNITE;
} }
return waitForOpenIndexedDB(db_name, function (db) { return waitForOpenIndexedDB(db_name, context._version,
return waitForTransaction(db, ["attachment", "blob"], "readwrite", context._index_keys, function (db) {
function (tx) { return waitForTransaction(db, ["attachment", "blob"], "readwrite",
var blob_store, function (tx) {
promise_list, var blob_store,
delete_promise_list = [], promise_list,
key_path = buildKeyPath([id, name]), delete_promise_list = [],
i; key_path = buildKeyPath([id, name]),
// First write the attachment info on top of previous i;
promise_list = [ // First write the attachment info on top of previous
waitForIDBRequest(tx.objectStore("attachment").put({ promise_list = [
"_key_path": key_path, waitForIDBRequest(tx.objectStore("attachment").put({
"_id": id, "_key_path": key_path,
"_attachment": name, "_id": id,
"info": { "_attachment": name,
"content_type": blob.type, "info": {
"length": blob.size "content_type": blob.type,
} "length": blob.size
})) }
];
// Then, write all blob parts on top of previous
blob_store = tx.objectStore("blob");
for (i = 0; i < blob_part.length; i += 1) {
promise_list.push(
waitForIDBRequest(blob_store.put({
"_key_path": buildKeyPath([id, name, i]),
"_id" : id,
"_attachment" : name,
"_part" : i,
"blob": blob_part[i]
})) }))
); ];
} // Then, write all blob parts on top of previous
blob_store = tx.objectStore("blob");
for (i = 0; i < blob_part.length; i += 1) {
promise_list.push(
waitForIDBRequest(blob_store.put({
"_key_path": buildKeyPath([id, name, i]),
"_id" : id,
"_attachment" : name,
"_part" : i,
"blob": blob_part[i]
}))
);
}
function deleteEntry(cursor) { function deleteEntry(cursor) {
var index = parseInt( var index = parseInt(
cursor.primaryKey.slice(key_path.length + 1), cursor.primaryKey.slice(key_path.length + 1),
10 10
);
if (index >= blob_part.length) {
delete_promise_list.push(
waitForIDBRequest(blob_store.delete(cursor.primaryKey))
); );
if (index >= blob_part.length) {
delete_promise_list.push(
waitForIDBRequest(blob_store.delete(cursor.primaryKey))
);
}
} }
}
// Finally, remove all remaining blobs // Finally, remove all remaining blobs
promise_list.push( promise_list.push(
waitForAllSynchronousCursor( waitForAllSynchronousCursor(
blob_store.index("_id_attachment") blob_store.index("_id_attachment")
.openKeyCursor(IDBKeyRange.only([id, name])), .openKeyCursor(IDBKeyRange.only([id, name])),
deleteEntry deleteEntry
) )
); );
return RSVP.all(promise_list) return RSVP.all(promise_list)
.then(function () { .then(function () {
if (delete_promise_list.length) { if (delete_promise_list.length) {
return RSVP.all(delete_promise_list); return RSVP.all(delete_promise_list);
} }
}); });
}); });
}); });
}); });
}; };
IndexedDBStorage.prototype.removeAttachment = function (id, name) { IndexedDBStorage.prototype.removeAttachment = function (id, name) {
return waitForOpenIndexedDB(this._database_name, function (db) { return waitForOpenIndexedDB(this._database_name, this._version,
return waitForTransaction(db, ["attachment", "blob"], "readwrite", this._index_keys, function (db) {
function (tx) { return waitForTransaction(db, ["attachment", "blob"], "readwrite",
var promise_list = [], function (tx) {
attachment_store = tx.objectStore("attachment"), var promise_list = [],
blob_store = tx.objectStore("blob"); attachment_store = tx.objectStore("attachment"),
blob_store = tx.objectStore("blob");
function deleteEntry(cursor) {
promise_list.push(
waitForIDBRequest(blob_store.delete(cursor.primaryKey))
);
}
return RSVP.all([ function deleteEntry(cursor) {
waitForIDBRequest( promise_list.push(
attachment_store.delete(buildKeyPath([id, name])) waitForIDBRequest(blob_store.delete(cursor.primaryKey))
), );
waitForAllSynchronousCursor( }
blob_store.index("_id_attachment")
.openKeyCursor(IDBKeyRange.only([id, name])), return RSVP.all([
deleteEntry waitForIDBRequest(
) attachment_store.delete(buildKeyPath([id, name]))
]) ),
.then(function () { waitForAllSynchronousCursor(
return RSVP.all(promise_list); blob_store.index("_id_attachment")
}); .openKeyCursor(IDBKeyRange.only([id, name])),
deleteEntry
)
])
.then(function () {
return RSVP.all(promise_list);
});
}); });
}); });
}; };
jIO.addStorage("indexeddb", IndexedDBStorage); jIO.addStorage("indexeddb", IndexedDBStorage);
}(indexedDB, jIO, RSVP, Blob, Math, IDBKeyRange, IDBOpenDBRequest, DOMError)); }(indexedDB, jIO, RSVP, Blob, Math, IDBKeyRange, IDBOpenDBRequest, DOMError,
parseStringToObject));
...@@ -49,6 +49,182 @@ ...@@ -49,6 +49,182 @@
}); });
} }
function idCompare(value1, value2) {
if (value1.id > value2.id) {
return 1;
}
if (value1.id < value2.id) {
return -1;
}
return 0;
}
/////////////////////////////////////////////////////////////////
// indexedDBStorage.buildQuery
/////////////////////////////////////////////////////////////////
module("indexedDBStorage.buildQuery", {
teardown: function () {
deleteIndexedDB(this.jio);
}
});
test("Simple query matching single object", function () {
var context = this;
context.jio = jIO.createJIO({
type: "indexeddb",
database: "index2_test",
index_keys: ["a", "b"],
});
stop();
expect(2);
context.jio.put("32", {"a": "3", "b": "2"})
.then(function () {
return context.jio.allDocs({subquery: 'a: "3"'});
})
.then(function (result) {
equal(result.data.total_rows, 1);
deepEqual(result.data.rows, [{"id": "32", "value": {}}]);
})
.fail(function (error) {
console.log(error);
})
.always(function () {
start();
});
});
test("Simple query matching multiple objects", function () {
var context = this;
context.jio = jIO.createJIO({
type: "indexeddb",
database: "index2_test",
index_keys: ["a", "b"],
});
stop();
expect(2);
RSVP.all([
context.jio.put("32", {a: "3", b: "1"}),
context.jio.put("21", {a: "8", b: "1"}),
context.jio.put("3", {a: "5", b: "1"})
])
.then(function () {
return context.jio.allDocs({subquery: 'b: "1"'});
})
.then(function (result) {
equal(result.data.total_rows, 3);
deepEqual(result.data.rows.sort(idCompare),
[
{"id": "32", "value": {}},
{"id": "21", "value": {}},
{"id": "3", "value": {}}
].sort(idCompare));
})
.fail(function (error) {
console.log(error);
})
.always(function () {
start();
});
});
test("Index keys are modified", function () {
var context = this;
context.jio = jIO.createJIO({
type: "indexeddb",
database: "index2_test",
version: 1,
index_keys: ["a"]
});
stop();
expect(7);
RSVP.all([
context.jio.put("32", {"a": "3", "b": "2", "c": "inverse"}),
context.jio.put("5", {"a": "6", "b": "2", "c": "strong"}),
context.jio.put("14", {"a": "67", "b": "3", "c": "disolve"})
])
.then(function () {
return context.jio.allDocs({subquery: 'a: "67"'});
})
.then(function (result) {
deepEqual(result.data.rows, [{"id": "14", "value": {}}]);
})
.then(function () {
context.jio = jIO.createJIO({
type: "indexeddb",
database: "index2_test",
version: 2,
index_keys: ["a", "b", "c"],
});
})
.then(function () {
return RSVP.all([
context.jio.put("18", {"a": "2", "b": "3", "c": "align"}),
context.jio.put("62", {"a": "3", "b": "2", "c": "disolve"})
]);
})
.then(function () {
return context.jio.allDocs({subquery: 'b: "3"'});
})
.then(function (result) {
deepEqual(result.data.rows, [{"id": "14", "value": {}},
{"id": "18", "value": {}}]);
})
.then(function () {
return context.jio.allDocs({subquery: 'c: "disolve"'});
})
.then(function (result) {
deepEqual(result.data.rows, [{"id": "14", "value": {}},
{"id": "62", "value": {}}]);
})
.then(function () {
return context.jio.allDocs({subquery: 'a: "3"'});
})
.then(function (result) {
deepEqual(result.data.rows, [{"id": "32", "value": {}},
{"id": "62", "value": {}}]);
})
.then(function () {
context.jio = jIO.createJIO({
type: "indexeddb",
database: "index2_test",
index_keys: ["a", "c"],
version: 3
});
})
.then(function () {
return context.jio.put("192", {"a": "3", "b": "3", "c": "disolve"});
})
.then(function () {
return context.jio.allDocs({subquery: 'a: "3"'});
})
.then(function (result) {
deepEqual(result.data.rows.sort(idCompare), [{"id": "192", "value": {}},
{"id": "32", "value": {}}, {"id": "62", "value": {}}]);
})
.then(function () {
return context.jio.allDocs({query: 'c: "disolve"'});
})
.then(function (result) {
deepEqual(result.data.rows.sort(idCompare), [{"id": "14", "value": {}},
{"id": "192", "value": {}}, {"id": "62", "value": {}}]);
})
.then(function () {
return context.jio.allDocs({subquery: 'b: "3"'});
})
.fail(function (error) {
equal(error.status_code, 501);
equal(error.message,
"Capacity 'query' is not implemented on 'indexeddb'");
})
.always(function () {
start();
});
});
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// indexeddbStorage.constructor // indexeddbStorage.constructor
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
......
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