UNPKG

query-engine

Version:

Query-Engine is a NoSQL and MongoDb compliant query engine. It can run on the server-side with Node.js, or on the client-side within web browsers

1,599 lines (1,510 loc) 53 kB
// Generated by CoffeeScript 1.6.3 (function() { var Backbone, Criteria, Hash, Pill, Query, QueryCollection, queryEngine, util, _ref, __hasProp = {}.hasOwnProperty, __slice = [].slice, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; Backbone = this.Backbone || (typeof window !== "undefined" && window !== null ? window.Backbone : void 0) || ((function() { try { return typeof require === "function" ? require('backbone') : void 0; } catch (_error) {} })()) || ((function() { try { return typeof require === "function" ? require('exoskeleton') : void 0; } catch (_error) {} })()) || null; util = { toString: function(value) { return Object.prototype.toString.call(value); }, isPlainObject: function(value) { return util.isObject(value) && value.__proto__ === Object.prototype; }, isObject: function(value) { return value && typeof value === 'object'; }, isError: function(value) { return value instanceof Error; }, isDate: function(value) { return util.toString(value) === '[object Date]'; }, isArguments: function(value) { return util.toString(value) === '[object Arguments]'; }, isFunction: function(value) { return util.toString(value) === '[object Function]'; }, isRegExp: function(value) { return util.toString(value) === '[object RegExp]'; }, isArray: function(value) { if (Array.isArray != null) { return Array.isArray(value); } else { return util.toString(value) === '[object Array]'; } }, isNumber: function(value) { return typeof value === 'number' || util.toString(value) === '[object Number]'; }, isString: function(value) { return typeof value === 'string' || util.toString(value) === '[object String]'; }, isBoolean: function(value) { return value === true || value === false || util.toString(value) === '[object Boolean]'; }, isNull: function(value) { return value === null; }, isUndefined: function(value) { return typeof value === 'undefined'; }, isDefined: function(value) { return typeof value !== 'undefined'; }, isEmpty: function(value) { return value != null; }, isObjectEmpty: function(object) { var empty, key, value; empty = true; for (key in object) { if (!__hasProp.call(object, key)) continue; value = object[key]; empty = false; break; } return empty; }, isComparable: function(value) { return util.isNumber(value) || util.isDate(value); }, isEqual: function(value1, value2) { return JSON.stringify(value1) === JSON.stringify(value2); }, clone: function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return util.shallowExtendPlainObjects.apply(util, [{}].concat(__slice.call(args))); }, extend: function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return util.shallowExtendPlainObjects.apply(util, args); }, shallowExtendPlainObjects: function() { var key, obj, objs, target, value, _i, _len; target = arguments[0], objs = 2 <= arguments.length ? __slice.call(arguments, 1) : []; for (_i = 0, _len = objs.length; _i < _len; _i++) { obj = objs[_i]; obj || (obj = {}); for (key in obj) { if (!__hasProp.call(obj, key)) continue; value = obj[key]; target[key] = value; } } return target; }, get: function(obj, key) { var result; if (obj.get != null) { result = obj.get(key); } else { result = obj[key]; } return result; }, safeRegex: function(str) { if (str === false) { return 'false'; } else if (str === true) { return 'true'; } else if (str === null) { return 'null'; } else { return (str || '').replace('(.)', '\\$1'); } }, createRegex: function(str) { return new RegExp(str, 'ig'); }, createSafeRegex: function(str) { return util.createRegex(util.safeRegex(str)); }, toArray: function(value) { var item, key, result, valueExists; result = []; valueExists = typeof value !== 'undefined'; if (valueExists) { if (util.isArray(value)) { result = value.slice(); } else if (util.isObject(value)) { for (key in value) { if (!__hasProp.call(value, key)) continue; item = value[key]; result.push(item); } } else { result.push(value); } } return result; }, toArrayGroup: function(value) { var item, key, obj, result, valueExists; result = []; valueExists = typeof value !== 'undefined'; if (valueExists) { if (util.isArray(value)) { result = value.slice(); } else if (util.isObject(value)) { for (key in value) { if (!__hasProp.call(value, key)) continue; item = value[key]; obj = {}; obj[key] = item; result.push(obj); } } else { result.push(value); } } return result; }, generateComparator: function(input) { var generateFunction; generateFunction = function(comparator) { if (!comparator) { return null; } else if (util.isFunction(comparator)) { return comparator; } else if (util.isArray(comparator)) { return function(a, b) { var comparison, key, value, _i, _len; comparison = 0; for (key = _i = 0, _len = comparator.length; _i < _len; key = ++_i) { value = comparator[key]; comparison = generateFunction(value)(a, b); if (comparison) { return comparison; } } return comparison; }; } else if (util.isObject(comparator)) { return function(a, b) { var aValue, bValue, comparison, key, value; comparison = 0; for (key in comparator) { if (!__hasProp.call(comparator, key)) continue; value = comparator[key]; aValue = util.get(a, key); bValue = util.get(b, key); if (aValue === bValue) { comparison = 0; } else if (aValue < bValue) { comparison = -1; } else if (aValue > bValue) { comparison = 1; } if (value === -1) { comparison *= -1; } if (comparison) { return comparison; } } return comparison; }; } else { throw new Error('Unknown comparator type'); } }; return generateFunction(input); } }; Hash = (function(_super) { __extends(Hash, _super); function Hash(value) { var item, key, _i, _len; value = util.toArray(value); for (key = _i = 0, _len = value.length; _i < _len; key = ++_i) { item = value[key]; this.push(item); } } Hash.prototype.hasIn = function(options) { var value, _i, _len; options = util.toArray(options); for (_i = 0, _len = this.length; _i < _len; _i++) { value = this[_i]; if (__indexOf.call(options, value) >= 0) { return true; } } return false; }; Hash.prototype.hasAll = function(options) { var empty, pass, value, _i, _len; options = util.toArray(options); empty = true; pass = true; for (_i = 0, _len = this.length; _i < _len; _i++) { value = this[_i]; empty = false; if (__indexOf.call(options, value) < 0) { pass = false; } } if (empty) { pass = false; } return pass; }; Hash.prototype.isSame = function(options) { var pass; options = util.toArray(options); pass = this.sort().join() === options.sort().join(); return pass; }; return Hash; })(Array); if (Backbone == null) { QueryCollection = null; } else { QueryCollection = (function(_super) { __extends(QueryCollection, _super); function QueryCollection() { this.onParentReset = __bind(this.onParentReset, this); this.onParentAdd = __bind(this.onParentAdd, this); this.onParentRemove = __bind(this.onParentRemove, this); this.onParentChange = __bind(this.onParentChange, this); this.onChange = __bind(this.onChange, this); _ref = QueryCollection.__super__.constructor.apply(this, arguments); return _ref; } QueryCollection.prototype.model = Backbone.Model; QueryCollection.prototype.initialize = function(models, options) { var key, me, value, _ref1; me = this; if (this.options == null) { this.options = {}; } _ref1 = Criteria.prototype; for (key in _ref1) { if (!__hasProp.call(_ref1, key)) continue; value = _ref1[key]; if (this[key] == null) { this[key] = value; } } if (this.comparator != null) { this.setComparator(this.comparator); } this.applyCriteriaOptions(options); if (options != null) { if (options.parentCollection != null) { this.options.parentCollection = options.parentCollection; } if (options.live != null) { this.options.live = options.live; } this.live(); } return this; }; QueryCollection.prototype.getComparator = function() { return this.comparator; }; QueryCollection.prototype.setComparator = function(comparator) { comparator = util.generateComparator(comparator); this.comparator = comparator; return this; }; QueryCollection.prototype.createChildCollection = function(models, options) { var collection; options || (options = {}); options.parentCollection = this; if (options.collection == null) { options.collection = this.collection || QueryCollection; } if (options.comparator == null) { options.comparator = options.collection.prototype.comparator || this.comparator; } collection = new options.collection(models, options); return collection; }; QueryCollection.prototype.createLiveChildCollection = function(models, options) { var collection; options || (options = {}); options.live = true; collection = this.createChildCollection(models, options); return collection; }; QueryCollection.prototype.hasParentCollection = function() { return this.options.parentCollection != null; }; QueryCollection.prototype.getParentCollection = function() { return this.options.parentCollection; }; QueryCollection.prototype.setParentCollection = function(parentCollection, skipCheck) { if (!skipCheck && this.options.parentCollection === parentCollection) { return this; } this.options.parentCollection = parentCollection; this.live(); return this; }; QueryCollection.prototype.hasModel = function(model) { var exists, _ref1, _ref2; model || (model = {}); if ((model.id != null) && this.get(model.id)) { exists = true; } else if ((model.cid != null) && ((_ref1 = (_ref2 = this._byCid) != null ? _ref2[model.cid] : void 0) != null ? _ref1 : this.get(model.cid))) { exists = true; } else { exists = false; } return exists; }; QueryCollection.prototype.safeRemove = function(model) { var exists; exists = this.hasModel(model); if (exists) { this.remove(model); } return this; }; QueryCollection.prototype.safeAdd = function(model) { var exists; exists = this.hasModel(model); if (!exists) { this.add(model); } return this; }; QueryCollection.prototype.sortCollection = function(comparator) { if (comparator) { comparator = util.generateComparator(comparator); this.models.sort(comparator); } else { comparator = this.getComparator(); if (comparator) { this.models.sort(comparator); } else { throw new Error('You need a comparator to sort'); } } return this; }; QueryCollection.prototype.sortArray = function(comparator) { var arr; arr = this.toJSON(); if (comparator) { comparator = util.generateComparator(comparator); arr.sort(comparator); } else { comparator = this.getComparator(); if (comparator) { arr.sort(comparator); } else { throw new Error('You need a comparator to sort'); } } return arr; }; QueryCollection.prototype.findAll = function() { var args, collection, comparator, criteriaOptions, paging, query; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (args.length) { if (args.length === 1 && args[0] instanceof Criteria) { criteriaOptions = args[0].options; } else { query = args[0], comparator = args[1], paging = args[2]; criteriaOptions = { comparator: comparator, paging: paging, queries: { find: query } }; } } else { criteriaOptions = null; } collection = this.createChildCollection([], criteriaOptions).query(); return collection; }; QueryCollection.prototype.findAllLive = function() { var args, collection, comparator, criteriaOptions, paging, query; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (args.length) { if (args.length === 1 && args[0] instanceof Criteria) { criteriaOptions = args[0].options; } else { query = args[0], comparator = args[1], paging = args[2]; criteriaOptions = { comparator: comparator, paging: paging, queries: { find: query } }; } } else { criteriaOptions = null; } collection = this.createLiveChildCollection([], criteriaOptions).query(); return collection; }; QueryCollection.prototype.findOne = function() { var args, comparator, criteriaOptions, paging, passed, query; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (args.length) { if (args.length === 1 && args[0] instanceof Criteria) { criteriaOptions = args[0].options; } else { query = args[0], comparator = args[1], paging = args[2]; criteriaOptions = { comparator: comparator, paging: paging, queries: { find: query } }; } } else { criteriaOptions = null; } passed = this.testModels(this.models, criteriaOptions); if ((passed != null ? passed.length : void 0) !== 0) { return passed[0]; } else { return null; } }; QueryCollection.prototype.query = function() { var args, criteria, passed; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (args.length === 1) { if (args[0] instanceof Criteria) { criteria = args[0].options; } else { criteria = { paging: args[0] }; } } passed = this.queryModels(criteria); this.reset(passed); return this; }; QueryCollection.prototype.queryModels = function() { var args, collection, criteriaOptions, models, passed; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; criteriaOptions = this.extractCriteriaOptions.apply(this, args); collection = this.getParentCollection() || this; models = collection.models; passed = this.testModels(models, criteriaOptions); return passed; }; QueryCollection.prototype.queryArray = function() { var args, model, passed, result, _i, _len; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; result = []; passed = this.queryModels.apply(this, args); for (_i = 0, _len = passed.length; _i < _len; _i++) { model = passed[_i]; result.push(model.toJSON()); } return result; }; QueryCollection.prototype.live = function(enabled) { var parentCollection; if (enabled == null) { enabled = this.options.live; } this.options.live = enabled; if (enabled) { this.on('change', this.onChange); } else { this.off('change', this.onChange); } parentCollection = this.getParentCollection(); if (parentCollection != null) { if (enabled) { parentCollection.on('change', this.onParentChange); parentCollection.on('remove', this.onParentRemove); parentCollection.on('add', this.onParentAdd); parentCollection.on('reset', this.onParentReset); } else { parentCollection.off('change', this.onParentChange); parentCollection.off('remove', this.onParentRemove); parentCollection.off('add', this.onParentAdd); parentCollection.off('reset', this.onParentReset); } } return this; }; QueryCollection.prototype.add = function(models, options) { var model, passedModels, _i, _len; options = options ? util.clone(options) : {}; models = util.isArray(models) ? models.slice() : [models]; passedModels = []; for (_i = 0, _len = models.length; _i < _len; _i++) { model = models[_i]; model = this._prepareModel(model, options); if (model && this.test(model)) { passedModels.push(model); } } Backbone.Collection.prototype.add.apply(this, [passedModels, options]); return this; }; QueryCollection.prototype.create = function(model, options) { options = options ? util.clone(options) : {}; model = this._prepareModel(model, options); if (model && this.test(model)) { Backbone.Collection.prototype.create.apply(this, [model, options]); } return this; }; QueryCollection.prototype.onChange = function(model) { var pass; if (this.getPaging()) { return this.query(); } pass = this.test(model); if (!pass) { this.safeRemove(model); } else { if (this.comparator) { this.sortCollection(); } } return this; }; QueryCollection.prototype.onParentChange = function(model) { var pass; if (this.getPaging()) { return this.query(); } pass = this.test(model) && this.getParentCollection().hasModel(model); if (pass) { this.safeAdd(model); } else { this.safeRemove(model); } return this; }; QueryCollection.prototype.onParentRemove = function(model) { if (this.getPaging()) { return this.query(); } this.safeRemove(model); return this; }; QueryCollection.prototype.onParentAdd = function(model) { if (this.getPaging()) { return this.query(); } this.safeAdd(model); return this; }; QueryCollection.prototype.onParentReset = function(model) { this.reset(this.getParentCollection().models); return this; }; return QueryCollection; })(Backbone.Collection); } Criteria = (function() { function Criteria() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; this.applyCriteriaOptions = __bind(this.applyCriteriaOptions, this); this.applyCriteriaOptions.apply(this, args); this; } Criteria.prototype.extractCriteriaOptions = function() { var args, comparator, criteriaOptions, paging, query; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (args.length === 1) { if (args[0] instanceof Criteria) { criteriaOptions = args[0].options; } else if (args[0]) { criteriaOptions = args[0]; } else { criteriaOptions = null; } } else if (args.length > 1) { query = args[0], comparator = args[1], paging = args[2]; criteriaOptions = { queries: { find: query || null }, comparator: comparator, paging: paging }; } else { criteriaOptions = null; } return criteriaOptions; }; Criteria.prototype.applyCriteriaOptions = function() { var args, criteriaOptions, _base, _base1, _base2, _base3, _base4, _base5; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (this.options == null) { this.options = {}; } if ((_base = this.options).filters == null) { _base.filters = {}; } if ((_base1 = this.options).queries == null) { _base1.queries = {}; } if ((_base2 = this.options).pills == null) { _base2.pills = {}; } if ((_base3 = this.options).paging == null) { _base3.paging = null; } if ((_base4 = this.options).searchString == null) { _base4.searchString = null; } if ((_base5 = this.options).comparator == null) { _base5.comparator = null; } criteriaOptions = this.extractCriteriaOptions.apply(this, args); if (criteriaOptions) { if (criteriaOptions.filters != null) { this.setFilters(criteriaOptions.filters); } if (criteriaOptions.queries != null) { this.setQueries(criteriaOptions.queries); } if (criteriaOptions.pills != null) { this.setPills(criteriaOptions.pills); } if (criteriaOptions.paging != null) { this.setPaging(criteriaOptions.paging); } if (criteriaOptions.searchString != null) { this.setSearchString(criteriaOptions.searchString); } if (criteriaOptions.comparator != null) { this.setComparator(criteriaOptions.comparator); } } return this; }; Criteria.prototype.getPaging = function() { return this.options.paging; }; Criteria.prototype.setPaging = function(paging) { paging = util.extend(this.getPaging() || {}, paging || {}); paging.page || (paging.page = null); paging.limit || (paging.limit = null); paging.offset || (paging.offset = null); if (paging.page || paging.limit || paging.offset) { this.options.paging = paging; } else { this.options.paging = null; } return this; }; Criteria.prototype.getComparator = function() { return this.options.comparator; }; Criteria.prototype.setComparator = function(comparator) { comparator = util.generateComparator(comparator); this.options.comparator = comparator; return this; }; Criteria.prototype.getFilter = function(key) { return this.options.filters[key]; }; Criteria.prototype.getFilters = function() { return this.options.filters; }; Criteria.prototype.setFilters = function(filters) { var key, value; filters || (filters = {}); for (key in filters) { if (!__hasProp.call(filters, key)) continue; value = filters[key]; this.setFilter(key, value); } return this; }; Criteria.prototype.setFilter = function(name, value) { var filters; if (typeof value === 'undefined') { throw new Error('QueryCollection::setFilter was called without both arguments'); } filters = this.options.filters; if (value != null) { filters[name] = value; } else if (filters[name] != null) { delete filters[name]; } return this; }; Criteria.prototype.getQuery = function(key) { return this.options.queries[key]; }; Criteria.prototype.getQueries = function() { return this.options.queries; }; Criteria.prototype.setQueries = function(queries) { var key, value; queries || (queries = {}); for (key in queries) { if (!__hasProp.call(queries, key)) continue; value = queries[key]; this.setQuery(key, value); } return this; }; Criteria.prototype.setQuery = function(name, value) { var queries; if (typeof value === 'undefined') { throw new Error('QueryCollection::setQuery was called without both arguments'); } queries = this.options.queries; if (value != null) { if (!(value instanceof Query)) { value = new Query(value); } queries[name] = value; } else if (queries[name] != null) { delete queries[name]; } return this; }; Criteria.prototype.getPill = function(key) { return this.options.pills[key]; }; Criteria.prototype.getPills = function() { return this.options.pills; }; Criteria.prototype.setPills = function(pills) { var key, value; pills || (pills = {}); for (key in pills) { if (!__hasProp.call(pills, key)) continue; value = pills[key]; this.setPill(key, value); } return this; }; Criteria.prototype.setPill = function(name, value) { var pills, searchString; if (typeof value === 'undefined') { throw new Error('QueryCollection::setPill was called without both arguments'); } pills = this.getPills(); searchString = this.getSearchString(); if (value != null) { if (!(value instanceof Pill)) { value = new Pill(value); } if (searchString) { value.setSearchString(searchString); } pills[name] = value; } else if (pills[name] != null) { delete pills[name]; } return this; }; Criteria.prototype.getCleanedSearchString = function() { return this.options.cleanedSearchString; }; Criteria.prototype.getSearchString = function() { return this.options.searchString; }; Criteria.prototype.setSearchString = function(searchString) { var cleanedSearchString, pill, pillName, pills; pills = this.options.pills; cleanedSearchString = searchString; for (pillName in pills) { if (!__hasProp.call(pills, pillName)) continue; pill = pills[pillName]; cleanedSearchString = pill.setSearchString(cleanedSearchString); } this.options.searchString = searchString; this.options.cleanedSearchString = cleanedSearchString; return this; }; Criteria.prototype.test = function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return this.testModel.apply(this, args); }; Criteria.prototype.testModel = function(model, criteriaOptions) { var passed; if (criteriaOptions == null) { criteriaOptions = {}; } passed = this.testQueries(model, criteriaOptions.queries) && this.testFilters(model, criteriaOptions.filters) && this.testPills(model, criteriaOptions.pills); return passed; }; Criteria.prototype.testModels = function(models, criteriaOptions) { var comparator, finish, me, model, paging, pass, passed, start, _i, _len; if (criteriaOptions == null) { criteriaOptions = {}; } me = this; passed = []; paging = criteriaOptions.paging, comparator = criteriaOptions.comparator; if (paging == null) { paging = this.getPaging(); } if (comparator != null) { if (comparator) { comparator = util.generateComparator(comparator); } } else { comparator = this.getComparator(); } for (_i = 0, _len = models.length; _i < _len; _i++) { model = models[_i]; pass = me.testModel(model, criteriaOptions); if (pass) { passed.push(model); } } if (comparator) { passed.sort(comparator); } if (paging) { start = paging.offset || 0; if ((paging.limit != null) && paging.limit > 0) { start = start + paging.limit * ((paging.page || 1) - 1); finish = start + paging.limit; passed = passed.slice(start, finish); } else if (start) { passed = passed.slice(start); } } return passed; }; Criteria.prototype.testQueries = function(model, queries) { var passed, query, queryName; passed = true; if (queries == null) { queries = this.getQueries(); } if (queries) { for (queryName in queries) { if (!__hasProp.call(queries, queryName)) continue; query = queries[queryName]; if (!(query instanceof Query)) { query = new Query(query); queries[queryName] = query; } if (query.test(model) === false) { passed = false; return false; } } } return passed; }; Criteria.prototype.testFilters = function(model, filters) { var cleanedSearchString, filter, filterName, passed; passed = true; cleanedSearchString = this.getCleanedSearchString(); if (filters == null) { filters = this.getFilters(); } if (filters) { for (filterName in filters) { if (!__hasProp.call(filters, filterName)) continue; filter = filters[filterName]; if (filter(model, cleanedSearchString) === false) { passed = false; return false; } } } return passed; }; Criteria.prototype.testPills = function(model, pills) { var passed, pill, pillName, searchString; passed = true; searchString = this.getSearchString(); if (pills == null) { pills = this.getPills(); } if ((searchString != null) && pills) { for (pillName in pills) { if (!__hasProp.call(pills, pillName)) continue; pill = pills[pillName]; if (!(pill instanceof Pill)) { pill = new Pill(query); pill.setSearchString(searchString); pills[pillName] = pill; } if (pill.test(model) === false) { passed = false; return false; } } } return passed; }; return Criteria; })(); Pill = (function() { Pill.prototype.callback = null; Pill.prototype.regex = null; Pill.prototype.prefixes = null; Pill.prototype.searchString = null; Pill.prototype.values = null; Pill.prototype.logicalOperator = 'OR'; function Pill(pill) { var prefix, regexString, safePrefixes, safePrefixesStr, _i, _len, _ref1; pill || (pill = {}); this.callback = pill.callback; this.prefixes = pill.prefixes; if (pill.logicalOperator != null) { this.logicalOperator = pill.logicalOperator; } safePrefixes = []; _ref1 = this.prefixes; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { prefix = _ref1[_i]; safePrefixes.push(util.safeRegex(prefix)); } safePrefixesStr = safePrefixes.join('|'); regexString = "(" + safePrefixesStr + ")\\s*('[^']+'|\\\"[^\\\"]+\\\"|[^'\\\"\\s]\\S*)"; this.regex = util.createRegex(regexString); this; } Pill.prototype.setSearchString = function(searchString) { var cleanedSearchString, match, value, values; cleanedSearchString = searchString; values = []; while (match = this.regex.exec(searchString)) { value = match[2].trim().replace(/(^['"]\s*|\s*['"]$)/g, ''); switch (value) { case 'true': case 'TRUE': value = true; break; case 'false': case 'FALSE': value = false; break; case 'null': case 'NULL': value = null; } values.push(value); cleanedSearchString = cleanedSearchString.replace(match[0], '').trim(); } this.searchString = searchString; this.values = values; return cleanedSearchString; }; Pill.prototype.test = function(model) { var pass, value, _i, _j, _len, _len1, _ref1, _ref2, _ref3; if ((_ref1 = this.values) != null ? _ref1.length : void 0) { if (this.logicalOperator === 'OR') { pass = false; _ref2 = this.values; for (_i = 0, _len = _ref2.length; _i < _len; _i++) { value = _ref2[_i]; pass = this.callback(model, value); if (pass) { break; } } } else if (this.logicalOperator === 'AND') { pass = false; _ref3 = this.values; for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) { value = _ref3[_j]; pass = this.callback(model, value); if (!pass) { break; } } } else { throw new Error('Unkown logical operator type'); } } else { pass = null; } return pass; }; return Pill; })(); Query = (function() { Query.prototype.source = null; Query.prototype.compiledSelectors = null; Query.prototype.selectors = { '$or': { compile: function(opts) { var queries, query, queryGroup, querySource, _i, _len; queries = []; queryGroup = util.toArrayGroup(opts.selectorValue); if (!queryGroup.length) { throw new Error("Query called with an empty " + selectorName + " statement"); } for (_i = 0, _len = queryGroup.length; _i < _len; _i++) { querySource = queryGroup[_i]; query = new Query(querySource); queries.push(query); } return { queries: queries }; }, test: function(opts) { var query, _i, _len, _ref1; _ref1 = opts.queries; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { query = _ref1[_i]; if (query.test(opts.model)) { return true; } } return false; } }, '$nor': { compile: function(opts) { return opts.selector('$or', opts); }, test: function(opts) { return !opts.selector('$or', opts); } }, '$and': { compile: function(opts) { return opts.selector('$or', opts); }, test: function(opts) { var query, _i, _len, _ref1; _ref1 = opts.queries; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { query = _ref1[_i]; if (query.test(opts.model) === false) { return false; } } return true; } }, '$not': { compile: function(opts) { return opts.selector('$and', opts); }, test: function(opts) { return !opts.selector('$and', opts); } }, 'string': { test: function(opts) { return opts.modelValueExists && opts.modelValue === opts.selectorValue; } }, 'number': { test: function(opts) { return opts.selector('string', opts); } }, 'boolean': { test: function(opts) { return opts.selector('string', opts); } }, 'array': { test: function(opts) { return opts.modelValueExists && (new Hash(opts.modelValue)).isSame(opts.selectorValue); } }, 'date': { test: function(opts) { return opts.modelValueExists && opts.modelValue.toString() === opts.selectorValue.toString(); } }, 'regexp': { test: function(opts) { return opts.modelValueExists && opts.selectorValue.test(opts.modelValue); } }, 'null': { test: function(opts) { return opts.modelValue === opts.selectorValue; } }, 'model': { test: function(opts) { var _ref1, _ref2; return (((_ref1 = opts.modelValue) != null ? _ref1.cid : void 0) || opts.modelValue) === (((_ref2 = opts.selectorValue) != null ? _ref2.cid : void 0) || opts.selectorValue); } }, 'collection': { test: function(opts) { return opts.modelValue === opts.selectorValue; } }, '$beginsWith': { test: function(opts) { var beginsWithParts, beginsWithValue, _i, _len; if (opts.selectorValue && opts.modelValueExists && util.isString(opts.modelValue)) { beginsWithParts = util.toArray(opts.selectorValue); for (_i = 0, _len = beginsWithParts.length; _i < _len; _i++) { beginsWithValue = beginsWithParts[_i]; if (opts.modelValue.substr(0, beginsWithValue.length) === beginsWithValue) { return true; break; } } } return false; } }, '$startsWith': { test: function(opts) { return opts.selector('$beginsWith', opts); } }, '$endsWith': { test: function(opts) { var endsWithParts, endsWithValue, _i, _len; if (opts.selectorValue && opts.modelValueExists && util.isString(opts.modelValue)) { endsWithParts = util.toArray(opts.selectorValue); for (_i = 0, _len = endsWithParts.length; _i < _len; _i++) { endsWithValue = endsWithParts[_i]; if (opts.modelValue.substr(endsWithValue.length * -1) === endsWithValue) { return true; break; } } } return false; } }, '$finishesWith': { test: function(opts) { return opts.selector('$endsWith', opts); } }, '$all': { test: function(opts) { if ((opts.selectorValue != null) && opts.modelValueExists) { if ((new Hash(opts.modelValue)).hasAll(opts.selectorValue)) { return true; } } return false; } }, '$in': { test: function(opts) { if ((opts.selectorValue != null) && opts.modelValueExists) { if ((new Hash(opts.modelValue)).hasIn(opts.selectorValue) || (new Hash(opts.selectorValue)).hasIn(opts.modelValue)) { return true; } } return false; } }, '$nin': { test: function(opts) { if ((opts.selectorValue != null) && opts.modelValueExists) { if ((new Hash(opts.modelValue)).hasIn(opts.selectorValue) === false && (new Hash(opts.selectorValue)).hasIn(opts.modelValue) === false) { return true; } } return false; } }, '$has': { test: function(opts) { if (opts.modelValueExists) { if ((new Hash(opts.modelValue)).hasIn(opts.selectorValue)) { return true; } } return false; } }, '$hasAll': { test: function(opts) { if (opts.modelValueExists) { if ((new Hash(opts.modelValue)).hasIn(opts.selectorValue)) { return true; } } return false; } }, '$size': { test: function(opts) { if (opts.modelValue.length != null) { if (opts.modelValue.length === opts.selectorValue) { return true; } } return false; } }, '$length': { test: function(opts) { return opts.selector('$size', opts); } }, '$type': { test: function(opts) { if (typeof opts.modelValue === opts.selectorValue) { return true; } return false; } }, '$like': { test: function(opts) { if (util.isString(opts.modelValue) && opts.modelValue.toLowerCase().indexOf(opts.selectorValue.toLowerCase()) !== -1) { return true; } return false; } }, '$likeSensitive': { test: function(opts) { if (util.isString(opts.modelValue) && opts.modelValue.indexOf(opts.selectorValue) !== -1) { return true; } return false; } }, '$exists': { test: function(opts) { if (opts.selectorValue === opts.modelValueExists) { return true; } return false; } }, '$mod': { test: function(opts) { var $mod; if (opts.modelValueExists) { $mod = opts.selectorValue; if (!util.isArray($mod)) { $mod = [$mod]; } if ($mod.length === 1) { $mod.push(0); } if ((opts.modelValue % $mod[0]) === $mod[1]) { return true; } } return false; } }, '$eq': { test: function(opts) { if (util.isEqual(opts.modelValue, opts.selectorValue)) { return true; } return false; } }, '$equal': { test: function(opts) { return opts.selector('$eq', opts); } }, '$ne': { test: function(opts) { if (opts.modelValue !== opts.selectorValue) { return true; } return false; } }, '$lt': { test: function(opts) { if ((opts.selectorValue != null) && util.isComparable(opts.modelValue) && opts.modelValue < opts.selectorValue) { return true; } return false; } }, '$gt': { test: function(opts) { if ((opts.selectorValue != null) && util.isComparable(opts.modelValue) && opts.modelValue > opts.selectorValue) { return true; } return false; } }, '$bt': { test: function(opts) { if ((opts.selectorValue != null) && util.isComparable(opts.modelValue) && opts.selectorValue[0] < opts.modelValue && opts.modelValue < opts.selectorValue[1]) { return true; } return false; } }, '$lte': { test: function(opts) { if ((opts.selectorValue != null) && util.isComparable(opts.modelValue) && opts.modelValue <= opts.selectorValue) { return true; } return false; } }, '$gte': { test: function(opts) { if ((opts.selectorValue != null) && util.isComparable(opts.modelValue) && opts.modelValue >= opts.selectorValue) { return true; } return false; } }, '$bte': { test: function(opts) { if ((opts.selectorValue != null) && util.isComparable(opts.modelValue) && opts.selectorValue[0] <= opts.modelValue && opts.modelValue <= opts.selectorValue[1]) { return true; } return false; } } }; function Query(source) { if (source == null) { source = {}; } this.source = source; this.compileQuery(); } Query.prototype.compileSelector = function(selectorName, selectorOpts) { var compileOpts, compiledSelector, key, opts, query, selector, selectors, value; if (selectorOpts == null) { selectorOpts = {}; } query = this; selectors = this.selectors; opts = { selectorName: selectorName }; selector = selectors[selectorName]; if (!selector) { throw new Error("Couldn't find the selector " + selectorName); } for (key in selectorOpts) { if (!__hasProp.call(selectorOpts, key)) continue; value = selectorOpts[key]; opts[key] = value; } if (selector.compile != null) { opts.selector = function(selectorName, opts) { return selectors[selectorName].compile(opts); }; compileOpts = selector.compile(opts); for (key in compileOpts) { if (!__hasProp.call(compileOpts, key)) continue; value = compileOpts[key]; opts[key] = value; } } opts.selector = function(selectorName, opts) { return selectors[selectorName].test(opts); }; compiledSelector = { opts: opts, test: selector.test }; return compiledSelector; }; Query.prototype.testCompiledSelector = function(compiledSelector, model) { var match, opts, test; opts = compiledSelector.opts; test = compiledSelector.test; opts.model = model; opts.modelValue = util.get(opts.model, opts.fieldName); opts.modelId = util.get(opts.model, 'id'); opts.modelValueExists = typeof opts.modelValue !== 'undefined'; if (!opts.modelValueExists) { opts.modelValue = false; } match = test(opts); return match; }; Query.prototype.compileQuery = function() { var advancedSelectorName, advancedSelectorValue, compiledSelector, compiledSelectors, fieldName, query, selectorValue, _ref1; query = this; compiledSelectors = []; _ref1 = this.source; for (fieldName in _ref1) { if (!__hasProp.call(_ref1, fieldName)) continue; selectorValue = _ref1[fieldName]; if (fieldName === '$or' || fieldName === '$nor' || fieldName === '$and' || fieldName === '$not') { compiledSelector = this.compileSelector(fieldName, { fieldName: fieldName, selectorValue: selectorValue }); compiledSelectors.push(compiledSelector); } else if (util.isString(selectorValue)) { compiledSelector = this.compileSelector('string', { fieldName: fieldName, selectorValue: selectorValue }); compiledSelectors.push(compiledSelector); } else if (util.isNumber(selectorValue)) { compiledSelector = this.compileSelector('number', { fieldName: fieldName, selectorValue: selectorValue }); compiledSelectors.push(compiledSelector); } else if (util.isBoolean(selectorValue)) { compiledSelector = this.compileSelector('boolean', { fieldName: fieldName, selectorValue: selectorValue }); compiledSelectors.push(compiledSelector); } else if (util.isArray(selectorValue)) { compiledSelector = this.compileSelector('array', { fieldName: fieldName, selectorValue: selectorValue }); compiledSelectors.push(compiledSelector); } else if (util.isDate(selectorValue)) { compiledSelector = this.compileSelector('date', { fieldName: fieldName, selectorValue: selectorValue }); compiledSelectors.push(compiledSelector); } else if (util.isRegExp(selectorValue)) { compiledSelector = this.compileSelector('regexp', { fieldName: fieldName, selectorValue: selectorValue }); compiledSelectors.push(compiledSelector); } else if (util.isNull(selectorValue)) { compiledSelector = this.compileSelector('null', { fieldName: fieldName, selectorValue: selectorValue }); compiledSelectors.push(compiledSelector); } else if (selectorValue instanceof Backbone.Model) { compiledSelector = this.compileSelector('model', { fieldName: fieldName, selectorValue: selectorValue }); compiledSelectors.push(compiledSelector); } else if (selectorValue instanceof Backbone.Collection) { compiled