Skip to content

Instantly share code, notes, and snippets.

@balupton
Created October 28, 2012 07:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save balupton/3968010 to your computer and use it in GitHub Desktop.
Save balupton/3968010 to your computer and use it in GitHub Desktop.
QueryEngine Performance
// Generated by CoffeeScript 1.4.0
(function() {
var Backbone, Criteria, Hash, Pill, Query, QueryCollection, queryEngine, util, _,
__hasProp = {}.hasOwnProperty,
__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); }; },
__slice = [].slice;
_ = typeof module !== "undefined" && module !== null ? require('underscore') : this._;
Backbone = typeof module !== "undefined" && module !== null ? require('backbone') : this.Backbone;
util = {
isEqual: function(value1, value2) {
return _.isEqual(value1, value2);
},
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;
},
isComparable: function(value) {
return util.isNumber(value) || util.isDate(value);
},
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;
result = [];
if (value) {
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;
result = [];
if (value) {
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) {
throw new Error('Cannot sort without a comparator');
} 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, _ref, _ref1;
comparison = 0;
for (key in comparator) {
if (!__hasProp.call(comparator, key)) continue;
value = comparator[key];
aValue = (_ref = typeof a.get === "function" ? a.get(key) : void 0) != null ? _ref : a[key];
bValue = (_ref1 = typeof b.get === "function" ? b.get(key) : void 0) != null ? _ref1 : 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);
Hash.prototype.arr = [];
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);
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);
return QueryCollection.__super__.constructor.apply(this, arguments);
}
QueryCollection.prototype.model = Backbone.Model;
QueryCollection.prototype.initialize = function(models, options) {
var key, me, value, _ref, _ref1, _ref2;
me = this;
if ((_ref = this.options) == null) {
this.options = {};
}
_.extend(this.options, options);
_ref1 = Criteria.prototype;
for (key in _ref1) {
if (!__hasProp.call(_ref1, key)) continue;
value = _ref1[key];
if ((_ref2 = this[key]) == null) {
this[key] = value;
}
}
if (this.comparator != null) {
this.setComparator(this.comparator);
}
this.applyCriteria(options);
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, _ref, _ref1;
options || (options = {});
options.parentCollection = this;
if ((_ref = options.collection) == null) {
options.collection = this.collection || QueryCollection;
}
if ((_ref1 = 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;
model || (model = {});
if ((model.id != null) && this.get(model.id)) {
exists = true;
} else if ((model.cid != null) && this.getByCid(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, criteria, paging, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
collection = this.createChildCollection([], criteria).query();
return collection;
};
QueryCollection.prototype.findAllLive = function() {
var args, collection, comparator, criteria, paging, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
collection = this.createLiveChildCollection([], criteria).query();
return collection;
};
QueryCollection.prototype.findOne = function() {
var args, comparator, criteria, paging, passed, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
passed = this.testModels(this.models, criteria);
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) {
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, comparator, criteria, models, paging, passed, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1) {
if (args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
criteria = args[0];
}
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
collection = this.getParentCollection() || this;
models = collection.models;
passed = this.testModels(models, criteria);
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 ? _.clone(options) : {};
models = _.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 ? _.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;
pass = this.test(model);
if (!pass) {
this.safeRemove(model);
} else {
if (this.comparator) {
this.sortCollection();
}
}
return this;
};
QueryCollection.prototype.onParentChange = function(model) {
var pass;
pass = this.test(model) && this.getParentCollection().hasModel(model);
if (pass) {
this.safeAdd(model);
} else {
this.safeRemove(model);
}
return this;
};
QueryCollection.prototype.onParentRemove = function(model) {
this.safeRemove(model);
return this;
};
QueryCollection.prototype.onParentAdd = function(model) {
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(options) {
this.applyCriteria = __bind(this.applyCriteria, this);
var _ref;
if ((_ref = this.options) == null) {
this.options = {};
}
_.extend(this.options, options);
this;
}
Criteria.prototype.applyCriteria = function(options) {
var _base;
if (options == null) {
options = {};
}
this.options.filters = _.extend({}, this.options.filters || {});
this.options.queries = _.extend({}, this.options.queries || {});
this.options.pills = _.extend({}, this.options.pills || {});
(_base = this.options).searchString || (_base.searchString = null);
this.options.paging = _.extend({}, this.options.paging || {});
this.setFilters(this.options.filters);
this.setQueries(this.options.queries);
this.setPills(this.options.pills);
if (this.options.searchString != null) {
this.setSearchString(this.options.searchString);
}
this.setPaging(this.options.paging);
if (this.options.comparator != null) {
this.setComparator(this.options.comparator);
}
return this;
};
Criteria.prototype.getPaging = function() {
return this.options.paging;
};
Criteria.prototype.setPaging = function(paging) {
paging = _.extend(this.getPaging(), paging || {});
paging.page || (paging.page = null);
paging.limit || (paging.limit = null);
paging.offset || (paging.offset = null);
this.options.paging = paging;
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, criteria) {
var passed;
if (criteria == null) {
criteria = {};
}
passed = this.testFilters(model, criteria.filters) && this.testQueries(model, criteria.queries) && this.testPills(model, criteria.pills);
return passed;
};
Criteria.prototype.testModels = function(models, criteria) {
var comparator, finish, me, model, paging, pass, passed, start, _i, _len, _ref;
if (criteria == null) {
criteria = {};
}
me = this;
passed = [];
paging = (_ref = criteria.paging) != null ? _ref : this.getPaging();
if (criteria.comparator != null) {
comparator = util.generateComparator(criteria.comparator);
} else {
comparator = this.getComparator();
}
for (_i = 0, _len = models.length; _i < _len; _i++) {
model = models[_i];
pass = me.testModel(model, criteria);
if (pass) {
passed.push(model);
}
}
if (comparator) {
passed.sort(comparator);
}
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 {
passed = passed.slice(start);
}
return passed;
};
Criteria.prototype.testFilters = function(model, filters) {
var cleanedSearchString, filter, filterName, passed;
passed = true;
cleanedSearchString = this.getCleanedSearchString();
if (filters == null) {
filters = this.getFilters();
}
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.testQueries = function(model, queries) {
var passed, query, queryName;
passed = true;
if (queries == null) {
queries = this.getQueries();
}
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.testPills = function(model, pills) {
var passed, pill, pillName, searchString;
passed = true;
searchString = this.getSearchString();
if (pills == null) {
pills = this.getPills();
}
if (searchString != null) {
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, _ref;
pill || (pill = {});
this.callback = pill.callback;
this.prefixes = pill.prefixes;
if (pill.logicalOperator != null) {
this.logicalOperator = pill.logicalOperator;
}
safePrefixes = [];
_ref = this.prefixes;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
prefix = _ref[_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, _ref, _ref1, _ref2;
if ((_ref = this.values) != null ? _ref.length : void 0) {
if (this.logicalOperator === 'OR') {
pass = false;
_ref1 = this.values;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
value = _ref1[_i];
pass = this.callback(model, value);
if (pass) {
break;
}
}
} else if (this.logicalOperator === 'AND') {
pass = false;
_ref2 = this.values;
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
value = _ref2[_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.query = null;
function Query(query) {
if (query == null) {
query = {};
}
this.query = query;
}
Query.prototype.test = function(model) {
var $mod, beginsWithValue, empty, endWithValue, match, matchAll, matchAny, modelId, modelValue, modelValueExists, query, queryGroup, queryType, queryValue, selectorName, selectorValue, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref;
matchAll = true;
matchAny = false;
empty = true;
_ref = this.query;
for (selectorName in _ref) {
if (!__hasProp.call(_ref, selectorName)) continue;
selectorValue = _ref[selectorName];
match = false;
empty = false;
modelValue = model.get(selectorName);
modelId = model.get('id');
modelValueExists = typeof modelValue !== 'undefined';
if (!modelValueExists) {
modelValue = false;
}
if (selectorName === '$or' || selectorName === '$nor') {
queryGroup = util.toArrayGroup(selectorValue);
if (!queryGroup.length) {
throw new Error("Query called with an empty " + selectorName + " statement");
}
for (_i = 0, _len = queryGroup.length; _i < _len; _i++) {
query = queryGroup[_i];
query = new Query(query);
if (query.test(model)) {
match = true;
break;
}
}
if (selectorName === '$nor') {
match = !match;
}
} else if (selectorName === '$and' || selectorName === '$not') {
queryGroup = util.toArrayGroup(selectorValue);
if (!queryGroup.length) {
throw new Error("Query called with an empty " + selectorName + " statement");
}
for (_j = 0, _len1 = queryGroup.length; _j < _len1; _j++) {
query = queryGroup[_j];
query = new Query(query);
match = query.test(model);
if (!match) {
break;
}
}
if (selectorName === '$not') {
match = !match;
}
} else if (util.isString(selectorValue) || util.isNumber(selectorValue) || util.isBoolean(selectorValue)) {
if (modelValueExists && modelValue === selectorValue) {
match = true;
}
} else if (util.isArray(selectorValue)) {
if (modelValueExists && (new Hash(modelValue)).isSame(selectorValue)) {
match = true;
}
} else if (util.isDate(selectorValue)) {
if (modelValueExists && modelValue.toString() === selectorValue.toString()) {
match = true;
}
} else if (util.isRegExp(selectorValue)) {
if (modelValueExists && selectorValue.test(modelValue)) {
match = true;
}
} else if (util.isNull(selectorValue)) {
if (modelValue === selectorValue) {
match = true;
}
} else if (util.isObject(selectorValue)) {
for (queryType in selectorValue) {
if (!__hasProp.call(selectorValue, queryType)) continue;
queryValue = selectorValue[queryType];
switch (queryType) {
case '$beginsWith':
case '$startsWith':
if (queryValue && modelValueExists && util.isString(modelValue)) {
if (!util.isArray(queryValue)) {
queryValue = [queryValue];
}
for (_k = 0, _len2 = queryValue.length; _k < _len2; _k++) {
beginsWithValue = queryValue[_k];
if (modelValue.substr(0, beginsWithValue.length) === beginsWithValue) {
match = true;
break;
}
}
}
break;
case '$endsWith':
case '$finishesWith':
if (queryValue && modelValueExists && util.isString(modelValue)) {
if (!util.isArray(queryValue)) {
queryValue = [queryValue];
}
for (_l = 0, _len3 = queryValue.length; _l < _len3; _l++) {
endWithValue = queryValue[_l];
if (modelValue.substr(endWithValue.length * -1) === endWithValue) {
match = true;
break;
}
}
}
break;
case '$all':
if ((queryValue != null) && modelValueExists) {
if ((new Hash(modelValue)).hasAll(queryValue)) {
match = true;
}
}
break;
case '$in':
if ((queryValue != null) && modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue) || (new Hash(queryValue)).hasIn(modelValue)) {
match = true;
}
}
break;
case '$nin':
if ((queryValue != null) && modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue) === false && (new Hash(queryValue)).hasIn(modelValue) === false) {
match = true;
}
}
break;
case '$has':
if (modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue)) {
match = true;
}
}
break;
case '$hasAll':
if (modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue)) {
match = true;
}
}
break;
case '$size':
case '$length':
if (modelValue.length != null) {
if (modelValue.length === queryValue) {
match = true;
}
}
break;
case '$type':
if (typeof modelValue === queryValue) {
match = true;
}
break;
case '$like':
if (util.isString(modelValue) && modelValue.toLowerCase().indexOf(queryValue.toLowerCase()) !== -1) {
match = true;
}
break;
case '$likeSensitive':
if (util.isString(modelValue) && modelValue.indexOf(queryValue) !== -1) {
match = true;
}
break;
case '$exists':
if (queryValue === modelValueExists) {
match = true;
}
break;
case '$mod':
if (modelValueExists) {
$mod = queryValue;
if (!util.isArray($mod)) {
$mod = [$mod];
}
if ($mod.length === 1) {
$mod.push(0);
}
if ((modelValue % $mod[0]) === $mod[1]) {
match = true;
}
}
break;
case '$eq':
case '$equal':
if (util.isEqual(modelValue, queryValue)) {
match = true;
}
break;
case '$ne':
if (modelValue !== queryValue) {
match = true;
}
break;
case '$lt':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue < queryValue) {
match = true;
}
break;
case '$gt':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue > queryValue) {
match = true;
}
break;
case '$bt':
if ((queryValue != null) && util.isComparable(modelValue) && queryValue[0] < modelValue && modelValue < queryValue[1]) {
match = true;
}
break;
case '$lte':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue <= queryValue) {
match = true;
}
break;
case '$gte':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue >= queryValue) {
match = true;
}
break;
case '$bte':
if ((queryValue != null) && util.isComparable(modelValue) && queryValue[0] <= modelValue && modelValue <= queryValue[1]) {
match = true;
}
}
}
}
if (match) {
matchAny = true;
} else {
matchAll = false;
}
}
if (matchAll && !matchAny) {
matchAll = false;
}
return matchAll;
};
return Query;
})();
queryEngine = {
safeRegex: util.safeRegex,
createRegex: util.createRegex,
createSafeRegex: util.createSafeRegex,
generateComparator: util.generateComparator,
toArray: util.toArray,
Backbone: Backbone,
Hash: Hash,
QueryCollection: QueryCollection,
Criteria: Criteria,
Query: Query,
Pill: Pill,
createCollection: function(models, options) {
var collection;
models = util.toArray(models);
collection = new QueryCollection(models, options);
return collection;
},
createLiveCollection: function(models, options) {
var collection;
models = util.toArray(models);
collection = new QueryCollection(models, options).live(true);
return collection;
}
};
if (typeof module !== "undefined" && module !== null) {
module.exports = queryEngine;
} else {
this.queryEnginePublished130 = queryEngine;
}
}).call(this);
// Generated by CoffeeScript 1.4.0
(function() {
var Backbone, Criteria, Hash, Pill, Query, QueryCollection, queryEngine, util, _,
__hasProp = {}.hasOwnProperty,
__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); }; },
__slice = [].slice;
_ = typeof module !== "undefined" && module !== null ? require('underscore') : this._;
Backbone = typeof module !== "undefined" && module !== null ? require('backbone') : this.Backbone;
util = {
isEqual: function(value1, value2) {
return _.isEqual(value1, value2);
},
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;
},
isComparable: function(value) {
return util.isNumber(value) || util.isDate(value);
},
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) {
throw new Error('Cannot sort without a comparator');
} 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, _ref, _ref1;
comparison = 0;
for (key in comparator) {
if (!__hasProp.call(comparator, key)) continue;
value = comparator[key];
aValue = (_ref = typeof a.get === "function" ? a.get(key) : void 0) != null ? _ref : a[key];
bValue = (_ref1 = typeof b.get === "function" ? b.get(key) : void 0) != null ? _ref1 : 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);
Hash.prototype.arr = [];
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);
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);
return QueryCollection.__super__.constructor.apply(this, arguments);
}
QueryCollection.prototype.model = Backbone.Model;
QueryCollection.prototype.initialize = function(models, options) {
var key, me, value, _ref, _ref1, _ref2;
me = this;
if ((_ref = this.options) == null) {
this.options = {};
}
_.extend(this.options, options);
_ref1 = Criteria.prototype;
for (key in _ref1) {
if (!__hasProp.call(_ref1, key)) continue;
value = _ref1[key];
if ((_ref2 = this[key]) == null) {
this[key] = value;
}
}
if (this.comparator != null) {
this.setComparator(this.comparator);
}
this.applyCriteria(options);
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, _ref, _ref1;
options || (options = {});
options.parentCollection = this;
if ((_ref = options.collection) == null) {
options.collection = this.collection || QueryCollection;
}
if ((_ref1 = 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;
model || (model = {});
if ((model.id != null) && this.get(model.id)) {
exists = true;
} else if ((model.cid != null) && this.getByCid(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, criteria, paging, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
collection = this.createChildCollection([], criteria).query();
return collection;
};
QueryCollection.prototype.findAllLive = function() {
var args, collection, comparator, criteria, paging, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
collection = this.createLiveChildCollection([], criteria).query();
return collection;
};
QueryCollection.prototype.findOne = function() {
var args, comparator, criteria, paging, passed, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
passed = this.testModels(this.models, criteria);
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) {
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, comparator, criteria, models, paging, passed, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1) {
if (args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
criteria = args[0];
}
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
collection = this.getParentCollection() || this;
models = collection.models;
passed = this.testModels(models, criteria);
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 ? _.clone(options) : {};
models = _.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 ? _.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;
pass = this.test(model);
if (!pass) {
this.safeRemove(model);
} else {
if (this.comparator) {
this.sortCollection();
}
}
return this;
};
QueryCollection.prototype.onParentChange = function(model) {
var pass;
pass = this.test(model) && this.getParentCollection().hasModel(model);
if (pass) {
this.safeAdd(model);
} else {
this.safeRemove(model);
}
return this;
};
QueryCollection.prototype.onParentRemove = function(model) {
this.safeRemove(model);
return this;
};
QueryCollection.prototype.onParentAdd = function(model) {
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(options) {
this.applyCriteria = __bind(this.applyCriteria, this);
var _ref;
if ((_ref = this.options) == null) {
this.options = {};
}
_.extend(this.options, options);
this;
}
Criteria.prototype.applyCriteria = function(options) {
var _base;
if (options == null) {
options = {};
}
this.options.filters = _.extend({}, this.options.filters || {});
this.options.queries = _.extend({}, this.options.queries || {});
this.options.pills = _.extend({}, this.options.pills || {});
(_base = this.options).searchString || (_base.searchString = null);
this.options.paging = _.extend({}, this.options.paging || {});
this.setFilters(this.options.filters);
this.setQueries(this.options.queries);
this.setPills(this.options.pills);
if (this.options.searchString != null) {
this.setSearchString(this.options.searchString);
}
this.setPaging(this.options.paging);
if (this.options.comparator != null) {
this.setComparator(this.options.comparator);
}
return this;
};
Criteria.prototype.getPaging = function() {
return this.options.paging;
};
Criteria.prototype.setPaging = function(paging) {
paging = _.extend(this.getPaging(), paging || {});
paging.page || (paging.page = null);
paging.limit || (paging.limit = null);
paging.offset || (paging.offset = null);
this.options.paging = paging;
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, criteria) {
var passed;
if (criteria == null) {
criteria = {};
}
passed = this.testFilters(model, criteria.filters) && this.testQueries(model, criteria.queries) && this.testPills(model, criteria.pills);
return passed;
};
Criteria.prototype.testModels = function(models, criteria) {
var comparator, finish, me, model, paging, pass, passed, start, _i, _len, _ref;
if (criteria == null) {
criteria = {};
}
me = this;
passed = [];
paging = (_ref = criteria.paging) != null ? _ref : this.getPaging();
if (criteria.comparator != null) {
comparator = util.generateComparator(criteria.comparator);
} else {
comparator = this.getComparator();
}
for (_i = 0, _len = models.length; _i < _len; _i++) {
model = models[_i];
pass = me.testModel(model, criteria);
if (pass) {
passed.push(model);
}
}
if (comparator) {
passed.sort(comparator);
}
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 {
passed = passed.slice(start);
}
return passed;
};
Criteria.prototype.testFilters = function(model, filters) {
var cleanedSearchString, filter, filterName, passed;
passed = true;
cleanedSearchString = this.getCleanedSearchString();
if (filters == null) {
filters = this.getFilters();
}
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.testQueries = function(model, queries) {
var passed, query, queryName;
passed = true;
if (queries == null) {
queries = this.getQueries();
}
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.testPills = function(model, pills) {
var passed, pill, pillName, searchString;
passed = true;
searchString = this.getSearchString();
if (pills == null) {
pills = this.getPills();
}
if (searchString != null) {
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, _ref;
pill || (pill = {});
this.callback = pill.callback;
this.prefixes = pill.prefixes;
if (pill.logicalOperator != null) {
this.logicalOperator = pill.logicalOperator;
}
safePrefixes = [];
_ref = this.prefixes;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
prefix = _ref[_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, _ref, _ref1, _ref2;
if ((_ref = this.values) != null ? _ref.length : void 0) {
if (this.logicalOperator === 'OR') {
pass = false;
_ref1 = this.values;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
value = _ref1[_i];
pass = this.callback(model, value);
if (pass) {
break;
}
}
} else if (this.logicalOperator === 'AND') {
pass = false;
_ref2 = this.values;
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
value = _ref2[_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.query = null;
function Query(query) {
if (query == null) {
query = {};
}
this.query = query;
}
Query.prototype.test = function(model) {
var $mod, beginsWithValue, empty, endWithValue, match, matchAll, matchAny, modelId, modelValue, modelValueExists, query, queryGroup, queryType, queryValue, selectorName, selectorValue, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref;
matchAll = true;
matchAny = false;
empty = true;
_ref = this.query;
for (selectorName in _ref) {
if (!__hasProp.call(_ref, selectorName)) continue;
selectorValue = _ref[selectorName];
match = false;
empty = false;
modelValue = model.get(selectorName);
modelId = model.get('id');
modelValueExists = typeof modelValue !== 'undefined';
if (!modelValueExists) {
modelValue = false;
}
if (selectorName === '$or' || selectorName === '$nor') {
queryGroup = util.toArrayGroup(selectorValue);
if (!queryGroup.length) {
throw new Error("Query called with an empty " + selectorName + " statement");
}
for (_i = 0, _len = queryGroup.length; _i < _len; _i++) {
query = queryGroup[_i];
query = new Query(query);
if (query.test(model)) {
match = true;
break;
}
}
if (selectorName === '$nor') {
match = !match;
}
} else if (selectorName === '$and' || selectorName === '$not') {
queryGroup = util.toArrayGroup(selectorValue);
if (!queryGroup.length) {
throw new Error("Query called with an empty " + selectorName + " statement");
}
for (_j = 0, _len1 = queryGroup.length; _j < _len1; _j++) {
query = queryGroup[_j];
query = new Query(query);
match = query.test(model);
if (!match) {
break;
}
}
if (selectorName === '$not') {
match = !match;
}
} else if (util.isString(selectorValue) || util.isNumber(selectorValue) || util.isBoolean(selectorValue)) {
if (modelValueExists && modelValue === selectorValue) {
match = true;
}
} else if (util.isArray(selectorValue)) {
if (modelValueExists && (new Hash(modelValue)).isSame(selectorValue)) {
match = true;
}
} else if (util.isDate(selectorValue)) {
if (modelValueExists && modelValue.toString() === selectorValue.toString()) {
match = true;
}
} else if (util.isRegExp(selectorValue)) {
if (modelValueExists && selectorValue.test(modelValue)) {
match = true;
}
} else if (util.isNull(selectorValue)) {
if (modelValue === selectorValue) {
match = true;
}
} else if (util.isObject(selectorValue)) {
for (queryType in selectorValue) {
if (!__hasProp.call(selectorValue, queryType)) continue;
queryValue = selectorValue[queryType];
switch (queryType) {
case '$beginsWith':
case '$startsWith':
if (queryValue && modelValueExists && util.isString(modelValue)) {
if (!util.isArray(queryValue)) {
queryValue = [queryValue];
}
for (_k = 0, _len2 = queryValue.length; _k < _len2; _k++) {
beginsWithValue = queryValue[_k];
if (modelValue.substr(0, beginsWithValue.length) === beginsWithValue) {
match = true;
break;
}
}
}
break;
case '$endsWith':
case '$finishesWith':
if (queryValue && modelValueExists && util.isString(modelValue)) {
if (!util.isArray(queryValue)) {
queryValue = [queryValue];
}
for (_l = 0, _len3 = queryValue.length; _l < _len3; _l++) {
endWithValue = queryValue[_l];
if (modelValue.substr(endWithValue.length * -1) === endWithValue) {
match = true;
break;
}
}
}
break;
case '$all':
if ((queryValue != null) && modelValueExists) {
if ((new Hash(modelValue)).hasAll(queryValue)) {
match = true;
}
}
break;
case '$in':
if ((queryValue != null) && modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue) || (new Hash(queryValue)).hasIn(modelValue)) {
match = true;
}
}
break;
case '$nin':
if ((queryValue != null) && modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue) === false && (new Hash(queryValue)).hasIn(modelValue) === false) {
match = true;
}
}
break;
case '$has':
if (modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue)) {
match = true;
}
}
break;
case '$hasAll':
if (modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue)) {
match = true;
}
}
break;
case '$size':
case '$length':
if (modelValue.length != null) {
if (modelValue.length === queryValue) {
match = true;
}
}
break;
case '$type':
if (typeof modelValue === queryValue) {
match = true;
}
break;
case '$like':
if (util.isString(modelValue) && modelValue.toLowerCase().indexOf(queryValue.toLowerCase()) !== -1) {
match = true;
}
break;
case '$likeSensitive':
if (util.isString(modelValue) && modelValue.indexOf(queryValue) !== -1) {
match = true;
}
break;
case '$exists':
if (queryValue === modelValueExists) {
match = true;
}
break;
case '$mod':
if (modelValueExists) {
$mod = queryValue;
if (!util.isArray($mod)) {
$mod = [$mod];
}
if ($mod.length === 1) {
$mod.push(0);
}
if ((modelValue % $mod[0]) === $mod[1]) {
match = true;
}
}
break;
case '$eq':
case '$equal':
if (util.isEqual(modelValue, queryValue)) {
match = true;
}
break;
case '$ne':
if (modelValue !== queryValue) {
match = true;
}
break;
case '$lt':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue < queryValue) {
match = true;
}
break;
case '$gt':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue > queryValue) {
match = true;
}
break;
case '$bt':
if ((queryValue != null) && util.isComparable(modelValue) && queryValue[0] < modelValue && modelValue < queryValue[1]) {
match = true;
}
break;
case '$lte':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue <= queryValue) {
match = true;
}
break;
case '$gte':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue >= queryValue) {
match = true;
}
break;
case '$bte':
if ((queryValue != null) && util.isComparable(modelValue) && queryValue[0] <= modelValue && modelValue <= queryValue[1]) {
match = true;
}
}
}
}
if (match) {
matchAny = true;
} else {
matchAll = false;
}
}
if (matchAll && !matchAny) {
matchAll = false;
}
return matchAll;
};
return Query;
})();
queryEngine = {
safeRegex: util.safeRegex,
createRegex: util.createRegex,
createSafeRegex: util.createSafeRegex,
generateComparator: util.generateComparator,
toArray: util.toArray,
Backbone: Backbone,
Hash: Hash,
QueryCollection: QueryCollection,
Criteria: Criteria,
Query: Query,
Pill: Pill,
createCollection: function(models, options) {
var collection;
models = util.toArray(models);
collection = new QueryCollection(models, options);
return collection;
},
createLiveCollection: function(models, options) {
var collection;
models = util.toArray(models);
collection = new QueryCollection(models, options).live(true);
return collection;
}
};
if (typeof module !== "undefined" && module !== null) {
module.exports = queryEngine;
} else {
this.queryEnginePublished131 = queryEngine;
}
}).call(this);
// Generated by CoffeeScript 1.3.3
(function() {
var Backbone, Criteria, Hash, Pill, Query, QueryCollection, queryEngine, util, _,
__hasProp = {}.hasOwnProperty,
__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); }; },
__slice = [].slice;
_ = typeof module !== "undefined" && module !== null ? require('underscore') : this._;
Backbone = typeof module !== "undefined" && module !== null ? require('backbone') : this.Backbone;
util = {
isEqual: function(value1, value2) {
return _.isEqual(value1, value2);
},
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;
},
isComparable: function(value) {
return util.isNumber(value) || util.isDate(value);
},
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;
result = [];
if (value) {
if (util.isArray(value)) {
result = value;
} 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;
result = [];
if (value) {
if (util.isArray(value)) {
result = value;
} 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) {
throw new Error('Cannot sort without a comparator');
} 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, _ref, _ref1;
comparison = 0;
for (key in comparator) {
if (!__hasProp.call(comparator, key)) continue;
value = comparator[key];
aValue = (_ref = typeof a.get === "function" ? a.get(key) : void 0) != null ? _ref : a[key];
bValue = (_ref1 = typeof b.get === "function" ? b.get(key) : void 0) != null ? _ref1 : 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);
Hash.prototype.arr = [];
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);
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);
return QueryCollection.__super__.constructor.apply(this, arguments);
}
QueryCollection.prototype.model = Backbone.Model;
QueryCollection.prototype.initialize = function(models, options) {
var key, me, value, _ref, _ref1, _ref2;
me = this;
if ((_ref = this.options) == null) {
this.options = {};
}
_.extend(this.options, options);
_ref1 = Criteria.prototype;
for (key in _ref1) {
if (!__hasProp.call(_ref1, key)) continue;
value = _ref1[key];
if ((_ref2 = this[key]) == null) {
this[key] = value;
}
}
if (this.comparator != null) {
this.setComparator(this.comparator);
}
this.applyCriteria(options);
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, _ref, _ref1;
options || (options = {});
options.parentCollection = this;
if ((_ref = options.collection) == null) {
options.collection = this.collection || QueryCollection;
}
if ((_ref1 = 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;
model || (model = {});
if ((model.id != null) && this.get(model.id)) {
exists = true;
} else if ((model.cid != null) && this.getByCid(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, criteria, paging, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
collection = this.createChildCollection([], criteria).query();
return collection;
};
QueryCollection.prototype.findAllLive = function() {
var args, collection, comparator, criteria, paging, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
collection = this.createLiveChildCollection([], criteria).query();
return collection;
};
QueryCollection.prototype.findOne = function() {
var args, comparator, criteria, paging, passed, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
passed = this.testModels(this.models, criteria);
if ((passed != null ? passed.length : void 0) !== 0) {
return passed[0];
} else {
return null;
}
};
QueryCollection.prototype.query = function() {
var args, collection, criteria, models, 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]
};
}
}
collection = this.getParentCollection() || this;
models = collection.models;
passed = this.testModels(models, criteria);
this.reset(passed);
return this;
};
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 ? _.clone(options) : {};
models = _.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 ? _.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;
pass = this.test(model);
if (!pass) {
this.safeRemove(model);
} else {
if (this.comparator) {
this.sortCollection();
}
}
return this;
};
QueryCollection.prototype.onParentChange = function(model) {
var pass;
pass = this.test(model) && this.getParentCollection().hasModel(model);
if (pass) {
this.safeAdd(model);
} else {
this.safeRemove(model);
}
return this;
};
QueryCollection.prototype.onParentRemove = function(model) {
this.safeRemove(model);
return this;
};
QueryCollection.prototype.onParentAdd = function(model) {
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(options) {
this.applyCriteria = __bind(this.applyCriteria, this);
var _ref;
if ((_ref = this.options) == null) {
this.options = {};
}
_.extend(this.options, options);
this;
}
Criteria.prototype.applyCriteria = function(options) {
var _base;
if (options == null) {
options = {};
}
this.options.filters = _.extend({}, this.options.filters || {});
this.options.queries = _.extend({}, this.options.queries || {});
this.options.pills = _.extend({}, this.options.pills || {});
(_base = this.options).searchString || (_base.searchString = null);
this.options.paging = _.extend({}, this.options.paging || {});
this.setFilters(this.options.filters);
this.setQueries(this.options.queries);
this.setPills(this.options.pills);
if (this.options.searchString != null) {
this.setSearchString(this.options.searchString);
}
this.setPaging(this.options.paging);
if (this.options.comparator != null) {
this.setComparator(this.options.comparator);
}
return this;
};
Criteria.prototype.getPaging = function() {
return this.options.paging;
};
Criteria.prototype.setPaging = function(paging) {
paging = _.extend(this.getPaging(), paging || {});
paging.page || (paging.page = null);
paging.limit || (paging.limit = null);
paging.offset || (paging.offset = null);
this.options.paging = paging;
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, criteria) {
var passed;
if (criteria == null) {
criteria = {};
}
passed = this.testFilters(model, criteria.filters) && this.testQueries(model, criteria.queries) && this.testPills(model, criteria.pills);
return passed;
};
Criteria.prototype.testModels = function(models, criteria) {
var comparator, finish, me, model, paging, pass, passed, start, _i, _len, _ref, _ref1;
if (criteria == null) {
criteria = {};
}
me = this;
passed = [];
if (models == null) {
models = this.models;
}
paging = (_ref = criteria.paging) != null ? _ref : this.getPaging();
comparator = (_ref1 = criteria.comparator) != null ? _ref1 : this.getComparator();
for (_i = 0, _len = models.length; _i < _len; _i++) {
model = models[_i];
pass = me.testModel(model, criteria);
if (pass) {
passed.push(model);
}
}
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 {
passed = passed.slice(start);
}
if (comparator) {
passed.sort(comparator);
}
return passed;
};
Criteria.prototype.testFilters = function(model, filters) {
var cleanedSearchString, filter, filterName, passed;
passed = true;
cleanedSearchString = this.getCleanedSearchString();
if (filters == null) {
filters = this.getFilters();
}
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.testQueries = function(model, queries) {
var passed, query, queryName;
passed = true;
if (queries == null) {
queries = this.getQueries();
}
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.testPills = function(model, pills) {
var passed, pill, pillName, searchString;
passed = true;
searchString = this.getSearchString();
if (pills == null) {
pills = this.getPills();
}
if (searchString != null) {
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, _ref;
pill || (pill = {});
this.callback = pill.callback;
this.prefixes = pill.prefixes;
if (pill.logicalOperator != null) {
this.logicalOperator = pill.logicalOperator;
}
safePrefixes = [];
_ref = this.prefixes;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
prefix = _ref[_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, _ref, _ref1, _ref2;
if ((_ref = this.values) != null ? _ref.length : void 0) {
if (this.logicalOperator === 'OR') {
pass = false;
_ref1 = this.values;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
value = _ref1[_i];
pass = this.callback(model, value);
if (pass) {
break;
}
}
} else if (this.logicalOperator === 'AND') {
pass = false;
_ref2 = this.values;
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
value = _ref2[_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.query = null;
function Query(query) {
if (query == null) {
query = {};
}
this.query = query;
}
Query.prototype.test = function(model) {
var $beginsWith, $beginsWithValue, $endWithValue, $endsWith, $mod, $size, empty, match, matchAll, matchAny, modelId, modelValue, modelValueExists, query, queryGroup, selectorName, selectorValue, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref;
matchAll = true;
matchAny = false;
empty = true;
_ref = this.query;
for (selectorName in _ref) {
if (!__hasProp.call(_ref, selectorName)) continue;
selectorValue = _ref[selectorName];
match = false;
empty = false;
modelValue = model.get(selectorName);
modelId = model.get('id');
modelValueExists = typeof modelValue !== 'undefined';
if (!modelValueExists) {
modelValue = false;
}
if (selectorName === '$or' || selectorName === '$nor') {
queryGroup = util.toArrayGroup(selectorValue);
if (!queryGroup.length) {
throw new Error("Query called with an empty " + selectorName + " statement");
}
for (_i = 0, _len = queryGroup.length; _i < _len; _i++) {
query = queryGroup[_i];
query = new Query(query);
if (query.test(model)) {
match = true;
break;
}
}
if (selectorName === '$nor') {
match = !match;
}
} else if (selectorName === '$and' || selectorName === '$not') {
queryGroup = util.toArrayGroup(selectorValue);
if (!queryGroup.length) {
throw new Error("Query called with an empty " + selectorName + " statement");
}
for (_j = 0, _len1 = queryGroup.length; _j < _len1; _j++) {
query = queryGroup[_j];
query = new Query(query);
match = query.test(model);
if (!match) {
break;
}
}
if (selectorName === '$not') {
match = !match;
}
} else if (util.isString(selectorValue) || util.isNumber(selectorValue) || util.isBoolean(selectorValue)) {
if (modelValueExists && modelValue === selectorValue) {
match = true;
}
} else if (util.isArray(selectorValue)) {
if (modelValueExists && (new Hash(modelValue)).isSame(selectorValue)) {
match = true;
}
} else if (util.isDate(selectorValue)) {
if (modelValueExists && modelValue.toString() === selectorValue.toString()) {
match = true;
}
} else if (util.isRegExp(selectorValue)) {
if (modelValueExists && selectorValue.test(modelValue)) {
match = true;
}
} else if (util.isNull(selectorValue)) {
if (modelValue === selectorValue) {
match = true;
}
} else if (util.isObject(selectorValue)) {
$beginsWith = selectorValue.$beginsWith || selectorValue.$startsWith || null;
if ($beginsWith && modelValueExists && util.isString(modelValue)) {
if (!util.isArray($beginsWith)) {
$beginsWith = [$beginsWith];
}
for (_k = 0, _len2 = $beginsWith.length; _k < _len2; _k++) {
$beginsWithValue = $beginsWith[_k];
if (modelValue.substr(0, $beginsWithValue.length) === $beginsWithValue) {
match = true;
break;
}
}
}
$endsWith = selectorValue.$endsWith || selectorValue.$finishesWith || null;
if ($endsWith && modelValueExists && util.isString(modelValue)) {
if (!util.isArray($endsWith)) {
$endsWith = [$endsWith];
}
for (_l = 0, _len3 = $endsWith.length; _l < _len3; _l++) {
$endWithValue = $endsWith[_l];
if (modelValue.substr($endWithValue.length * -1) === $endWithValue) {
match = true;
break;
}
}
}
if (selectorValue.$all != null) {
if (modelValueExists) {
if ((new Hash(modelValue)).hasAll(selectorValue.$all)) {
match = true;
}
}
}
if (selectorValue.$in != null) {
if (modelValueExists) {
if ((new Hash(modelValue)).hasIn(selectorValue.$in)) {
match = true;
} else if ((new Hash(selectorValue.$in)).hasIn(modelValue)) {
match = true;
}
}
}
if (selectorValue.$has != null) {
if (modelValueExists) {
if ((new Hash(modelValue)).hasIn(selectorValue.$has)) {
match = true;
}
}
}
if (selectorValue.$hasAll != null) {
if (modelValueExists) {
if ((new Hash(modelValue)).hasIn(selectorValue.$hasAll)) {
match = true;
}
}
}
if (selectorValue.$nin != null) {
if (modelValueExists) {
if ((new Hash(modelValue)).hasIn(selectorValue.$nin) === false && (new Hash(selectorValue.$nin)).hasIn(selectorValue) === false) {
match = true;
}
}
}
$size = selectorValue.$size || selectorValue.$length;
if ($size != null) {
if ((modelValue.length != null) && modelValue.length === $size) {
match = true;
}
}
if (selectorValue.$type) {
if (typeof modelValue === selectorValue.$type) {
match = true;
}
}
if (selectorValue.$like != null) {
if (util.isString(modelValue) && modelValue.toLowerCase().indexOf(selectorValue.$like.toLowerCase()) !== -1) {
match = true;
}
}
if (selectorValue.$likeSensitive != null) {
if (util.isString(modelValue) && modelValue.indexOf(selectorValue.$likeSensitive) !== -1) {
match = true;
}
}
if (selectorValue.$exists != null) {
if (selectorValue.$exists) {
if (modelValueExists === true) {
match = true;
}
} else {
if (modelValueExists === false) {
match = true;
}
}
}
if (selectorValue.$mod != null) {
if (modelValueExists) {
$mod = selectorValue.$mod;
if (!util.isArray($mod)) {
$mod = [$mod];
}
if ($mod.length === 1) {
$mod.push(0);
}
if ((modelValue % $mod[0]) === $mod[1]) {
match = true;
}
}
}
if (util.isDefined(selectorValue.$eq)) {
if (util.isEqual(modelValue, selectorValue.$eq)) {
match = true;
}
}
if (util.isDefined(selectorValue.$ne)) {
if (modelValue !== selectorValue.$ne) {
match = true;
}
}
if (selectorValue.$lt != null) {
if (util.isComparable(modelValue) && modelValue < selectorValue.$lt) {
match = true;
}
}
if (selectorValue.$gt != null) {
if (util.isComparable(modelValue) && modelValue > selectorValue.$gt) {
match = true;
}
}
if (selectorValue.$bt != null) {
if (util.isComparable(modelValue) && selectorValue.$bt[0] < modelValue && modelValue < selectorValue.$bt[1]) {
match = true;
}
}
if (selectorValue.$lte != null) {
if (util.isComparable(modelValue) && modelValue <= selectorValue.$lte) {
match = true;
}
}
if (selectorValue.$gte != null) {
if (util.isComparable(modelValue) && modelValue >= selectorValue.$gte) {
match = true;
}
}
if (selectorValue.$bte != null) {
if (util.isComparable(modelValue) && selectorValue.$bte[0] <= modelValue && modelValue <= selectorValue.$bte[1]) {
match = true;
}
}
}
if (match) {
matchAny = true;
} else {
matchAll = false;
}
}
if (matchAll && !matchAny) {
matchAll = false;
}
return matchAll;
};
return Query;
})();
queryEngine = {
safeRegex: util.safeRegex,
createRegex: util.createRegex,
createSafeRegex: util.createSafeRegex,
generateComparator: util.generateComparator,
toArray: util.toArray,
Backbone: Backbone,
Hash: Hash,
QueryCollection: QueryCollection,
Query: Query,
Pill: Pill,
createCollection: function(models, options) {
var collection;
models = util.toArray(models);
collection = new QueryCollection(models, options);
return collection;
},
createLiveCollection: function(models, options) {
var collection;
models = util.toArray(models);
collection = new QueryCollection(models, options).live(true);
return collection;
}
};
if (typeof module !== "undefined" && module !== null) {
module.exports = queryEngine;
} else {
this.queryEngineRewrite1 = queryEngine;
}
}).call(this);
// Generated by CoffeeScript 1.3.3
(function() {
var Backbone, Criteria, Hash, Pill, Query, QueryCollection, queryEngine, util, _,
__hasProp = {}.hasOwnProperty,
__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); }; },
__slice = [].slice;
_ = typeof module !== "undefined" && module !== null ? require('underscore') : this._;
Backbone = typeof module !== "undefined" && module !== null ? require('backbone') : this.Backbone;
util = {
isEqual: function(value1, value2) {
return _.isEqual(value1, value2);
},
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;
},
isComparable: function(value) {
return util.isNumber(value) || util.isDate(value);
},
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;
result = [];
if (value) {
if (util.isArray(value)) {
result = value;
} 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;
result = [];
if (value) {
if (util.isArray(value)) {
result = value;
} 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) {
throw new Error('Cannot sort without a comparator');
} 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, _ref, _ref1;
comparison = 0;
for (key in comparator) {
if (!__hasProp.call(comparator, key)) continue;
value = comparator[key];
aValue = (_ref = typeof a.get === "function" ? a.get(key) : void 0) != null ? _ref : a[key];
bValue = (_ref1 = typeof b.get === "function" ? b.get(key) : void 0) != null ? _ref1 : 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);
Hash.prototype.arr = [];
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);
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);
return QueryCollection.__super__.constructor.apply(this, arguments);
}
QueryCollection.prototype.model = Backbone.Model;
QueryCollection.prototype.initialize = function(models, options) {
var key, me, value, _ref, _ref1, _ref2;
me = this;
if ((_ref = this.options) == null) {
this.options = {};
}
_.extend(this.options, options);
_ref1 = Criteria.prototype;
for (key in _ref1) {
if (!__hasProp.call(_ref1, key)) continue;
value = _ref1[key];
if ((_ref2 = this[key]) == null) {
this[key] = value;
}
}
if (this.comparator != null) {
this.setComparator(this.comparator);
}
this.applyCriteria(options);
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, _ref, _ref1;
options || (options = {});
options.parentCollection = this;
if ((_ref = options.collection) == null) {
options.collection = this.collection || QueryCollection;
}
if ((_ref1 = 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;
model || (model = {});
if ((model.id != null) && this.get(model.id)) {
exists = true;
} else if ((model.cid != null) && this.getByCid(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, criteria, paging, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
collection = this.createChildCollection([], criteria).query();
return collection;
};
QueryCollection.prototype.findAllLive = function() {
var args, collection, comparator, criteria, paging, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
collection = this.createLiveChildCollection([], criteria).query();
return collection;
};
QueryCollection.prototype.findOne = function() {
var args, comparator, criteria, paging, passed, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
passed = this.testModels(this.models, criteria);
if ((passed != null ? passed.length : void 0) !== 0) {
return passed[0];
} else {
return null;
}
};
QueryCollection.prototype.query = function() {
var args, collection, criteria, models, 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]
};
}
}
collection = this.getParentCollection() || this;
models = collection.models;
passed = this.testModels(models, criteria);
this.reset(passed);
return this;
};
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 ? _.clone(options) : {};
models = _.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 ? _.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;
pass = this.test(model);
if (!pass) {
this.safeRemove(model);
} else {
if (this.comparator) {
this.sortCollection();
}
}
return this;
};
QueryCollection.prototype.onParentChange = function(model) {
var pass;
pass = this.test(model) && this.getParentCollection().hasModel(model);
if (pass) {
this.safeAdd(model);
} else {
this.safeRemove(model);
}
return this;
};
QueryCollection.prototype.onParentRemove = function(model) {
this.safeRemove(model);
return this;
};
QueryCollection.prototype.onParentAdd = function(model) {
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(options) {
this.applyCriteria = __bind(this.applyCriteria, this);
var _ref;
if ((_ref = this.options) == null) {
this.options = {};
}
_.extend(this.options, options);
this;
}
Criteria.prototype.applyCriteria = function(options) {
var _base;
if (options == null) {
options = {};
}
this.options.filters = _.extend({}, this.options.filters || {});
this.options.queries = _.extend({}, this.options.queries || {});
this.options.pills = _.extend({}, this.options.pills || {});
(_base = this.options).searchString || (_base.searchString = null);
this.options.paging = _.extend({}, this.options.paging || {});
this.setFilters(this.options.filters);
this.setQueries(this.options.queries);
this.setPills(this.options.pills);
if (this.options.searchString != null) {
this.setSearchString(this.options.searchString);
}
this.setPaging(this.options.paging);
if (this.options.comparator != null) {
this.setComparator(this.options.comparator);
}
return this;
};
Criteria.prototype.getPaging = function() {
return this.options.paging;
};
Criteria.prototype.setPaging = function(paging) {
paging = _.extend(this.getPaging(), paging || {});
paging.page || (paging.page = null);
paging.limit || (paging.limit = null);
paging.offset || (paging.offset = null);
this.options.paging = paging;
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, criteria) {
var passed;
if (criteria == null) {
criteria = {};
}
passed = this.testFilters(model, criteria.filters) && this.testQueries(model, criteria.queries) && this.testPills(model, criteria.pills);
return passed;
};
Criteria.prototype.testModels = function(models, criteria) {
var comparator, finish, me, model, paging, pass, passed, start, _i, _len, _ref, _ref1;
if (criteria == null) {
criteria = {};
}
me = this;
passed = [];
if (models == null) {
models = this.models;
}
paging = (_ref = criteria.paging) != null ? _ref : this.getPaging();
comparator = (_ref1 = criteria.comparator) != null ? _ref1 : this.getComparator();
for (_i = 0, _len = models.length; _i < _len; _i++) {
model = models[_i];
pass = me.testModel(model, criteria);
if (pass) {
passed.push(model);
}
}
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 {
passed = passed.slice(start);
}
if (comparator) {
passed.sort(comparator);
}
return passed;
};
Criteria.prototype.testFilters = function(model, filters) {
var cleanedSearchString, filter, filterName, passed;
passed = true;
cleanedSearchString = this.getCleanedSearchString();
if (filters == null) {
filters = this.getFilters();
}
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.testQueries = function(model, queries) {
var passed, query, queryName;
passed = true;
if (queries == null) {
queries = this.getQueries();
}
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.testPills = function(model, pills) {
var passed, pill, pillName, searchString;
passed = true;
searchString = this.getSearchString();
if (pills == null) {
pills = this.getPills();
}
if (searchString != null) {
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, _ref;
pill || (pill = {});
this.callback = pill.callback;
this.prefixes = pill.prefixes;
if (pill.logicalOperator != null) {
this.logicalOperator = pill.logicalOperator;
}
safePrefixes = [];
_ref = this.prefixes;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
prefix = _ref[_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, _ref, _ref1, _ref2;
if ((_ref = this.values) != null ? _ref.length : void 0) {
if (this.logicalOperator === 'OR') {
pass = false;
_ref1 = this.values;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
value = _ref1[_i];
pass = this.callback(model, value);
if (pass) {
break;
}
}
} else if (this.logicalOperator === 'AND') {
pass = false;
_ref2 = this.values;
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
value = _ref2[_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.query = null;
function Query(query) {
if (query == null) {
query = {};
}
this.query = query;
}
Query.prototype.test = function(model) {
var $mod, beginsWithValue, empty, endWithValue, match, matchAll, matchAny, modelId, modelValue, modelValueExists, query, queryGroup, queryType, queryValue, selectorName, selectorValue, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref;
matchAll = true;
matchAny = false;
empty = true;
_ref = this.query;
for (selectorName in _ref) {
if (!__hasProp.call(_ref, selectorName)) continue;
selectorValue = _ref[selectorName];
match = false;
empty = false;
modelValue = model.get(selectorName);
modelId = model.get('id');
modelValueExists = typeof modelValue !== 'undefined';
if (!modelValueExists) {
modelValue = false;
}
if (selectorName === '$or' || selectorName === '$nor') {
queryGroup = util.toArrayGroup(selectorValue);
if (!queryGroup.length) {
throw new Error("Query called with an empty " + selectorName + " statement");
}
for (_i = 0, _len = queryGroup.length; _i < _len; _i++) {
query = queryGroup[_i];
query = new Query(query);
if (query.test(model)) {
match = true;
break;
}
}
if (selectorName === '$nor') {
match = !match;
}
} else if (selectorName === '$and' || selectorName === '$not') {
queryGroup = util.toArrayGroup(selectorValue);
if (!queryGroup.length) {
throw new Error("Query called with an empty " + selectorName + " statement");
}
for (_j = 0, _len1 = queryGroup.length; _j < _len1; _j++) {
query = queryGroup[_j];
query = new Query(query);
match = query.test(model);
if (!match) {
break;
}
}
if (selectorName === '$not') {
match = !match;
}
} else if (util.isString(selectorValue) || util.isNumber(selectorValue) || util.isBoolean(selectorValue)) {
if (modelValueExists && modelValue === selectorValue) {
match = true;
}
} else if (util.isArray(selectorValue)) {
if (modelValueExists && (new Hash(modelValue)).isSame(selectorValue)) {
match = true;
}
} else if (util.isDate(selectorValue)) {
if (modelValueExists && modelValue.toString() === selectorValue.toString()) {
match = true;
}
} else if (util.isRegExp(selectorValue)) {
if (modelValueExists && selectorValue.test(modelValue)) {
match = true;
}
} else if (util.isNull(selectorValue)) {
if (modelValue === selectorValue) {
match = true;
}
} else if (util.isObject(selectorValue)) {
for (queryType in selectorValue) {
if (!__hasProp.call(selectorValue, queryType)) continue;
queryValue = selectorValue[queryType];
switch (queryType) {
case '$beginsWith':
case '$startsWith':
if (queryValue && modelValueExists && util.isString(modelValue)) {
if (!util.isArray(queryValue)) {
queryValue = [queryValue];
}
for (_k = 0, _len2 = queryValue.length; _k < _len2; _k++) {
beginsWithValue = queryValue[_k];
if (modelValue.substr(0, beginsWithValue.length) === beginsWithValue) {
match = true;
break;
}
}
}
break;
case '$endsWith':
case '$finishesWith':
if (queryValue && modelValueExists && util.isString(modelValue)) {
if (!util.isArray(queryValue)) {
queryValue = [queryValue];
}
for (_l = 0, _len3 = queryValue.length; _l < _len3; _l++) {
endWithValue = queryValue[_l];
if (modelValue.substr(endWithValue.length * -1) === endWithValue) {
match = true;
break;
}
}
}
break;
case '$all':
if ((queryValue != null) && modelValueExists) {
if ((new Hash(modelValue)).hasAll(queryValue)) {
match = true;
}
}
break;
case '$in':
if ((queryValue != null) && modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue) || (new Hash(queryValue)).hasIn(modelValue)) {
match = true;
}
}
break;
case '$nin':
if ((queryValue != null) && modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue) === false && (new Hash(queryValue)).hasIn(modelValue) === false) {
match = true;
}
}
break;
case '$has':
if (modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue)) {
match = true;
}
}
break;
case '$hasAll':
if (modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue)) {
match = true;
}
}
break;
case '$size':
case '$length':
if (modelValue.length != null) {
if (modelValue.length === queryValue) {
match = true;
}
}
break;
case '$type':
if (typeof modelValue === queryValue) {
match = true;
}
break;
case '$like':
if (util.isString(modelValue) && modelValue.toLowerCase().indexOf(queryValue.toLowerCase()) !== -1) {
match = true;
}
break;
case '$likeSensitive':
if (util.isString(modelValue) && modelValue.indexOf(queryValue) !== -1) {
match = true;
}
break;
case '$exists':
if (queryValue === modelValueExists) {
match = true;
}
break;
case '$mod':
if (modelValueExists) {
$mod = queryValue;
if (!util.isArray($mod)) {
$mod = [$mod];
}
if ($mod.length === 1) {
$mod.push(0);
}
if ((modelValue % $mod[0]) === $mod[1]) {
match = true;
}
}
break;
case '$eq':
case '$equal':
if (util.isEqual(modelValue, queryValue)) {
match = true;
}
break;
case '$ne':
if (modelValue !== queryValue) {
match = true;
}
break;
case '$lt':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue < queryValue) {
match = true;
}
break;
case '$gt':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue > queryValue) {
match = true;
}
break;
case '$bt':
if ((queryValue != null) && util.isComparable(modelValue) && queryValue[0] < modelValue && modelValue < queryValue[1]) {
match = true;
}
break;
case '$lte':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue <= queryValue) {
match = true;
}
break;
case '$gte':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue >= queryValue) {
match = true;
}
break;
case '$bte':
if ((queryValue != null) && util.isComparable(modelValue) && queryValue[0] <= modelValue && modelValue <= queryValue[1]) {
match = true;
}
}
}
}
if (match) {
matchAny = true;
} else {
matchAll = false;
}
}
if (matchAll && !matchAny) {
matchAll = false;
}
return matchAll;
};
return Query;
})();
queryEngine = {
safeRegex: util.safeRegex,
createRegex: util.createRegex,
createSafeRegex: util.createSafeRegex,
generateComparator: util.generateComparator,
toArray: util.toArray,
Backbone: Backbone,
Hash: Hash,
QueryCollection: QueryCollection,
Query: Query,
Pill: Pill,
createCollection: function(models, options) {
var collection;
models = util.toArray(models);
collection = new QueryCollection(models, options);
return collection;
},
createLiveCollection: function(models, options) {
var collection;
models = util.toArray(models);
collection = new QueryCollection(models, options).live(true);
return collection;
}
};
if (typeof module !== "undefined" && module !== null) {
module.exports = queryEngine;
} else {
this.queryEngineRewrite2 = queryEngine;
}
}).call(this);
// Generated by CoffeeScript 1.3.3
(function() {
var Backbone, Criteria, Hash, Pill, Query, QueryCollection, queryEngine, util, _,
__hasProp = {}.hasOwnProperty,
__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); }; },
__slice = [].slice;
_ = typeof module !== "undefined" && module !== null ? require('underscore') : this._;
Backbone = typeof module !== "undefined" && module !== null ? require('backbone') : this.Backbone;
util = {
isEqual: function(value1, value2) {
return _.isEqual(value1, value2);
},
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;
},
isComparable: function(value) {
return util.isNumber(value) || util.isDate(value);
},
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;
result = [];
if (value) {
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;
result = [];
if (value) {
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) {
throw new Error('Cannot sort without a comparator');
} 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, _ref, _ref1;
comparison = 0;
for (key in comparator) {
if (!__hasProp.call(comparator, key)) continue;
value = comparator[key];
aValue = (_ref = typeof a.get === "function" ? a.get(key) : void 0) != null ? _ref : a[key];
bValue = (_ref1 = typeof b.get === "function" ? b.get(key) : void 0) != null ? _ref1 : 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);
Hash.prototype.arr = [];
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);
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);
return QueryCollection.__super__.constructor.apply(this, arguments);
}
QueryCollection.prototype.model = Backbone.Model;
QueryCollection.prototype.initialize = function(models, options) {
var key, me, value, _ref, _ref1, _ref2;
me = this;
if ((_ref = this.options) == null) {
this.options = {};
}
_.extend(this.options, options);
_ref1 = Criteria.prototype;
for (key in _ref1) {
if (!__hasProp.call(_ref1, key)) continue;
value = _ref1[key];
if ((_ref2 = this[key]) == null) {
this[key] = value;
}
}
if (this.comparator != null) {
this.setComparator(this.comparator);
}
this.applyCriteria(options);
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, _ref, _ref1;
options || (options = {});
options.parentCollection = this;
if ((_ref = options.collection) == null) {
options.collection = this.collection || QueryCollection;
}
if ((_ref1 = 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;
model || (model = {});
if ((model.id != null) && this.get(model.id)) {
exists = true;
} else if ((model.cid != null) && this.getByCid(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, criteria, paging, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
collection = this.createChildCollection([], criteria).query();
return collection;
};
QueryCollection.prototype.findAllLive = function() {
var args, collection, comparator, criteria, paging, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
collection = this.createLiveChildCollection([], criteria).query();
return collection;
};
QueryCollection.prototype.findOne = function() {
var args, comparator, criteria, paging, passed, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1 && args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
passed = this.testModels(this.models, criteria);
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) {
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, comparator, criteria, models, paging, passed, query;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
if (args.length) {
if (args.length === 1) {
if (args[0] instanceof Criteria) {
criteria = args[0].options;
} else {
criteria = args[0];
}
} else {
query = args[0], comparator = args[1], paging = args[2];
criteria = {
comparator: comparator,
paging: paging,
queries: {
find: query
}
};
}
}
collection = this.getParentCollection() || this;
models = collection.models;
passed = this.testModels(models, criteria);
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 ? _.clone(options) : {};
models = _.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 ? _.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;
pass = this.test(model);
if (!pass) {
this.safeRemove(model);
} else {
if (this.comparator) {
this.sortCollection();
}
}
return this;
};
QueryCollection.prototype.onParentChange = function(model) {
var pass;
pass = this.test(model) && this.getParentCollection().hasModel(model);
if (pass) {
this.safeAdd(model);
} else {
this.safeRemove(model);
}
return this;
};
QueryCollection.prototype.onParentRemove = function(model) {
this.safeRemove(model);
return this;
};
QueryCollection.prototype.onParentAdd = function(model) {
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(options) {
this.applyCriteria = __bind(this.applyCriteria, this);
var _ref;
if ((_ref = this.options) == null) {
this.options = {};
}
_.extend(this.options, options);
this;
}
Criteria.prototype.applyCriteria = function(options) {
var _base;
if (options == null) {
options = {};
}
this.options.filters = _.extend({}, this.options.filters || {});
this.options.queries = _.extend({}, this.options.queries || {});
this.options.pills = _.extend({}, this.options.pills || {});
(_base = this.options).searchString || (_base.searchString = null);
this.options.paging = _.extend({}, this.options.paging || {});
this.setFilters(this.options.filters);
this.setQueries(this.options.queries);
this.setPills(this.options.pills);
if (this.options.searchString != null) {
this.setSearchString(this.options.searchString);
}
this.setPaging(this.options.paging);
if (this.options.comparator != null) {
this.setComparator(this.options.comparator);
}
return this;
};
Criteria.prototype.getPaging = function() {
return this.options.paging;
};
Criteria.prototype.setPaging = function(paging) {
paging = _.extend(this.getPaging(), paging || {});
paging.page || (paging.page = null);
paging.limit || (paging.limit = null);
paging.offset || (paging.offset = null);
this.options.paging = paging;
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, criteria) {
var passed;
if (criteria == null) {
criteria = {};
}
passed = this.testFilters(model, criteria.filters) && this.testQueries(model, criteria.queries) && this.testPills(model, criteria.pills);
return passed;
};
Criteria.prototype.testModels = function(models, criteria) {
var comparator, finish, me, model, paging, pass, passed, start, _i, _len, _ref;
if (criteria == null) {
criteria = {};
}
me = this;
passed = [];
paging = (_ref = criteria.paging) != null ? _ref : this.getPaging();
if (criteria.comparator != null) {
comparator = util.generateComparator(criteria.comparator);
} else {
comparator = this.getComparator();
}
for (_i = 0, _len = models.length; _i < _len; _i++) {
model = models[_i];
pass = me.testModel(model, criteria);
if (pass) {
passed.push(model);
}
}
if (comparator) {
passed.sort(comparator);
}
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 {
passed = passed.slice(start);
}
return passed;
};
Criteria.prototype.testFilters = function(model, filters) {
var cleanedSearchString, filter, filterName, passed;
passed = true;
cleanedSearchString = this.getCleanedSearchString();
if (filters == null) {
filters = this.getFilters();
}
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.testQueries = function(model, queries) {
var passed, query, queryName;
passed = true;
if (queries == null) {
queries = this.getQueries();
}
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.testPills = function(model, pills) {
var passed, pill, pillName, searchString;
passed = true;
searchString = this.getSearchString();
if (pills == null) {
pills = this.getPills();
}
if (searchString != null) {
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, _ref;
pill || (pill = {});
this.callback = pill.callback;
this.prefixes = pill.prefixes;
if (pill.logicalOperator != null) {
this.logicalOperator = pill.logicalOperator;
}
safePrefixes = [];
_ref = this.prefixes;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
prefix = _ref[_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, _ref, _ref1, _ref2;
if ((_ref = this.values) != null ? _ref.length : void 0) {
if (this.logicalOperator === 'OR') {
pass = false;
_ref1 = this.values;
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
value = _ref1[_i];
pass = this.callback(model, value);
if (pass) {
break;
}
}
} else if (this.logicalOperator === 'AND') {
pass = false;
_ref2 = this.values;
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
value = _ref2[_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.query = null;
function Query(query) {
if (query == null) {
query = {};
}
this.query = query;
}
Query.prototype.test = function(model) {
var $mod, beginsWithValue, empty, endWithValue, match, matchAll, matchAny, modelId, modelValue, modelValueExists, query, queryGroup, queryType, queryValue, selectorName, selectorValue, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref;
matchAll = true;
matchAny = false;
empty = true;
_ref = this.query;
for (selectorName in _ref) {
if (!__hasProp.call(_ref, selectorName)) continue;
selectorValue = _ref[selectorName];
match = false;
empty = false;
modelValue = model.get(selectorName);
modelId = model.get('id');
modelValueExists = typeof modelValue !== 'undefined';
if (!modelValueExists) {
modelValue = false;
}
if (selectorName === '$or' || selectorName === '$nor') {
queryGroup = util.toArrayGroup(selectorValue);
if (!queryGroup.length) {
throw new Error("Query called with an empty " + selectorName + " statement");
}
for (_i = 0, _len = queryGroup.length; _i < _len; _i++) {
query = queryGroup[_i];
query = new Query(query);
if (query.test(model)) {
match = true;
break;
}
}
if (selectorName === '$nor') {
match = !match;
}
} else if (selectorName === '$and' || selectorName === '$not') {
queryGroup = util.toArrayGroup(selectorValue);
if (!queryGroup.length) {
throw new Error("Query called with an empty " + selectorName + " statement");
}
for (_j = 0, _len1 = queryGroup.length; _j < _len1; _j++) {
query = queryGroup[_j];
query = new Query(query);
match = query.test(model);
if (!match) {
break;
}
}
if (selectorName === '$not') {
match = !match;
}
} else if (util.isString(selectorValue) || util.isNumber(selectorValue) || util.isBoolean(selectorValue)) {
if (modelValueExists && modelValue === selectorValue) {
match = true;
}
} else if (util.isArray(selectorValue)) {
if (modelValueExists && (new Hash(modelValue)).isSame(selectorValue)) {
match = true;
}
} else if (util.isDate(selectorValue)) {
if (modelValueExists && modelValue.toString() === selectorValue.toString()) {
match = true;
}
} else if (util.isRegExp(selectorValue)) {
if (modelValueExists && selectorValue.test(modelValue)) {
match = true;
}
} else if (util.isNull(selectorValue)) {
if (modelValue === selectorValue) {
match = true;
}
} else if (util.isObject(selectorValue)) {
for (queryType in selectorValue) {
if (!__hasProp.call(selectorValue, queryType)) continue;
queryValue = selectorValue[queryType];
switch (queryType) {
case '$beginsWith':
case '$startsWith':
if (queryValue && modelValueExists && util.isString(modelValue)) {
if (!util.isArray(queryValue)) {
queryValue = [queryValue];
}
for (_k = 0, _len2 = queryValue.length; _k < _len2; _k++) {
beginsWithValue = queryValue[_k];
if (modelValue.substr(0, beginsWithValue.length) === beginsWithValue) {
match = true;
break;
}
}
}
break;
case '$endsWith':
case '$finishesWith':
if (queryValue && modelValueExists && util.isString(modelValue)) {
if (!util.isArray(queryValue)) {
queryValue = [queryValue];
}
for (_l = 0, _len3 = queryValue.length; _l < _len3; _l++) {
endWithValue = queryValue[_l];
if (modelValue.substr(endWithValue.length * -1) === endWithValue) {
match = true;
break;
}
}
}
break;
case '$all':
if ((queryValue != null) && modelValueExists) {
if ((new Hash(modelValue)).hasAll(queryValue)) {
match = true;
}
}
break;
case '$in':
if ((queryValue != null) && modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue) || (new Hash(queryValue)).hasIn(modelValue)) {
match = true;
}
}
break;
case '$nin':
if ((queryValue != null) && modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue) === false && (new Hash(queryValue)).hasIn(modelValue) === false) {
match = true;
}
}
break;
case '$has':
if (modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue)) {
match = true;
}
}
break;
case '$hasAll':
if (modelValueExists) {
if ((new Hash(modelValue)).hasIn(queryValue)) {
match = true;
}
}
break;
case '$size':
case '$length':
if (modelValue.length != null) {
if (modelValue.length === queryValue) {
match = true;
}
}
break;
case '$type':
if (typeof modelValue === queryValue) {
match = true;
}
break;
case '$like':
if (util.isString(modelValue) && modelValue.toLowerCase().indexOf(queryValue.toLowerCase()) !== -1) {
match = true;
}
break;
case '$likeSensitive':
if (util.isString(modelValue) && modelValue.indexOf(queryValue) !== -1) {
match = true;
}
break;
case '$exists':
if (queryValue === modelValueExists) {
match = true;
}
break;
case '$mod':
if (modelValueExists) {
$mod = queryValue;
if (!util.isArray($mod)) {
$mod = [$mod];
}
if ($mod.length === 1) {
$mod.push(0);
}
if ((modelValue % $mod[0]) === $mod[1]) {
match = true;
}
}
break;
case '$eq':
case '$equal':
if (util.isEqual(modelValue, queryValue)) {
match = true;
}
break;
case '$ne':
if (modelValue !== queryValue) {
match = true;
}
break;
case '$lt':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue < queryValue) {
match = true;
}
break;
case '$gt':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue > queryValue) {
match = true;
}
break;
case '$bt':
if ((queryValue != null) && util.isComparable(modelValue) && queryValue[0] < modelValue && modelValue < queryValue[1]) {
match = true;
}
break;
case '$lte':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue <= queryValue) {
match = true;
}
break;
case '$gte':
if ((queryValue != null) && util.isComparable(modelValue) && modelValue >= queryValue) {
match = true;
}
break;
case '$bte':
if ((queryValue != null) && util.isComparable(modelValue) && queryValue[0] <= modelValue && modelValue <= queryValue[1]) {
match = true;
}
}
}
}
if (match) {
matchAny = true;
} else {
matchAll = false;
}
}
if (matchAll && !matchAny) {
matchAll = false;
}
return matchAll;
};
return Query;
})();
queryEngine = {
safeRegex: util.safeRegex,
createRegex: util.createRegex,
createSafeRegex: util.createSafeRegex,
generateComparator: util.generateComparator,
toArray: util.toArray,
Backbone: Backbone,
Hash: Hash,
QueryCollection: QueryCollection,
Criteria: Criteria,
Query: Query,
Pill: Pill,
createCollection: function(models, options) {
var collection;
models = util.toArray(models);
collection = new QueryCollection(models, options);
return collection;
},
createLiveCollection: function(models, options) {
var collection;
models = util.toArray(models);
collection = new QueryCollection(models, options).live(true);
return collection;
}
};
if (typeof module !== "undefined" && module !== null) {
module.exports = queryEngine;
} else {
this.queryEngineRewrite3 = queryEngine;
}
}).call(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment