Commit cd07ec24 authored by preetwinder's avatar preetwinder

fix tests, new tests and fix index2 issues

parent 50234845
...@@ -33,11 +33,11 @@ ...@@ -33,11 +33,11 @@
} }
this._sub_storage = jIO.createJIO(description.sub_storage); this._sub_storage = jIO.createJIO(description.sub_storage);
this._database_name = "jio:" + description.database; this._database_name = "jio:" + description.database;
this._index_keys = description.index_keys; this._index_keys = description.index_keys || [];
} }
IndexStorage2.prototype.hasCapacity = function (name) { IndexStorage2.prototype.hasCapacity = function (name) {
return ((name === "list") || (name === "query")); return ((name === "list") || (name === "query")) || (name === "limit");
}; };
function handleUpgradeNeeded(evt, index_keys) { function handleUpgradeNeeded(evt, index_keys) {
...@@ -160,26 +160,43 @@ ...@@ -160,26 +160,43 @@
}); });
} }
IndexStorage2.prototype._runQuery = function (index, value) { function filterDocValues(doc, keys) {
var filtered_doc = {}, i;
for (i = 0; i < keys.length; i += 1) {
if (doc[keys[i]]) {
filtered_doc[keys[i]] = doc[keys[i]];
} else {
throw new jIO.util.jIOError(
"Index key '" + keys[i] + "' not found in document",
404
);
}
}
return filtered_doc;
}
IndexStorage2.prototype._runQuery = function (index, value, limit) {
var context = this; var context = this;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
if ((context._index_keys.indexOf(index) === -1)) { if ((context._index_keys.indexOf(index) === -1)) {
if (context._sub_storage.hasCapacity("query")) { try {
return context._sub_storage.buildQuery( context._sub_storage.hasCapacity("query");
{"query": index + ":" + value} } catch (error) {
) throw new jIO.util.jIOError(
.then(function (result) { "No index for this key and substorage doesn't support queries"
return result; );
});
} }
return context._sub_storage.buildQuery(
{"query": index + ":" + value}
);
} }
return waitForOpenIndexedDB(context._database_name, return waitForOpenIndexedDB(context._database_name, context._index_keys,
context._index_keys, function (db) { function (db) {
return waitForTransaction(db, ["index-store"], "readonly", return waitForTransaction(db, ["index-store"], "readonly",
function (tx) { function (tx) {
return waitForIDBRequest(tx.objectStore("index-store") return waitForIDBRequest(tx.objectStore("index-store")
.index("Index-" + index).getAll(value)) .index("Index-" + index).getAll(value, limit))
.then(function (evt) { .then(function (evt) {
return evt.target.result; return evt.target.result;
}); });
...@@ -188,12 +205,12 @@ ...@@ -188,12 +205,12 @@
}); });
}; };
IndexStorage2.prototype._processQueryObject = function (object) { IndexStorage2.prototype._processQueryObject = function (object, limit) {
var promise_list = [], context = this, i, j, query_result = new Set(); var promise_list = [], context = this, i, j, query_result = new Set();
return RSVP.Queue() return RSVP.Queue()
.push(function () { .push(function () {
if (object.type === "simple") { if (object.type === "simple") {
return context._runQuery(object.key, object.value); return context._runQuery(object.key, object.value, limit);
} }
if (object.type === "complex") { if (object.type === "complex") {
for (i = 0; i < object.query_list.length; i += 1) { for (i = 0; i < object.query_list.length; i += 1) {
...@@ -234,18 +251,20 @@ ...@@ -234,18 +251,20 @@
IndexStorage2.prototype.buildQuery = function (options) { IndexStorage2.prototype.buildQuery = function (options) {
var context = this; var context = this;
if (options.query) { if (options.query) {
return this._processQueryObject(parseStringToObject(options.query)) return this._processQueryObject(parseStringToObject(options.query),
.then(function (result) { options.limit)
.push(function (result) {
return result.map(function (value) { return result.map(function (value) {
return {"id": value.id, "value": {} }; return {"id": value.id, "value": {} };
}); });
}); });
} }
return waitForOpenIndexedDB(context._database_name, return waitForOpenIndexedDB(context._database_name, context._index_keys,
context._index_keys, function (db) { function (db) {
return waitForTransaction(db, ["index-store"], "readonly", return waitForTransaction(db, ["index-store"], "readonly",
function (tx) { function (tx) {
return waitForIDBRequest(tx.objectStore("index-store").getAll()) return waitForIDBRequest(tx.objectStore("index-store")
.getAll(undefined, options.limit))
.then(function (evt) { .then(function (evt) {
return evt.target.result.map(function (value) { return evt.target.result.map(function (value) {
return {"id": value.id, "value": {} }; return {"id": value.id, "value": {} };
...@@ -259,29 +278,18 @@ ...@@ -259,29 +278,18 @@
return this._sub_storage.get.apply(this._sub_storage, arguments); return this._sub_storage.get.apply(this._sub_storage, arguments);
}; };
IndexStorage2.prototype._filter_doc_values = function (doc, keys) {
var filtered_doc = {}, i;
for (i = 0; i < keys.length; i += 1) {
filtered_doc[keys[i]] = doc[keys[i]];
}
return filtered_doc;
};
IndexStorage2.prototype.put = function (id, value) { IndexStorage2.prototype.put = function (id, value) {
var context = this; var context = this;
return context._sub_storage.put(id, value) return context._sub_storage.put(id, value)
.push(function (result) { .push(function () {
return waitForOpenIndexedDB(context._database_name, return waitForOpenIndexedDB(context._database_name, context._index_keys,
context._index_keys, function (db) { function (db) {
return waitForTransaction(db, ["index-store"], "readwrite", return waitForTransaction(db, ["index-store"], "readwrite",
function (tx) { function (tx) {
return waitForIDBRequest(tx.objectStore("index-store").put({ return waitForIDBRequest(tx.objectStore("index-store").put({
"id": id, "id": id,
"doc": context._filter_doc_values(value, context._index_keys) "doc": filterDocValues(value, context._index_keys)
})) }));
.then(function () {
return result;
});
}); });
}); });
}); });
...@@ -291,13 +299,13 @@ ...@@ -291,13 +299,13 @@
var context = this; var context = this;
return context._sub_storage.post(value) return context._sub_storage.post(value)
.push(function (id) { .push(function (id) {
return waitForOpenIndexedDB(context._database_name, return waitForOpenIndexedDB(context._database_name, context._index_keys,
context._index_keys, function (db) { function (db) {
return waitForTransaction(db, ["index-store"], "readwrite", return waitForTransaction(db, ["index-store"], "readwrite",
function (tx) { function (tx) {
return waitForIDBRequest(tx.objectStore("index-store").put({ return waitForIDBRequest(tx.objectStore("index-store").put({
"id": id, "id": id,
"doc": context._filter_doc_values(value, context._index_keys) "doc": filterDocValues(value, context._index_keys)
})) }))
.then(function () { .then(function () {
return id; return id;
......
...@@ -18,10 +18,8 @@ ...@@ -18,10 +18,8 @@
* See https://www.nexedi.com/licensing for rationale and options. * See https://www.nexedi.com/licensing for rationale and options.
*/ */
/*jslint nomen: true */ /*jslint nomen: true */
/*global indexedDB, sinon, IDBDatabase, Blob, /*global indexedDB, Blob*/
IDBTransaction, IDBIndex, IDBObjectStore, IDBKeyRange*/ (function (jIO, QUnit, indexedDB, Blob) {
(function (jIO, QUnit, indexedDB, sinon, IDBDatabase, Blob,
IDBTransaction, IDBIndex, IDBObjectStore, IDBKeyRange) {
"use strict"; "use strict";
var test = QUnit.test, var test = QUnit.test,
stop = QUnit.stop, stop = QUnit.stop,
...@@ -30,7 +28,8 @@ ...@@ -30,7 +28,8 @@
expect = QUnit.expect, expect = QUnit.expect,
deepEqual = QUnit.deepEqual, deepEqual = QUnit.deepEqual,
equal = QUnit.equal, equal = QUnit.equal,
module = QUnit.module; module = QUnit.module,
throws = QUnit.throws;
function deleteIndexedDB(storage) { function deleteIndexedDB(storage) {
return new RSVP.Promise(function resolver(resolve, reject) { return new RSVP.Promise(function resolver(resolve, reject) {
...@@ -69,11 +68,10 @@ ...@@ -69,11 +68,10 @@
deleteIndexedDB(this.jio); deleteIndexedDB(this.jio);
} }
}); });
test("Constructor with empty index_keys", function () { test("Constructor without index_keys", function () {
this.jio = jIO.createJIO({ this.jio = jIO.createJIO({
type: "index2", type: "index2",
database: "index2_test", database: "index2_test",
index_keys: [],
sub_storage: { sub_storage: {
type: "dummystorage3" type: "dummystorage3"
} }
...@@ -82,6 +80,23 @@ ...@@ -82,6 +80,23 @@
equal(this.jio.__type, "index2"); equal(this.jio.__type, "index2");
equal(this.jio.__storage._sub_storage.__type, "dummystorage3"); equal(this.jio.__storage._sub_storage.__type, "dummystorage3");
equal(this.jio.__storage._database_name, "jio:index2_test"); equal(this.jio.__storage._database_name, "jio:index2_test");
deepEqual(this.jio.__storage._index_keys, []);
});
test("Constructor with index_keys", function () {
this.jio = jIO.createJIO({
type: "index2",
database: "index2_test",
index_keys: ["a", "b"],
sub_storage: {
type: "dummystorage3"
}
});
equal(this.jio.__type, "index2");
equal(this.jio.__storage._sub_storage.__type, "dummystorage3");
equal(this.jio.__storage._database_name, "jio:index2_test");
deepEqual(this.jio.__storage._index_keys, ["a", "b"]);
}); });
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -96,14 +111,27 @@ ...@@ -96,14 +111,27 @@
this.jio = jIO.createJIO({ this.jio = jIO.createJIO({
type: "index2", type: "index2",
database: "index2_test", database: "index2_test",
index_keys: [],
sub_storage: { sub_storage: {
type: "dummystorage3" type: "dummystorage3"
} }
}); });
throws(
function () {
this.jio.hasCapacity("non");
},
function (error) {
ok(error instanceof jIO.util.jIOError);
equal(error.status_code, 501);
equal(error.message,
"Capacity 'non' is not implemented on 'index2'");
return true;
}
);
ok(this.jio.hasCapacity("list")); ok(this.jio.hasCapacity("list"));
ok(this.jio.hasCapacity("query")); ok(this.jio.hasCapacity("query"));
ok(this.jio.hasCapacity("limit"));
}); });
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -124,35 +152,23 @@ ...@@ -124,35 +152,23 @@
deleteIndexedDB(this.jio); deleteIndexedDB(this.jio);
} }
}); });
test("Simple put get", function () { test("Get calls substorage", function () {
var context = this; var context = this;
stop(); stop();
expect(4); expect(2);
DummyStorage3.prototype.put = function (id, value) {
equal(id, "32");
deepEqual(value, {"a": 3, "b": 2, "c": 8});
return id;
};
DummyStorage3.prototype.get = function (id) { DummyStorage3.prototype.get = function (id) {
equal(id, "32"); equal(id, "32");
return {"a": 3, "b": 2, "c": 8}; return {"a": 3, "b": 2, "c": 8};
}; };
context.jio.put("32", {"a": 3, "b": 2, "c": 8}) context.jio.get("32")
.then(function () {
return context.jio.get("32");
})
.then(function (result) { .then(function (result) {
deepEqual(result, {"a": 3, "b": 2, "c": 8}); deepEqual(result, {"a": 3, "b": 2, "c": 8});
}) })
.fail(function (error) { .fail(function (error) {
console.log(error); console.log(error);
}) })
.then(function () {
return deleteIndexedDB(context.jio);
})
.always(function () { .always(function () {
start(); start();
}); });
...@@ -252,12 +268,12 @@ ...@@ -252,12 +268,12 @@
}); });
}); });
test("No index keys provided", function () { test("Querying with key without an index", function () {
var context = this; var context = this;
context.jio = jIO.createJIO({ context.jio = jIO.createJIO({
type: "index2", type: "index2",
database: "index2_test", database: "index2_test",
index_keys: [], index_keys: ["a"],
sub_storage: { sub_storage: {
type: "dummystorage3" type: "dummystorage3"
} }
...@@ -270,9 +286,6 @@ ...@@ -270,9 +286,6 @@
deepEqual(value, {"a": "3", "b": "2"}); deepEqual(value, {"a": "3", "b": "2"});
return id; return id;
}; };
DummyStorage3.prototype.buildQuery = function (options) {
equal(options.query, 'a:3');
};
DummyStorage3.prototype.hasCapacity = function (capacity) { DummyStorage3.prototype.hasCapacity = function (capacity) {
equal(capacity, "query"); equal(capacity, "query");
return false; return false;
...@@ -280,11 +293,14 @@ ...@@ -280,11 +293,14 @@
context.jio.put("32", {"a": "3", "b": "2"}) context.jio.put("32", {"a": "3", "b": "2"})
.then(function () { .then(function () {
return context.jio.allDocs({query: 'a:"3"'}); return context.jio.allDocs({query: 'b:"2"'});
})
.then(function () {
return deleteIndexedDB(context.jio);
}) })
.fail(function (error) { .fail(function (error) {
equal(error.message, equal(error.message,
"Capacity 'query' is not implemented on 'dummystorage3'"); "No index for this key and substorage doesn't support queries");
}) })
.always(function () { .always(function () {
start(); start();
...@@ -309,7 +325,7 @@ ...@@ -309,7 +325,7 @@
}; };
DummyStorage3.prototype.hasCapacity = function (capacity) { DummyStorage3.prototype.hasCapacity = function (capacity) {
equal(capacity, "query"); equal(capacity, "query");
if (capacity === "query") { return true; } return (capacity === 'query');
}; };
DummyStorage3.prototype.buildQuery = function (options) { DummyStorage3.prototype.buildQuery = function (options) {
equal(options.query, "a:5"); equal(options.query, "a:5");
...@@ -419,6 +435,84 @@ ...@@ -419,6 +435,84 @@
}); });
}); });
test("Limit without query", function () {
var context = this;
context.jio = jIO.createJIO({
type: "index2",
database: "index2_test",
index_keys: ["a", "b"],
sub_storage: {
type: "dummystorage3"
}
});
stop();
expect(1);
DummyStorage3.prototype.put = function (id) {
return id;
};
RSVP.all([
context.jio.put("1", {"a": "55", "b": "5"}),
context.jio.put("2", {"a": "98", "b": "3"}),
context.jio.put("3", {"a": "75", "b": "1"}),
context.jio.put("8", {"a": "43", "b": "7"}),
context.jio.put("6", {"a": "21", "b": "2"})
])
.then(function () {
return context.jio.allDocs({limit: 3});
})
.then(function (result) {
equal(result.data.total_rows, 3);
})
.fail(function (error) {
console.log(error);
})
.always(function () {
start();
});
});
test("Limit with query", function () {
var context = this;
context.jio = jIO.createJIO({
type: "index2",
database: "index2_test",
index_keys: ["a", "b"],
sub_storage: {
type: "dummystorage3"
}
});
stop();
expect(1);
DummyStorage3.prototype.put = function (id) {
return id;
};
RSVP.all([
context.jio.put("1", {"a": "55", "b": "2"}),
context.jio.put("2", {"a": "98", "b": "2"}),
context.jio.put("3", {"a": "75", "b": "2"}),
context.jio.put("8", {"a": "43", "b": "2"}),
context.jio.put("6", {"a": "21", "b": "2"}),
context.jio.put("16", {"a": "39", "b": "2"}),
context.jio.put("11", {"a": "16", "b": "3"})
])
.then(function () {
return context.jio.allDocs({limit: 4, query: "b:2"});
})
.then(function (result) {
equal(result.data.total_rows, 4);
})
.fail(function (error) {
console.log(error);
})
.always(function () {
start();
});
});
test("Complex queries", function () { test("Complex queries", function () {
var context = this; var context = this;
context.jio = jIO.createJIO({ context.jio = jIO.createJIO({
...@@ -513,131 +607,59 @@ ...@@ -513,131 +607,59 @@
}); });
}); });
///////////////////////////////////////////////////////////////// /* test("Index keys modified", function () {
// indexStorage2.put
/////////////////////////////////////////////////////////////////
module("indexStorage2.put", {
setup: function () {
this.jio = jIO.createJIO({
type: "index2",
database: "index2_test",
index_keys: ["name", "user"],
sub_storage: {
type: "dummystorage3"
}
});
},
teardown: function () {
deleteIndexedDB(this.jio);
}
});
test("spy index usage", function () {
var context = this; var context = this;
context.jio = jIO.createJIO({
type: "index2",
database: "index2_test",
index_keys: ["a"],
sub_storage: {
type: "dummystorage3"
}
});
stop(); stop();
expect(22); expect(5);
DummyStorage3.prototype.put = function (id) { DummyStorage3.prototype.put = function (id, value) {
equal(id, "32");
deepEqual(value, {a: "3", b: "2"});
return id; return id;
}; };
deleteIndexedDB(context.jio) context.jio.put("32", {"a": "3", "b": "2"})
.then(function () { .then(function () {
context.spy_open = sinon.spy(indexedDB, "open"); return context.jio.allDocs({query: 'a: "3"'});
context.spy_create_store = sinon.spy(IDBDatabase.prototype, })
"createObjectStore"); .then(function (result) {
context.spy_transaction = sinon.spy(IDBDatabase.prototype, deepEqual(result.data.rows[0], {"id": "32", "value": {}});
"transaction");
context.spy_store = sinon.spy(IDBTransaction.prototype, "objectStore");
context.spy_put = sinon.spy(IDBObjectStore.prototype, "put");
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");
context.spy_key_range = sinon.spy(IDBKeyRange, "only");
return context.jio.put("foo", {"name": "foo", "user": "bar"});
}) })
.then(function () { .then(function () {
context.jio = jIO.createJIO({
ok(context.spy_open.calledOnce, "open count " + type: "index2",
context.spy_open.callCount); database: "index2_test",
equal(context.spy_open.firstCall.args[0], "jio:index2_test", index_keys: ["b"],
"open first argument"); sub_storage: {
type: "dummystorage3"
equal(context.spy_create_store.callCount, 1, }
"createObjectStore count"); });
equal(context.spy_create_store.firstCall.args[0], "index-store",
"first createObjectStore first argument");
deepEqual(context.spy_create_store.firstCall.args[1],
{keyPath: "id", autoIncrement: false},
"first createObjectStore second argument");
equal(context.spy_create_index.callCount, 2, "createIndex count");
equal(context.spy_create_index.firstCall.args[0], "Index-name",
"first createIndex first argument");
equal(context.spy_create_index.firstCall.args[1], "doc.name",
"first createIndex second argument");
deepEqual(context.spy_create_index.firstCall.args[2], {unique: false},
"first createIndex third argument");
equal(context.spy_create_index.secondCall.args[0], "Index-user",
"second createIndex first argument");
equal(context.spy_create_index.secondCall.args[1], "doc.user",
"second createIndex second argument");
deepEqual(context.spy_create_index.secondCall.args[2],
{unique: false},
"second createIndex third argument");
ok(context.spy_transaction.calledOnce, "transaction count " +
context.spy_transaction.callCount);
deepEqual(context.spy_transaction.firstCall.args[0], ["index-store"],
"transaction first argument");
equal(context.spy_transaction.firstCall.args[1], "readwrite",
"transaction second argument");
ok(context.spy_store.calledOnce, "store count " +
context.spy_store.callCount);
deepEqual(context.spy_store.firstCall.args[0], "index-store",
"store first argument");
ok(context.spy_put.calledOnce, "put count " +
context.spy_put.callCount);
deepEqual(context.spy_put.firstCall.args[0],
{"id": "foo", doc: {name: "foo", user: "bar"}},
"put first argument");
ok(!context.spy_index.called, "index count " +
context.spy_index.callCount);
ok(!context.spy_cursor.called, "cursor count " +
context.spy_cursor.callCount);
ok(!context.spy_key_range.called, "key range count " +
context.spy_key_range.callCount);
}) })
.fail(function (error) { .then(function () {
ok(false, error); console.log(context.jio.__storage._index_keys);
return context.jio.put("32", {"a": "3", "b": "2"});
}) })
.always(function () { .then(function () {
var i, return context.jio.allDocs({query: 'b: "2"'});
spy_list = ['spy_open', 'spy_create_store', 'spy_transaction', })
'spy_store', 'spy_put', 'spy_index', 'spy_create_index', .then(function (result) {
'spy_cursor', 'spy_key_range']; deepEqual(result.data.rows[0], {"id": "32", "value": {}});
for (i = 0; i < spy_list.length; i += 1) { })
if (context.hasOwnProperty(spy_list[i])) { .fail(function (error) {
context[spy_list[i]].restore(); console.log(error);
delete context[spy_list[i]];
}
}
}) })
.always(function () { .always(function () {
start(); start();
}); });
}); });*/
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// IndexStorage2.getAttachment // IndexStorage2.getAttachment
...@@ -747,5 +769,4 @@ ...@@ -747,5 +769,4 @@
}); });
}); });
}(jIO, QUnit, indexedDB, sinon, IDBDatabase, Blob, }(jIO, QUnit, indexedDB, Blob));
IDBTransaction, IDBIndex, IDBObjectStore, IDBKeyRange)); \ No newline at end of file
\ No newline at end of file
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