201 lines
5.6 KiB
JavaScript
201 lines
5.6 KiB
JavaScript
define("dstore/SimpleQuery", [
|
|
'dojo/_base/declare',
|
|
'dojo/_base/array'
|
|
], function (declare, arrayUtil) {
|
|
|
|
// module:
|
|
// dstore/SimpleQuery
|
|
|
|
function makeGetter(property, queryAccessors) {
|
|
if (property.indexOf('.') > -1) {
|
|
var propertyPath = property.split('.');
|
|
var pathLength = propertyPath.length;
|
|
return function (object) {
|
|
for (var i = 0; i < pathLength; i++) {
|
|
object = object && (queryAccessors && object.get ? object.get(propertyPath[i]) : object[propertyPath[i]]);
|
|
}
|
|
return object;
|
|
};
|
|
}
|
|
// else
|
|
return function (object) {
|
|
return object.get ? object.get(property) : object[property];
|
|
};
|
|
}
|
|
|
|
var comparators = {
|
|
eq: function (value, required) {
|
|
return value === required;
|
|
},
|
|
'in': function(value, required) {
|
|
// allow for a collection of data
|
|
return arrayUtil.indexOf(required.data || required, value) > -1;
|
|
},
|
|
ne: function (value, required) {
|
|
return value !== required;
|
|
},
|
|
lt: function (value, required) {
|
|
return value < required;
|
|
},
|
|
lte: function (value, required) {
|
|
return value <= required;
|
|
},
|
|
gt: function (value, required) {
|
|
return value > required;
|
|
},
|
|
gte: function (value, required) {
|
|
return value >= required;
|
|
},
|
|
match: function (value, required, object) {
|
|
return required.test(value, object);
|
|
},
|
|
contains: function (value, required, object, key) {
|
|
var collection = this;
|
|
return arrayUtil.every(required.data || required, function (requiredValue) {
|
|
if (typeof requiredValue === 'object' && requiredValue.type) {
|
|
var comparator = collection._getFilterComparator(requiredValue.type);
|
|
return arrayUtil.some(value, function (item) {
|
|
return comparator.call(collection, item, requiredValue.args[1], object, key);
|
|
});
|
|
}
|
|
return arrayUtil.indexOf(value, requiredValue) > -1;
|
|
});
|
|
}
|
|
};
|
|
|
|
return declare(null, {
|
|
// summary:
|
|
// Mixin providing querier factories for core query types
|
|
|
|
_createFilterQuerier: function (filter) {
|
|
// create our matching filter function
|
|
var queryAccessors = this.queryAccessors;
|
|
var collection = this;
|
|
var querier = getQuerier(filter);
|
|
|
|
function getQuerier(filter) {
|
|
var type = filter.type;
|
|
var args = filter.args;
|
|
var comparator = collection._getFilterComparator(type);
|
|
if (comparator) {
|
|
// it is a comparator
|
|
var firstArg = args[0];
|
|
var getProperty = makeGetter(firstArg, queryAccessors);
|
|
var secondArg = args[1];
|
|
if (secondArg && secondArg.fetchSync) {
|
|
// if it is a collection, fetch the contents (for `in` and `contains` operators)
|
|
secondArg = secondArg.fetchSync();
|
|
}
|
|
return function (object) {
|
|
// get the value for the property and compare to expected value
|
|
return comparator.call(collection, getProperty(object), secondArg, object, firstArg);
|
|
};
|
|
}
|
|
switch (type) {
|
|
case 'and': case 'or':
|
|
for (var i = 0, l = args.length; i < l; i++) {
|
|
// combine filters, using and or or
|
|
var nextQuerier = getQuerier(args[i]);
|
|
if (querier) {
|
|
// combine the last querier with a new one
|
|
querier = (function(a, b) {
|
|
return type === 'and' ?
|
|
function(object) {
|
|
return a(object) && b(object);
|
|
} :
|
|
function(object) {
|
|
return a(object) || b(object);
|
|
|
|
};
|
|
})(querier, nextQuerier);
|
|
} else {
|
|
querier = nextQuerier;
|
|
}
|
|
}
|
|
return querier;
|
|
case 'function':
|
|
return args[0];
|
|
case 'string':
|
|
// named filter
|
|
var filterFunction = collection[args[0]];
|
|
if (!filterFunction) {
|
|
throw new Error('No filter function ' + args[0] + ' was found in the collection');
|
|
}
|
|
return filterFunction;
|
|
case undefined:
|
|
return function () {
|
|
return true;
|
|
};
|
|
default:
|
|
throw new Error('Unknown filter operation "' + type + '"');
|
|
}
|
|
}
|
|
return function (data) {
|
|
return arrayUtil.filter(data, querier);
|
|
};
|
|
},
|
|
|
|
_getFilterComparator: function (type) {
|
|
// summary:
|
|
// Get the comparator for the specified type
|
|
// returns: Function?
|
|
|
|
return comparators[type] || this.inherited(arguments);
|
|
},
|
|
|
|
_createSelectQuerier: function (properties) {
|
|
return function (data) {
|
|
var l = properties.length;
|
|
return arrayUtil.map(data, properties instanceof Array ?
|
|
// array of properties
|
|
function (object) {
|
|
var selectedObject = {};
|
|
for (var i = 0; i < l; i++) {
|
|
var property = properties[i];
|
|
selectedObject[property] = object[property];
|
|
}
|
|
return selectedObject;
|
|
} :
|
|
// single property
|
|
function (object) {
|
|
return object[properties];
|
|
});
|
|
};
|
|
},
|
|
|
|
_createSortQuerier: function (sorted) {
|
|
var queryAccessors = this.queryAccessors;
|
|
return function (data) {
|
|
data = data.slice();
|
|
data.sort(typeof sorted == 'function' ? sorted : function (a, b) {
|
|
for (var i = 0; i < sorted.length; i++) {
|
|
var comparison;
|
|
var sorter = sorted[i];
|
|
if (typeof sorter == 'function') {
|
|
comparison = sorter(a, b);
|
|
} else {
|
|
var getProperty = sorter.get || (sorter.get = makeGetter(sorter.property, queryAccessors));
|
|
var descending = sorter.descending;
|
|
var aValue = getProperty(a);
|
|
var bValue = getProperty(b);
|
|
|
|
aValue != null && (aValue = aValue.valueOf());
|
|
bValue != null && (bValue = bValue.valueOf());
|
|
|
|
comparison = aValue === bValue
|
|
? 0
|
|
: (!!descending === (aValue === null || aValue > bValue && bValue !== null) ? -1 : 1);
|
|
}
|
|
|
|
if (comparison !== 0) {
|
|
return comparison;
|
|
}
|
|
}
|
|
return 0;
|
|
});
|
|
return data;
|
|
};
|
|
}
|
|
});
|
|
});
|