# Source: data/model/data-query.js

    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;
            }
        }

    });