Show:
import Mixin from '@ember/object/mixin';
import RSVP from 'rsvp';
import { debug } from '@ember/debug';
import { isArray } from '@ember/array';

import QueryBuilder from '../query/builder';

/**
 * Mixin for {{#crossLink "DS.Store"}}Store{{/crossLink}} to support
 * fetching models using projection.
 *
 * @module ember-flexberry-data
 * @class StoreMixin
 * @extends Ember.Mixin
 */
export default Mixin.create({
  /**
   *
   * @method query
   * @param {String} modelName
   * @param {any} query an opaque query to be used by the adapter
   * @return {Promise} promise
   */
  query(modelName, query) {
    debug(`Flexberry Store::query ${modelName}`, query);

    let promise = this._super(...arguments);
    return new RSVP.Promise((resolve, reject) => {
      promise.then((results) => {
        if (results && isArray(results)) {
          results.forEach((result) => {
            result.didLoad();
          });
        }

        resolve(results);
      }, reject);
    });
  },

  /**
   *
   * @method queryRecord
   * @param {String} modelName
   * @param {any} query an opaque query to be used by the adapter
   * @return {Promise} promise
   */
  queryRecord(modelName, query) {
    debug(`Flexberry Store::queryRecord ${modelName}`, query);

    return this.query(modelName, query).then(result => new RSVP.Promise((resolve) => resolve(result.get('firstObject'))));
  },

  /**
   * Finds all records for the given model type.
   *
   * See {{#crossLink "DS.Store/findAll:method"}}{{/crossLink}} for details.
   *
   * @method findAll
   * @public
   *
   * @param {String} modelName The name of the model type.
   * @param {Object} [options] Options.
   * @param {String} options.projection Projection name.
   * @return {DS.AdapterPopulatedRecordArray} Records promise.
   */
  findAll(modelName, options) {
    debug(`Flexberry Store::findAll ${modelName}`);

    let builder = new QueryBuilder(this, modelName);

    if (options && options.projection) {
      debug(`Flexberry Store::findAll using projection '${options.projection}'`);

      builder.selectByProjection(options.projection);
      return this.query(modelName, builder.build());
    }

    let queryObject = builder.build();

    // Now if projection is not specified then only 'id' field will be selected.
    queryObject.select = [];
    return this.query(modelName, queryObject);
  },

  /**
   * Returns a record for a given type and id combination.
   *
   * See {{#crossLink "DS.Store/findRecord:method"}}{{/crossLink}} for details.
   *
   * @method findRecord
   * @public
   *
   * @param {String} modelName The name of the model type.
   * @param {String|Integer} id Record ID.
   * @param {Object} [options] Options.
   * @param {String} options.projection Projection name.
   * @return {Promise} Record promise.
   */
  findRecord(modelName, id, options) {
    debug(`Flexberry Store::findRecord ${modelName}(${id})`);

    let builder = new QueryBuilder(this, modelName).byId(id);

    if (options && options.projection) {
      debug(`Flexberry Store::findRecord using projection '${options.projection}'`);

      builder.selectByProjection(options.projection);
      return this.query(modelName, builder.build()).then(result => new RSVP.Promise((resolve) => resolve(result.get('firstObject'))));
    }

    let queryObject = builder.build();

    // Now if projection is not specified then only 'id' field will be selected.
    queryObject.select = [];
    return this.query(modelName, queryObject).then(result => new RSVP.Promise((resolve) => resolve(result.get('firstObject'))));
  }
});