/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ /*global newClass: true, sortFunction: true, parseStringToObject: true, _export: true, stringEscapeRegexpCharacters: true, deepClone: true */ /** * The query to use to filter a list of objects. * This is an abstract class. * * @class Query * @constructor */ var Query = newClass(function () { var that = this, emptyFunction = function () {}; /** * Filter the item list with matching item only * * @method exec * @param {Array} item_list The list of object * @param {Object} [option] Some operation option * @param {String} [option.wildcard_character="%"] The wildcard character * @param {Array} [option.select_list] A object keys to retrieve * @param {Array} [option.sort_on] Couples of object keys and "ascending" * or "descending" * @param {Array} [option.limit] Couple of integer, first is an index and * second is the length. */ that.exec = function (item_list, option) { var i = 0; while (i < item_list.length) { if (!that.match(item_list[i], option.wildcard_character)) { item_list.splice(i, 1); } else { i += 1; } } if (option.sort_on) { Query.sortOn(option.sort_on, item_list); } if (option.limit) { Query.limit(option.limit, item_list); } Query.select(option.select_list || [], item_list); }; /** * Test if an item matches this query * * @method match * @param {Object} item The object to test * @return {Boolean} true if match, false otherwise */ that.match = function (item, wildcard_character) { return true; }; /** * The recursive parser. * * @method recParse * @private * @param {Object} object The object shared in the parse process * @param {Object} options Some options usable in the parseMethods * @return {Any} The parser result */ function recParse(object, option) { var i, query = object.parsed; if (query.type === "complex") { for (i = 0; i < query.query_list.length; i += 1) { object.parsed = query.query_list[i]; recParse(object, option); query.query_list[i] = object.parsed; } object.parsed = query; that.onParseComplexQuery(object, option); } else if (query.type === "simple") { that.onParseSimpleQuery(object, option); } } /** * Browse the Query in deep calling parser method in each step. * * `onParseStart` is called first, on end `onParseEnd` is called. * It starts from the simple queries at the bottom of the tree calling the * parser method `onParseSimpleQuery`, and go up calling the * `onParseComplexQuery` method. * * @method parse * @param {Object} option Any options you want (except 'parsed') * @return {Any} The parse result */ that.parse = function (option) { var object; object = {"parsed": JSON.parse(JSON.stringify(that.serialized()))}; that.onParseStart(object, option); recParse(object, option); that.onParseEnd(object, option); return object.parsed; }; /** * Called before parsing the query. Must be overridden! * * @method onParseStart * @param {Object} object The object shared in the parse process * @param {Object} option Some option gave in parse() */ that.onParseStart = emptyFunction; /** * Called when parsing a simple query. Must be overridden! * * @method onParseSimpleQuery * @param {Object} object The object shared in the parse process * @param {Object} option Some option gave in parse() */ that.onParseSimpleQuery = emptyFunction; /** * Called when parsing a complex query. Must be overridden! * * @method onParseComplexQuery * @param {Object} object The object shared in the parse process * @param {Object} option Some option gave in parse() */ that.onParseComplexQuery = emptyFunction; /** * Called after parsing the query. Must be overridden! * * @method onParseEnd * @param {Object} object The object shared in the parse process * @param {Object} option Some option gave in parse() */ that.onParseEnd = emptyFunction; /** * Convert this query to a parsable string. * * @method toString * @return {String} The string version of this query */ that.toString = function () { return ""; }; /** * Convert this query to an jsonable object in order to be remake thanks to * QueryFactory class. * * @method serialized * @return {Object} The jsonable object */ that.serialized = function () { return undefined; }; }, {"static_methods": { /** * Filter a list of items, modifying them to select only wanted keys. If * `clone` is true, then the method will act on a cloned list. * * @method select * @static * @param {Array} select_option Key list to keep * @param {Array} list The item list to filter * @param {Boolean} [clone=false] If true, modifies a clone of the list * @return {Array} The filtered list */ "select": function (select_option, list, clone) { var i, j, new_item; if (clone) { list = deepClone(list); } for (i = 0; i < list.length; i += 1) { new_item = {}; for (j = 0; j < select_option.length; j += 1) { new_item[select_option[j]] = list[i][select_option[j]]; } for (j in new_item) { if (new_item.hasOwnProperty(j)) { list[i] = new_item; break; } } } return list; }, /** * Sort a list of items, according to keys and directions. If `clone` is true, * then the method will act on a cloned list. * * @method sortOn * @static * @param {Array} sort_on_option List of couples [key, direction] * @param {Array} list The item list to sort * @param {Boolean} [clone=false] If true, modifies a clone of the list * @return {Array} The filtered list */ "sortOn": function (sort_on_option, list, clone) { var sort_index; if (clone) { list = deepClone(list); } for (sort_index = sort_on_option.length - 1; sort_index >= 0; sort_index -= 1) { list.sort(sortFunction( sort_on_option[sort_index][0], sort_on_option[sort_index][1] )); } return list; }, /** * Limit a list of items, according to index and length. If `clone` is true, * then the method will act on a cloned list. * * @method limit * @static * @param {Array} limit_option A couple [from, length] * @param {Array} list The item list to limit * @param {Boolean} [clone=false] If true, modifies a clone of the list * @return {Array} The filtered list */ "limit": function (limit_option, list, clone) { if (clone) { list = deepClone(list); } list.splice(0, limit_option[0]); if (limit_option[1]) { list.splice(limit_option[1]); } return list; }, /** * Parse a text request to a json query object tree * * @method parseStringToObject * @static * @param {String} string The string to parse * @return {Object} The json query tree */ "parseStringToObject": parseStringToObject, /** * Convert a search text to a regexp. * * @method convertStringToRegExp * @static * @param {String} string The string to convert * @param {String} [wildcard_character=undefined] The wildcard chararter * @return {RegExp} The search text regexp */ "convertStringToRegExp": function (string, wildcard_character) { return new RegExp("^" + stringEscapeRegexpCharacters(string).replace( stringEscapeRegexpCharacters(wildcard_character), '.*' ) + "$"); } }}); _export("Query", Query);