platanus/angular-restmod

View on GitHub
src/plugins/find-many.js

Summary

Maintainability
A
0 mins
Test Coverage
/**
 * @mixin FindMany
 *
 * @description
 *
 * Adds the `Scope.$populate` method that enables multiple record resolving using one request.
 *
 * This plugin requires special api support for multiple id requests.
 */

'use strict';

angular.module('restmod').factory('restmod.FindMany', ['restmod', 'RMPackerCache', 'inflector', function(restmod, packerCache, inflector) {

  return restmod.mixin(function() {

    /**
     * @method $findManyUrl
     * @memberOf FindMany
     *
     * @description Provides the url for a findMany/populate operation.
     */
    this.define('Scope.$findManyUrl', function(_resource) {
      return this.$fetchManyUrl ? this.$fetchManyUrl(_resource) : this.$url(_resource);
    })
    /**
     * @method $populate
     * @memberOf FindMany
     *
     * @description Resolves a series of records using a single api call.
     *
     * By default, this method uses the same url used by `collection.$fetch`. To provide a different url
     * then override the `Scope.$findManyUrl` function.
     *
     * By default this method uses the pluralized variat of the primary key for the query parameter holding
     * the ids. You can override this parameter by setting the `findManyKey` configuration var.
     *
     * This method triggers the `before-find-many` event before sending the server request.
     *
     * Usage:
     *
     * ```javascript
     * var bikes = [
     *  Bike.$new(1),
     *  Bike.$new(2),
     *  Bike.$new(3)
     * ];
     *
     * Bike.$populate(bikes).$then(function() {
     *   // populate returns a fully fledged resource!
     *   alert('Ready!');
     * })
     * ```
     *
     * @param {array} _records Records to resolve.
     * @return {Resource} Resource holding the populate promise.
     */
    .define('Scope.$populate', function(_records, _params) {

      // Extract record pks for non resolved records and build a record map
      var pks = [],
          recordMap = {},
          params = _params || {},
          model = this.$type,
          dummy = model.dummy(true),
          record, request;

      for(var i = 0; i < _records.length; i++) {
        record = _records[i];
        if(!record.$resolved) {
          if(recordMap[record.$pk]) {
            recordMap[record.$pk].push(record);
          } else {
            recordMap[record.$pk] = [record];
            pks.push(record.$pk);
          }
        }
      }

      if(pks.length === 0) return dummy;

      // build request
      params[model.getProperty('findManyKey', inflector.pluralize(model.getProperty('primaryKey')))] = pks;
      request = {
        url: (this.$scope || this).$findManyUrl(this),
        method: 'GET',
        params: params
      };

      // allow user to modify request on hook
      dummy.$dispatch('before-find-many', [request]);

      // Execute request to fetch for required records
      return model.dummy(true).$send(request, function(_response) {
        try {
          packerCache.prepare();
          var raw = model.unpack(this, _response.data), pk, records;

          // load raw data into records
          for(var i = 0; i < raw.length; i++) {
            pk = model.inferKey(raw[i]);
            records = recordMap[pk];
            if(records) {
              for(var j = 0; j < records.length; j++) {
                if(!records[j].$resolved) records[j].$decode(raw[i]);
              }
            }
          }

        } finally {
          packerCache.clear();
        }
      });
    });
  });
}]);