Commit 44a20b19 authored by Marco Mariani's avatar Marco Mariani

Merge branch 'async-queries' into keys-jiodate-async

Conflicts:
	complex_queries.js
	src/jio.storage/localstorage.js
	src/queries/core/simplequery.js
parents f3e3a9f0 bf46a5d5
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
return module(exports); return module(exports);
} }
window.complex_queries = {}; window.complex_queries = {};
module(window.complex_queries); module(window.complex_queries, RSVP);
}(['exports'], function (to_export) { }(['exports'], function (to_export, RSVP) {
"use strict"; "use strict";
/** /**
...@@ -748,7 +748,7 @@ var query_class_dict = {}; ...@@ -748,7 +748,7 @@ var query_class_dict = {};
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global Query: true, query_class_dict: true, inherits: true, /*global Query: true, query_class_dict: true, inherits: true,
_export: true, QueryFactory: true */ _export, QueryFactory, RSVP, sequence */
/** /**
* The ComplexQuery inherits from Query, and compares one or several metadata * The ComplexQuery inherits from Query, and compares one or several metadata
...@@ -809,8 +809,7 @@ ComplexQuery.prototype.toString = function () { ...@@ -809,8 +809,7 @@ ComplexQuery.prototype.toString = function () {
str_list.push(query.toString()); str_list.push(query.toString());
str_list.push(this_operator); str_list.push(this_operator);
}); });
str_list.pop(); // remove last operator str_list[str_list.length - 1] = ")"; // replace last operator
str_list.push(")");
return str_list.join(" "); return str_list.join(" ");
}; };
...@@ -839,13 +838,41 @@ ComplexQuery.prototype.serialized = function () { ...@@ -839,13 +838,41 @@ ComplexQuery.prototype.serialized = function () {
* @return {Boolean} true if all match, false otherwise * @return {Boolean} true if all match, false otherwise
*/ */
ComplexQuery.prototype.AND = function (item, wildcard_character) { ComplexQuery.prototype.AND = function (item, wildcard_character) {
var j, promises = [];
for (j = 0; j < this.query_list.length; j += 1) {
promises.push(this.query_list[j].match(item, wildcard_character));
}
function cancel() {
var i; var i;
for (i = 0; i < this.query_list.length; i += 1) { for (i = 0; i < promises.length; i += 1) {
if (!this.query_list[i].match(item, wildcard_character)) { if (typeof promises.cancel === 'function') {
return false; promises.cancel();
} }
} }
return true; }
return new RSVP.Promise(function (resolve, reject) {
var i, count = 0;
function resolver(value) {
if (!value) {
resolve(false);
}
count += 1;
if (count === promises.length) {
resolve(true);
}
}
function rejecter(err) {
reject(err);
cancel();
}
for (i = 0; i < promises.length; i += 1) {
promises[i].then(resolver, rejecter);
}
}, cancel);
}; };
/** /**
...@@ -858,13 +885,41 @@ ComplexQuery.prototype.AND = function (item, wildcard_character) { ...@@ -858,13 +885,41 @@ ComplexQuery.prototype.AND = function (item, wildcard_character) {
* @return {Boolean} true if one match, false otherwise * @return {Boolean} true if one match, false otherwise
*/ */
ComplexQuery.prototype.OR = function (item, wildcard_character) { ComplexQuery.prototype.OR = function (item, wildcard_character) {
var j, promises = [];
for (j = 0; j < this.query_list.length; j += 1) {
promises.push(this.query_list[j].match(item, wildcard_character));
}
function cancel() {
var i; var i;
for (i = 0; i < this.query_list.length; i += 1) { for (i = 0; i < promises.length; i += 1) {
if (this.query_list[i].match(item, wildcard_character)) { if (typeof promises.cancel === 'function') {
return true; promises.cancel();
} }
} }
return false; }
return new RSVP.Promise(function (resolve, reject) {
var i, count = 0;
function resolver(value) {
if (value) {
resolve(true);
}
count += 1;
if (count === promises.length) {
resolve(false);
}
}
function rejecter(err) {
reject(err);
cancel();
}
for (i = 0; i < promises.length; i += 1) {
promises[i].then(resolver, rejecter);
}
}, cancel);
}; };
/** /**
...@@ -877,7 +932,11 @@ ComplexQuery.prototype.OR = function (item, wildcard_character) { ...@@ -877,7 +932,11 @@ ComplexQuery.prototype.OR = function (item, wildcard_character) {
* @return {Boolean} true if one match, false otherwise * @return {Boolean} true if one match, false otherwise
*/ */
ComplexQuery.prototype.NOT = function (item, wildcard_character) { ComplexQuery.prototype.NOT = function (item, wildcard_character) {
return !this.query_list[0].match(item, wildcard_character); return sequence([function () {
return this.query_list[0].match(item, wildcard_character);
}, function (answer) {
return !answer;
}]);
}; };
query_class_dict.complex = ComplexQuery; query_class_dict.complex = ComplexQuery;
...@@ -887,7 +946,7 @@ _export("ComplexQuery", ComplexQuery); ...@@ -887,7 +946,7 @@ _export("ComplexQuery", ComplexQuery);
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global parseStringToObject: true, emptyFunction: true, sortOn: true, limit: /*global parseStringToObject: true, emptyFunction: true, sortOn: true, limit:
true, select: true, _export: true, stringEscapeRegexpCharacters: true, true, select: true, _export: true, stringEscapeRegexpCharacters: true,
deepClone: true */ deepClone, RSVP, sequence */
/** /**
* The query to use to filter a list of objects. * The query to use to filter a list of objects.
...@@ -950,7 +1009,7 @@ function Query() { ...@@ -950,7 +1009,7 @@ function Query() {
* second is the length. * second is the length.
*/ */
Query.prototype.exec = function (item_list, option) { Query.prototype.exec = function (item_list, option) {
var i = 0; var i, promises = [];
if (!Array.isArray(item_list)) { if (!Array.isArray(item_list)) {
throw new TypeError("Query().exec(): Argument 1 is not of type 'array'"); throw new TypeError("Query().exec(): Argument 1 is not of type 'array'");
} }
...@@ -964,20 +1023,34 @@ Query.prototype.exec = function (item_list, option) { ...@@ -964,20 +1023,34 @@ Query.prototype.exec = function (item_list, option) {
if (option.wildcard_character === undefined) { if (option.wildcard_character === undefined) {
option.wildcard_character = '%'; option.wildcard_character = '%';
} }
while (i < item_list.length) { for (i = 0; i < item_list.length; i += 1) {
if (!item_list[i] || !this.match(item_list[i], option.wildcard_character)) { if (!item_list[i]) {
item_list.splice(i, 1); promises.push(RSVP.resolve(false));
} else { } else {
i += 1; promises.push(this.match(item_list[i], option.wildcard_character));
}
}
return sequence([function () {
return RSVP.all(promises);
}, function (answers) {
var j;
for (j = answers.length - 1; j >= 0; j -= 1) {
if (!answers[j]) {
item_list.splice(j, 1);
} }
} }
if (option.sort_on) { if (option.sort_on) {
sortOn(option.sort_on, item_list); return sortOn(option.sort_on, item_list);
} }
}, function () {
if (option.limit) { if (option.limit) {
limit(option.limit, item_list); return limit(option.limit, item_list);
} }
select(option.select_list || [], item_list); }, function () {
return select(option.select_list || [], item_list);
}, function () {
return item_list;
}]);
}; };
/** /**
...@@ -989,7 +1062,7 @@ Query.prototype.exec = function (item_list, option) { ...@@ -989,7 +1062,7 @@ Query.prototype.exec = function (item_list, option) {
* @return {Boolean} true if match, false otherwise * @return {Boolean} true if match, false otherwise
*/ */
Query.prototype.match = function () { Query.prototype.match = function () {
return true; return RSVP.resolve(true);
}; };
...@@ -1015,24 +1088,39 @@ Query.prototype.parse = function (option) { ...@@ -1015,24 +1088,39 @@ Query.prototype.parse = function (option) {
* @return {Any} The parser result * @return {Any} The parser result
*/ */
function recParse(object, option) { function recParse(object, option) {
var i, query = object.parsed; var query = object.parsed;
if (query.type === "complex") { if (query.type === "complex") {
for (i = 0; i < query.query_list.length; i += 1) { return sequence([function () {
return sequence(query.query_list.map(function (v, i) {
/*jslint unparam: true */
return function () {
sequence([function () {
object.parsed = query.query_list[i]; object.parsed = query.query_list[i];
recParse(object, option); return recParse(object, option);
}, function () {
query.query_list[i] = object.parsed; query.query_list[i] = object.parsed;
} }]);
};
}));
}, function () {
object.parsed = query; object.parsed = query;
that.onParseComplexQuery(object, option); return that.onParseComplexQuery(object, option);
} else if (query.type === "simple") { }]);
that.onParseSimpleQuery(object, option); }
if (query.type === "simple") {
return that.onParseSimpleQuery(object, option);
} }
} }
object = {"parsed": JSON.parse(JSON.stringify(that.serialized()))}; object = {"parsed": JSON.parse(JSON.stringify(that.serialized()))};
that.onParseStart(object, option); return sequence([function () {
recParse(object, option); return that.onParseStart(object, option);
that.onParseEnd(object, option); }, function () {
return recParse(object, option);
}, function () {
return that.onParseEnd(object, option);
}, function () {
return object.parsed; return object.parsed;
}]);
}; };
/** /**
...@@ -1123,7 +1211,7 @@ _export("objectToSearchText", objectToSearchText); ...@@ -1123,7 +1211,7 @@ _export("objectToSearchText", objectToSearchText);
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global Query: true, inherits: true, query_class_dict: true, _export: true, /*global Query: true, inherits: true, query_class_dict: true, _export: true,
convertStringToRegExp: true */ convertStringToRegExp, RSVP */
var checkKeySchema = function (key_schema) { var checkKeySchema = function (key_schema) {
var prop; var prop;
...@@ -1320,15 +1408,16 @@ SimpleQuery.prototype["="] = function (object_value, comparison_value, ...@@ -1320,15 +1408,16 @@ SimpleQuery.prototype["="] = function (object_value, comparison_value,
} }
if (comparison_value === undefined) { if (comparison_value === undefined) {
if (value === undefined) { if (value === undefined) {
return true; return RSVP.resolve(true);
} }
return false; return RSVP.resolve(false);
} }
if (value === undefined) { if (value === undefined) {
return false; return RSVP.resolve(false);
} }
if (value.cmp !== undefined) { if (value.cmp !== undefined) {
return value.cmp(comparison_value) === 0; return RSVP.resolve(value.cmp(comparison_value,
wildcard_character) === 0);
} }
if ( if (
convertStringToRegExp( convertStringToRegExp(
...@@ -1336,10 +1425,10 @@ SimpleQuery.prototype["="] = function (object_value, comparison_value, ...@@ -1336,10 +1425,10 @@ SimpleQuery.prototype["="] = function (object_value, comparison_value,
wildcard_character wildcard_character
).test(value.toString()) ).test(value.toString())
) { ) {
return true; return RSVP.resolve(true);
} }
} }
return false; return RSVP.resolve(false);
}; };
/** /**
...@@ -1364,15 +1453,16 @@ SimpleQuery.prototype["!="] = function (object_value, comparison_value, ...@@ -1364,15 +1453,16 @@ SimpleQuery.prototype["!="] = function (object_value, comparison_value,
} }
if (comparison_value === undefined) { if (comparison_value === undefined) {
if (value === undefined) { if (value === undefined) {
return false; return RSVP.resolve(false);
} }
return true; return RSVP.resolve(true);
} }
if (value === undefined) { if (value === undefined) {
return true; return RSVP.resolve(true);
} }
if (value.cmp !== undefined) { if (value.cmp !== undefined) {
return value.cmp(comparison_value) !== 0; return RSVP.resolve(value.cmp(comparison_value,
wildcard_character) !== 0);
} }
if ( if (
convertStringToRegExp( convertStringToRegExp(
...@@ -1380,10 +1470,10 @@ SimpleQuery.prototype["!="] = function (object_value, comparison_value, ...@@ -1380,10 +1470,10 @@ SimpleQuery.prototype["!="] = function (object_value, comparison_value,
wildcard_character wildcard_character
).test(value.toString()) ).test(value.toString())
) { ) {
return false; return RSVP.resolve(false);
} }
} }
return true; return RSVP.resolve(true);
}; };
/** /**
...@@ -1404,12 +1494,12 @@ SimpleQuery.prototype["<"] = function (object_value, comparison_value) { ...@@ -1404,12 +1494,12 @@ SimpleQuery.prototype["<"] = function (object_value, comparison_value) {
value = value.content; value = value.content;
} }
if (value === undefined || comparison_value === undefined) { if (value === undefined || comparison_value === undefined) {
return false; return RSVP.resolve(false);
} }
if (value.cmp !== undefined) { if (value.cmp !== undefined) {
return value.cmp(comparison_value) < 0; return RSVP.resolve(value.cmp(comparison_value) < 0);
} }
return value < comparison_value; return RSVP.resolve(value < comparison_value);
}; };
/** /**
...@@ -1431,12 +1521,12 @@ SimpleQuery.prototype["<="] = function (object_value, comparison_value) { ...@@ -1431,12 +1521,12 @@ SimpleQuery.prototype["<="] = function (object_value, comparison_value) {
value = value.content; value = value.content;
} }
if (value === undefined || comparison_value === undefined) { if (value === undefined || comparison_value === undefined) {
return false; return RSVP.resolve(false);
} }
if (value.cmp !== undefined) { if (value.cmp !== undefined) {
return value.cmp(comparison_value) <= 0; return RSVP.resolve(value.cmp(comparison_value) <= 0);
} }
return value <= comparison_value; return RSVP.resolve(value <= comparison_value);
}; };
/** /**
...@@ -1458,12 +1548,12 @@ SimpleQuery.prototype[">"] = function (object_value, comparison_value) { ...@@ -1458,12 +1548,12 @@ SimpleQuery.prototype[">"] = function (object_value, comparison_value) {
value = value.content; value = value.content;
} }
if (value === undefined || comparison_value === undefined) { if (value === undefined || comparison_value === undefined) {
return false; return RSVP.resolve(false);
} }
if (value.cmp !== undefined) { if (value.cmp !== undefined) {
return value.cmp(comparison_value) > 0; return RSVP.resolve(value.cmp(comparison_value) > 0);
} }
return value > comparison_value; return RSVP.resolve(value > comparison_value);
}; };
/** /**
...@@ -1485,12 +1575,12 @@ SimpleQuery.prototype[">="] = function (object_value, comparison_value) { ...@@ -1485,12 +1575,12 @@ SimpleQuery.prototype[">="] = function (object_value, comparison_value) {
value = value.content; value = value.content;
} }
if (value === undefined || comparison_value === undefined) { if (value === undefined || comparison_value === undefined) {
return false; return RSVP.resolve(false);
} }
if (value.cmp !== undefined) { if (value.cmp !== undefined) {
return value.cmp(comparison_value) >= 0; return RSVP.resolve(value.cmp(comparison_value) >= 0);
} }
return value >= comparison_value; return RSVP.resolve(value >= comparison_value);
}; };
query_class_dict.simple = SimpleQuery; query_class_dict.simple = SimpleQuery;
...@@ -1498,7 +1588,7 @@ query_class_dict.simple = SimpleQuery; ...@@ -1498,7 +1588,7 @@ query_class_dict.simple = SimpleQuery;
_export("SimpleQuery", SimpleQuery); _export("SimpleQuery", SimpleQuery);
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global _export: true */ /*global _export, RSVP */
/** /**
* Escapes regexp special chars from a string. * Escapes regexp special chars from a string.
...@@ -1787,6 +1877,46 @@ function convertStringToRegExp(string, wildcard_character) { ...@@ -1787,6 +1877,46 @@ function convertStringToRegExp(string, wildcard_character) {
_export('convertStringToRegExp', convertStringToRegExp); _export('convertStringToRegExp', convertStringToRegExp);
/**
* sequence(thens): Promise
*
* Executes a sequence of *then* callbacks. It acts like
* `smth().then(callback).then(callback)...`. The first callback is called with
* no parameter.
*
* Elements of `thens` array can be a function or an array contaning at most
* three *then* callbacks: *onFulfilled*, *onRejected*, *onNotified*.
*
* When `cancel()` is executed, each then promises are cancelled at the same
* time.
*
* @param {Array} thens An array of *then* callbacks
* @return {Promise} A new promise
*/
function sequence(thens) {
var promises = [];
return new RSVP.Promise(function (resolve, reject, notify) {
var i;
promises[0] = new RSVP.Promise(function (resolve) {
resolve();
});
for (i = 0; i < thens.length; i += 1) {
if (Array.isArray(thens[i])) {
promises[i + 1] = promises[i].
then(thens[i][0], thens[i][1], thens[i][2]);
} else {
promises[i + 1] = promises[i].then(thens[i]);
}
}
promises[i].then(resolve, reject, notify);
}, function () {
var i;
for (i = 0; i < promises.length; i += 1) {
promises[i].cancel();
}
});
}
return to_export; return to_export;
})); }));
...@@ -719,7 +719,7 @@ ...@@ -719,7 +719,7 @@
} }
} }
complex_queries.QueryFactory.create(option.query || ''). complex_queries.QueryFactory.create(option.query || '').
exec(db, option); exec(db, option).then(function () {
for (i = 0; i < db.length; i += 1) { for (i = 0; i < db.length; i += 1) {
id = db[i]._id; id = db[i]._id;
if (delete_id) { if (delete_id) {
...@@ -741,6 +741,7 @@ ...@@ -741,6 +741,7 @@
} }
} }
command.success(200, {"data": {"total_rows": db.length, "rows": db}}); command.success(200, {"data": {"total_rows": db.length, "rows": db}});
});
}, function (err) { }, function (err) {
if (err.status === 404) { if (err.status === 404) {
return command.success(200, {"data": {"total_rows": 0, "rows": []}}); return command.success(200, {"data": {"total_rows": 0, "rows": []}});
......
...@@ -448,7 +448,7 @@ ...@@ -448,7 +448,7 @@
} }
complex_queries.QueryFactory.create(options.query || "", complex_queries.QueryFactory.create(options.query || "",
this._key_schema). this._key_schema).
exec(document_list, options); exec(document_list, options).then(function () {
document_list = document_list.map(function (value) { document_list = document_list.map(function (value) {
var o = { var o = {
"id": value._id, "id": value._id,
...@@ -468,6 +468,7 @@ ...@@ -468,6 +468,7 @@
"total_rows": document_list.length, "total_rows": document_list.length,
"rows": document_list "rows": document_list
}}); }});
});
} }
}; };
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
return module(exports); return module(exports);
} }
window.complex_queries = {}; window.complex_queries = {};
module(window.complex_queries); module(window.complex_queries, RSVP);
}(['exports'], function (to_export) { }(['exports'], function (to_export, RSVP) {
"use strict"; "use strict";
/** /**
......
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global Query: true, query_class_dict: true, inherits: true, /*global Query: true, query_class_dict: true, inherits: true,
_export: true, QueryFactory: true */ _export, QueryFactory, RSVP, sequence */
/** /**
* The ComplexQuery inherits from Query, and compares one or several metadata * The ComplexQuery inherits from Query, and compares one or several metadata
...@@ -61,8 +61,7 @@ ComplexQuery.prototype.toString = function () { ...@@ -61,8 +61,7 @@ ComplexQuery.prototype.toString = function () {
str_list.push(query.toString()); str_list.push(query.toString());
str_list.push(this_operator); str_list.push(this_operator);
}); });
str_list.pop(); // remove last operator str_list[str_list.length - 1] = ")"; // replace last operator
str_list.push(")");
return str_list.join(" "); return str_list.join(" ");
}; };
...@@ -91,13 +90,41 @@ ComplexQuery.prototype.serialized = function () { ...@@ -91,13 +90,41 @@ ComplexQuery.prototype.serialized = function () {
* @return {Boolean} true if all match, false otherwise * @return {Boolean} true if all match, false otherwise
*/ */
ComplexQuery.prototype.AND = function (item, wildcard_character) { ComplexQuery.prototype.AND = function (item, wildcard_character) {
var j, promises = [];
for (j = 0; j < this.query_list.length; j += 1) {
promises.push(this.query_list[j].match(item, wildcard_character));
}
function cancel() {
var i; var i;
for (i = 0; i < this.query_list.length; i += 1) { for (i = 0; i < promises.length; i += 1) {
if (!this.query_list[i].match(item, wildcard_character)) { if (typeof promises.cancel === 'function') {
return false; promises.cancel();
}
}
}
return new RSVP.Promise(function (resolve, reject) {
var i, count = 0;
function resolver(value) {
if (!value) {
resolve(false);
} }
count += 1;
if (count === promises.length) {
resolve(true);
}
}
function rejecter(err) {
reject(err);
cancel();
}
for (i = 0; i < promises.length; i += 1) {
promises[i].then(resolver, rejecter);
} }
return true; }, cancel);
}; };
/** /**
...@@ -110,13 +137,41 @@ ComplexQuery.prototype.AND = function (item, wildcard_character) { ...@@ -110,13 +137,41 @@ ComplexQuery.prototype.AND = function (item, wildcard_character) {
* @return {Boolean} true if one match, false otherwise * @return {Boolean} true if one match, false otherwise
*/ */
ComplexQuery.prototype.OR = function (item, wildcard_character) { ComplexQuery.prototype.OR = function (item, wildcard_character) {
var j, promises = [];
for (j = 0; j < this.query_list.length; j += 1) {
promises.push(this.query_list[j].match(item, wildcard_character));
}
function cancel() {
var i; var i;
for (i = 0; i < this.query_list.length; i += 1) { for (i = 0; i < promises.length; i += 1) {
if (this.query_list[i].match(item, wildcard_character)) { if (typeof promises.cancel === 'function') {
return true; promises.cancel();
}
}
}
return new RSVP.Promise(function (resolve, reject) {
var i, count = 0;
function resolver(value) {
if (value) {
resolve(true);
} }
count += 1;
if (count === promises.length) {
resolve(false);
}
}
function rejecter(err) {
reject(err);
cancel();
}
for (i = 0; i < promises.length; i += 1) {
promises[i].then(resolver, rejecter);
} }
return false; }, cancel);
}; };
/** /**
...@@ -129,7 +184,11 @@ ComplexQuery.prototype.OR = function (item, wildcard_character) { ...@@ -129,7 +184,11 @@ ComplexQuery.prototype.OR = function (item, wildcard_character) {
* @return {Boolean} true if one match, false otherwise * @return {Boolean} true if one match, false otherwise
*/ */
ComplexQuery.prototype.NOT = function (item, wildcard_character) { ComplexQuery.prototype.NOT = function (item, wildcard_character) {
return !this.query_list[0].match(item, wildcard_character); return sequence([function () {
return this.query_list[0].match(item, wildcard_character);
}, function (answer) {
return !answer;
}]);
}; };
query_class_dict.complex = ComplexQuery; query_class_dict.complex = ComplexQuery;
......
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global parseStringToObject: true, emptyFunction: true, sortOn: true, limit: /*global parseStringToObject: true, emptyFunction: true, sortOn: true, limit:
true, select: true, _export: true, stringEscapeRegexpCharacters: true, true, select: true, _export: true, stringEscapeRegexpCharacters: true,
deepClone: true */ deepClone, RSVP, sequence */
/** /**
* The query to use to filter a list of objects. * The query to use to filter a list of objects.
...@@ -64,7 +64,7 @@ function Query() { ...@@ -64,7 +64,7 @@ function Query() {
* second is the length. * second is the length.
*/ */
Query.prototype.exec = function (item_list, option) { Query.prototype.exec = function (item_list, option) {
var i = 0; var i, promises = [];
if (!Array.isArray(item_list)) { if (!Array.isArray(item_list)) {
throw new TypeError("Query().exec(): Argument 1 is not of type 'array'"); throw new TypeError("Query().exec(): Argument 1 is not of type 'array'");
} }
...@@ -78,20 +78,34 @@ Query.prototype.exec = function (item_list, option) { ...@@ -78,20 +78,34 @@ Query.prototype.exec = function (item_list, option) {
if (option.wildcard_character === undefined) { if (option.wildcard_character === undefined) {
option.wildcard_character = '%'; option.wildcard_character = '%';
} }
while (i < item_list.length) { for (i = 0; i < item_list.length; i += 1) {
if (!item_list[i] || !this.match(item_list[i], option.wildcard_character)) { if (!item_list[i]) {
item_list.splice(i, 1); promises.push(RSVP.resolve(false));
} else { } else {
i += 1; promises.push(this.match(item_list[i], option.wildcard_character));
}
}
return sequence([function () {
return RSVP.all(promises);
}, function (answers) {
var j;
for (j = answers.length - 1; j >= 0; j -= 1) {
if (!answers[j]) {
item_list.splice(j, 1);
} }
} }
if (option.sort_on) { if (option.sort_on) {
sortOn(option.sort_on, item_list); return sortOn(option.sort_on, item_list);
} }
}, function () {
if (option.limit) { if (option.limit) {
limit(option.limit, item_list); return limit(option.limit, item_list);
} }
select(option.select_list || [], item_list); }, function () {
return select(option.select_list || [], item_list);
}, function () {
return item_list;
}]);
}; };
/** /**
...@@ -103,7 +117,7 @@ Query.prototype.exec = function (item_list, option) { ...@@ -103,7 +117,7 @@ Query.prototype.exec = function (item_list, option) {
* @return {Boolean} true if match, false otherwise * @return {Boolean} true if match, false otherwise
*/ */
Query.prototype.match = function () { Query.prototype.match = function () {
return true; return RSVP.resolve(true);
}; };
...@@ -129,24 +143,39 @@ Query.prototype.parse = function (option) { ...@@ -129,24 +143,39 @@ Query.prototype.parse = function (option) {
* @return {Any} The parser result * @return {Any} The parser result
*/ */
function recParse(object, option) { function recParse(object, option) {
var i, query = object.parsed; var query = object.parsed;
if (query.type === "complex") { if (query.type === "complex") {
for (i = 0; i < query.query_list.length; i += 1) { return sequence([function () {
return sequence(query.query_list.map(function (v, i) {
/*jslint unparam: true */
return function () {
sequence([function () {
object.parsed = query.query_list[i]; object.parsed = query.query_list[i];
recParse(object, option); return recParse(object, option);
}, function () {
query.query_list[i] = object.parsed; query.query_list[i] = object.parsed;
} }]);
};
}));
}, function () {
object.parsed = query; object.parsed = query;
that.onParseComplexQuery(object, option); return that.onParseComplexQuery(object, option);
} else if (query.type === "simple") { }]);
that.onParseSimpleQuery(object, option); }
if (query.type === "simple") {
return that.onParseSimpleQuery(object, option);
} }
} }
object = {"parsed": JSON.parse(JSON.stringify(that.serialized()))}; object = {"parsed": JSON.parse(JSON.stringify(that.serialized()))};
that.onParseStart(object, option); return sequence([function () {
recParse(object, option); return that.onParseStart(object, option);
that.onParseEnd(object, option); }, function () {
return recParse(object, option);
}, function () {
return that.onParseEnd(object, option);
}, function () {
return object.parsed; return object.parsed;
}]);
}; };
/** /**
......
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global Query: true, inherits: true, query_class_dict: true, _export: true, /*global Query: true, inherits: true, query_class_dict: true, _export: true,
convertStringToRegExp: true */ convertStringToRegExp, RSVP */
var checkKeySchema = function (key_schema) { var checkKeySchema = function (key_schema) {
var prop; var prop;
...@@ -197,15 +197,16 @@ SimpleQuery.prototype["="] = function (object_value, comparison_value, ...@@ -197,15 +197,16 @@ SimpleQuery.prototype["="] = function (object_value, comparison_value,
} }
if (comparison_value === undefined) { if (comparison_value === undefined) {
if (value === undefined) { if (value === undefined) {
return true; return RSVP.resolve(true);
} }
return false; return RSVP.resolve(false);
} }
if (value === undefined) { if (value === undefined) {
return false; return RSVP.resolve(false);
} }
if (value.cmp !== undefined) { if (value.cmp !== undefined) {
return value.cmp(comparison_value, wildcard_character) === 0; return RSVP.resolve(value.cmp(comparison_value,
wildcard_character) === 0);
} }
if ( if (
convertStringToRegExp( convertStringToRegExp(
...@@ -213,10 +214,10 @@ SimpleQuery.prototype["="] = function (object_value, comparison_value, ...@@ -213,10 +214,10 @@ SimpleQuery.prototype["="] = function (object_value, comparison_value,
wildcard_character wildcard_character
).test(value.toString()) ).test(value.toString())
) { ) {
return true; return RSVP.resolve(true);
} }
} }
return false; return RSVP.resolve(false);
}; };
/** /**
...@@ -241,15 +242,16 @@ SimpleQuery.prototype["!="] = function (object_value, comparison_value, ...@@ -241,15 +242,16 @@ SimpleQuery.prototype["!="] = function (object_value, comparison_value,
} }
if (comparison_value === undefined) { if (comparison_value === undefined) {
if (value === undefined) { if (value === undefined) {
return false; return RSVP.resolve(false);
} }
return true; return RSVP.resolve(true);
} }
if (value === undefined) { if (value === undefined) {
return true; return RSVP.resolve(true);
} }
if (value.cmp !== undefined) { if (value.cmp !== undefined) {
return value.cmp(comparison_value, wildcard_character) !== 0; return RSVP.resolve(value.cmp(comparison_value,
wildcard_character) !== 0);
} }
if ( if (
convertStringToRegExp( convertStringToRegExp(
...@@ -257,10 +259,10 @@ SimpleQuery.prototype["!="] = function (object_value, comparison_value, ...@@ -257,10 +259,10 @@ SimpleQuery.prototype["!="] = function (object_value, comparison_value,
wildcard_character wildcard_character
).test(value.toString()) ).test(value.toString())
) { ) {
return false; return RSVP.resolve(false);
} }
} }
return true; return RSVP.resolve(true);
}; };
/** /**
...@@ -281,12 +283,12 @@ SimpleQuery.prototype["<"] = function (object_value, comparison_value) { ...@@ -281,12 +283,12 @@ SimpleQuery.prototype["<"] = function (object_value, comparison_value) {
value = value.content; value = value.content;
} }
if (value === undefined || comparison_value === undefined) { if (value === undefined || comparison_value === undefined) {
return false; return RSVP.resolve(false);
} }
if (value.cmp !== undefined) { if (value.cmp !== undefined) {
return value.cmp(comparison_value) < 0; return RSVP.resolve(value.cmp(comparison_value) < 0);
} }
return value < comparison_value; return RSVP.resolve(value < comparison_value);
}; };
/** /**
...@@ -308,12 +310,12 @@ SimpleQuery.prototype["<="] = function (object_value, comparison_value) { ...@@ -308,12 +310,12 @@ SimpleQuery.prototype["<="] = function (object_value, comparison_value) {
value = value.content; value = value.content;
} }
if (value === undefined || comparison_value === undefined) { if (value === undefined || comparison_value === undefined) {
return false; return RSVP.resolve(false);
} }
if (value.cmp !== undefined) { if (value.cmp !== undefined) {
return value.cmp(comparison_value) <= 0; return RSVP.resolve(value.cmp(comparison_value) <= 0);
} }
return value <= comparison_value; return RSVP.resolve(value <= comparison_value);
}; };
/** /**
...@@ -335,12 +337,12 @@ SimpleQuery.prototype[">"] = function (object_value, comparison_value) { ...@@ -335,12 +337,12 @@ SimpleQuery.prototype[">"] = function (object_value, comparison_value) {
value = value.content; value = value.content;
} }
if (value === undefined || comparison_value === undefined) { if (value === undefined || comparison_value === undefined) {
return false; return RSVP.resolve(false);
} }
if (value.cmp !== undefined) { if (value.cmp !== undefined) {
return value.cmp(comparison_value) > 0; return RSVP.resolve(value.cmp(comparison_value) > 0);
} }
return value > comparison_value; return RSVP.resolve(value > comparison_value);
}; };
/** /**
...@@ -362,12 +364,12 @@ SimpleQuery.prototype[">="] = function (object_value, comparison_value) { ...@@ -362,12 +364,12 @@ SimpleQuery.prototype[">="] = function (object_value, comparison_value) {
value = value.content; value = value.content;
} }
if (value === undefined || comparison_value === undefined) { if (value === undefined || comparison_value === undefined) {
return false; return RSVP.resolve(false);
} }
if (value.cmp !== undefined) { if (value.cmp !== undefined) {
return value.cmp(comparison_value) >= 0; return RSVP.resolve(value.cmp(comparison_value) >= 0);
} }
return value >= comparison_value; return RSVP.resolve(value >= comparison_value);
}; };
query_class_dict.simple = SimpleQuery; query_class_dict.simple = SimpleQuery;
......
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global _export: true */ /*global _export, RSVP */
/** /**
* Escapes regexp special chars from a string. * Escapes regexp special chars from a string.
...@@ -287,3 +287,43 @@ function convertStringToRegExp(string, wildcard_character) { ...@@ -287,3 +287,43 @@ function convertStringToRegExp(string, wildcard_character) {
} }
_export('convertStringToRegExp', convertStringToRegExp); _export('convertStringToRegExp', convertStringToRegExp);
/**
* sequence(thens): Promise
*
* Executes a sequence of *then* callbacks. It acts like
* `smth().then(callback).then(callback)...`. The first callback is called with
* no parameter.
*
* Elements of `thens` array can be a function or an array contaning at most
* three *then* callbacks: *onFulfilled*, *onRejected*, *onNotified*.
*
* When `cancel()` is executed, each then promises are cancelled at the same
* time.
*
* @param {Array} thens An array of *then* callbacks
* @return {Promise} A new promise
*/
function sequence(thens) {
var promises = [];
return new RSVP.Promise(function (resolve, reject, notify) {
var i;
promises[0] = new RSVP.Promise(function (resolve) {
resolve();
});
for (i = 0; i < thens.length; i += 1) {
if (Array.isArray(thens[i])) {
promises[i + 1] = promises[i].
then(thens[i][0], thens[i][1], thens[i][2]);
} else {
promises[i + 1] = promises[i].then(thens[i]);
}
}
promises[i].then(resolve, reject, notify);
}, function () {
var i;
for (i = 0; i < promises.length; i += 1) {
promises[i].cancel();
}
});
}
/*jslint indent: 2, maxlen: 80, nomen: true */ /*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, exports, require, module, complex_queries, window, test, ok, /*global define, exports, require, module, complex_queries, window, test, ok,
deepEqual, sinon */ deepEqual, stop, start */
// define([module_name], [dependencies], module); // define([module_name], [dependencies], module);
(function (dependencies, module) { (function (dependencies, module) {
...@@ -23,11 +23,14 @@ ...@@ -23,11 +23,14 @@
{"identifier": "a"}, {"identifier": "a"},
{"identifier": ["b", "c"]} {"identifier": ["b", "c"]}
]; ];
complex_queries.QueryFactory.create('').exec(doc_list); stop();
complex_queries.QueryFactory.create('').exec(doc_list).
then(function (doc_list) {
deepEqual(doc_list, [ deepEqual(doc_list, [
{"identifier": "a"}, {"identifier": "a"},
{"identifier": ["b", "c"]} {"identifier": ["b", "c"]}
], 'Nothing done on the list'); ], 'Nothing done on the list');
}).always(start);
}); });
test('Simple Query', function () { test('Simple Query', function () {
...@@ -35,7 +38,9 @@ ...@@ -35,7 +38,9 @@
{"identifier": "a"}, {"identifier": "a"},
{"identifier": ["b", "c"]} {"identifier": ["b", "c"]}
]; ];
complex_queries.QueryFactory.create('identifier: "a"').exec(doc_list); stop();
complex_queries.QueryFactory.create('identifier: "a"').exec(doc_list).
then(function (doc_list) {
deepEqual(doc_list, [ deepEqual(doc_list, [
{"identifier": "a"} {"identifier": "a"}
], 'Document with several identifier should be removed'); ], 'Document with several identifier should be removed');
...@@ -44,11 +49,15 @@ ...@@ -44,11 +49,15 @@
{"identifier": "a"}, {"identifier": "a"},
{"identifier": ["a", "b"]} {"identifier": ["a", "b"]}
]; ];
complex_queries.QueryFactory.create('identifier: "a"').exec(doc_list);
return complex_queries.QueryFactory.create('identifier: "a"').
exec(doc_list);
}).then(function (doc_list) {
deepEqual(doc_list, [ deepEqual(doc_list, [
{"identifier": "a"}, {"identifier": "a"},
{"identifier": ["a", "b"]} {"identifier": ["a", "b"]}
], 'Document with several identifier should be kept'); ], 'Document with several identifier should be kept');
}).always(start);
}); });
test('Complex Query', function () { test('Complex Query', function () {
...@@ -56,9 +65,10 @@ ...@@ -56,9 +65,10 @@
{"identifier": "a"}, {"identifier": "a"},
{"identifier": ["b", "c"]} {"identifier": ["b", "c"]}
]; ];
stop();
complex_queries.QueryFactory.create( complex_queries.QueryFactory.create(
'identifier: "b" AND identifier: "c"' 'identifier: "b" AND identifier: "c"'
).exec(doc_list); ).exec(doc_list).then(function (doc_list) {
deepEqual(doc_list, [ deepEqual(doc_list, [
{"identifier": ["b", "c"]} {"identifier": ["b", "c"]}
], 'Document with only one identifier should be removed'); ], 'Document with only one identifier should be removed');
...@@ -67,9 +77,10 @@ ...@@ -67,9 +77,10 @@
{"identifier": "a"}, {"identifier": "a"},
{"identifier": ["b", "c"]} {"identifier": ["b", "c"]}
]; ];
complex_queries.QueryFactory.create( return complex_queries.QueryFactory.create(
'identifier: "a" OR identifier: "c"' 'identifier: "a" OR identifier: "c"'
).exec(doc_list); ).exec(doc_list);
}).then(function (doc_list) {
deepEqual(doc_list, [ deepEqual(doc_list, [
{"identifier": "a"}, {"identifier": "a"},
{"identifier": ["b", "c"]} {"identifier": ["b", "c"]}
...@@ -79,12 +90,15 @@ ...@@ -79,12 +90,15 @@
{"identifier": "a", "title": "o"}, {"identifier": "a", "title": "o"},
{"identifier": ["b", "c"]} {"identifier": ["b", "c"]}
]; ];
complex_queries.QueryFactory.create(
return complex_queries.QueryFactory.create(
'(identifier: "a" OR identifier: "b") AND title: "o"' '(identifier: "a" OR identifier: "b") AND title: "o"'
).exec(doc_list); ).exec(doc_list);
}).then(function (doc_list) {
deepEqual(doc_list, [ deepEqual(doc_list, [
{"identifier": "a", "title": "o"} {"identifier": "a", "title": "o"}
], 'Only first document should be kept'); ], 'Only first document should be kept');
}).always(start);
}); });
test('Wildcard Character', function () { test('Wildcard Character', function () {
...@@ -93,9 +107,10 @@ ...@@ -93,9 +107,10 @@
{"identifier": "a%"}, {"identifier": "a%"},
{"identifier": ["ab", "b"]} {"identifier": ["ab", "b"]}
]; ];
stop();
complex_queries.QueryFactory.create('identifier: "a%"').exec(doc_list, { complex_queries.QueryFactory.create('identifier: "a%"').exec(doc_list, {
// "wildcard_character": "%" // default // "wildcard_character": "%" // default
}); }).then(function (doc_list) {
deepEqual(doc_list, [ deepEqual(doc_list, [
{"identifier": "a"}, {"identifier": "a"},
{"identifier": "a%"}, {"identifier": "a%"},
...@@ -107,9 +122,10 @@ ...@@ -107,9 +122,10 @@
{"identifier": "a%"}, {"identifier": "a%"},
{"identifier": ["ab", "b"]} {"identifier": ["ab", "b"]}
]; ];
complex_queries.QueryFactory.create('identifier: "a%"').exec(doc_list, {
"wildcard_character": null return complex_queries.QueryFactory.create('identifier: "a%"').
}); exec(doc_list, {"wildcard_character": null});
}).then(function (doc_list) {
deepEqual(doc_list, [ deepEqual(doc_list, [
{"identifier": "a%"} {"identifier": "a%"}
], 'Document "a%" should be kept'); ], 'Document "a%" should be kept');
...@@ -119,14 +135,15 @@ ...@@ -119,14 +135,15 @@
{"identifier": "a%"}, {"identifier": "a%"},
{"identifier": ["ab", "b"]} {"identifier": ["ab", "b"]}
]; ];
complex_queries.QueryFactory.create('identifier: "b"').exec(doc_list, { return complex_queries.QueryFactory.create('identifier: "b"').
"wildcard_character": "b" exec(doc_list, {"wildcard_character": "b"});
}); }).then(function (doc_list) {
deepEqual(doc_list, [ deepEqual(doc_list, [
{"identifier": "a"}, {"identifier": "a"},
{"identifier": "a%"}, {"identifier": "a%"},
{"identifier": ["ab", "b"]} {"identifier": ["ab", "b"]}
], 'All documents should be kept'); ], 'All documents should be kept');
}).always(start);
}); });
test("Additional Filters", function () { test("Additional Filters", function () {
...@@ -135,14 +152,16 @@ ...@@ -135,14 +152,16 @@
{"identifier": "a", "title": "f"}, {"identifier": "a", "title": "f"},
{"identifier": "b", "title": "d"} {"identifier": "b", "title": "d"}
]; ];
stop();
complex_queries.QueryFactory.create('').exec(doc_list, { complex_queries.QueryFactory.create('').exec(doc_list, {
"select_list": ["title"], "select_list": ["title"],
"limit": [2, 1], "limit": [2, 1],
"sort_on": [["identifier", "ascending"], ["title", "descending"]] "sort_on": [["identifier", "ascending"], ["title", "descending"]]
}); }).then(function (doc_list) {
deepEqual(doc_list, [ deepEqual(doc_list, [
{"title": "d"} {"title": "d"}
], 'The first document should be kept'); ], 'The first document should be kept');
}).always(start);
}); });
})); }));
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