var Montage = require("montage").Montage;
/**
* Defines the criteria that objects must satisfy to be included in a set of
* data as well as other characteristics that data must possess.
*
* @class
* @extends external:Montage
*/
exports.DataQuery = Montage.specialize(/** @lends DataQuery.prototype */ {
/**
* The type of the data object to retrieve.
*
* @type {DataObjectDescriptor}
*/
type: {
value: undefined
},
/**
* An object defining the criteria that must be satisfied by objects for
* them to be included in the data set defined by this query.
*
* Initially this can be any object and will typically be a set of key-value
* pairs, ultimately this will be a boolean expression to be applied to data
* objects to determine whether they should be in the selected set or not.
*
* @type {Object}
*/
criteria: {
get: function () {
if (!this._criteria) {
this._criteria = {};
}
return this._criteria;
},
set: function (criteria) {
this._criteria = criteria;
}
},
_criteria: {
value: undefined
},
/**
* An array of DataOrdering objects which, combined, define the order
* desired for the data in the set specified by this query.
*
* @type {Array}
*/
orderings: {
get: function () {
if (!this._orderings) {
this._orderings = [];
}
return this._orderings;
},
set: function (orderings) {
this._orderings = orderings;
}
},
_orderings: {
value: undefined
},
/**
* An object defining bindings that will be created on the array
* of the dataStream returned by DataService's fetchData. The bindings
* follow the same syntax as used for regular bindings, creating dynamic
* properties that array. Expressions on the right side starts by data as the
* source is automatically set to the DataStream used in a fetchData and
* DataStream's data property is an array containing the results.
*
* For example, if one would want the number of objects fetched, one would do:
* aDataQuery.selectBindings = {
* "count": {"<-": "data.length"
* };
*
* aDataQuery.selectBindings = {
* "averageAge": {"<-": "data.map{age}.average()"
* };
* will add on the array passed to the then function following a fetchData
* a property averageAge with the average of the property age of all object in the array
*
* aDataQuery.selectBindings = {
* "clothingByColor": {"<-": "data.group{color}"
* };
* mainService.fetchData(aDataQuery).then(function(results){
* //assuming results is [
* // {type: 'shirt', color: 'blue'},
* // {type: 'pants', color: 'red'},
* // {type: 'blazer', color: 'blue'},
* // {type: 'hat', color: 'red'}
* // ];
*
* expect(results.clothingByColor).toEqual([
* ['blue', [
* {type: 'shirt', color: 'blue'},
* {type: 'blazer', color: 'blue'}
* ]],
* ['red', [
* {type: 'pants', color: 'red'},
* {type: 'hat', color: 'red'}
* ]]
* ]);
* })
* Since it is a one-way binding, if a DataService is capable of live updating a query,
* the value these properties created on the array will stay current/updated over time.
*
* It is possible that a DataService may obtain the results of these properties from the
* server itself, which is preferred, as fetchData can returns objects in batches. These
* expressions should be built from the whole result set, not the current client view of that
* result set.
* @type {Object}
*/
selectBindings: {
value: undefined
},
selectExpression: {
value: undefined
},
/**
* An object defining a list of expressions to resolve at the same time as the query.
* expressions are based on the content of results described by criteria. A common
* use is to prefetch relationships off fetched objects.
* @type {Array}
*/
prefetchExpressions: {
value: null
}
}, /** @lends DataQuery */ {
/**
* @todo Document.
*/
withTypeAndCriteria: {
value: function (type, criteria) {
var query;
query = new this();
query.type = type;
query.criteria = criteria;
return query;
}
}
});