Source: collections/DiscriminateCollection.js


/**
 * Overrides functions in the given model collection to turn it into a collection
 * which contains models with a discriminator field.
 *
 * @param {Rekord.ModelCollection} collection -
 *    The collection instance with discriminated models.
 * @param {String} discriminator -
 *    The name of the field which contains the discriminator.
 * @param {Object} discriminatorsToModel -
 *    A map of discriminators to the Rekord instances.
 * @return {Rekord.ModelCollection} -
 *    The reference to the given collection.
 */
function DiscriminateCollection(collection, discriminator, discriminatorsToModel)
{
  collection.discriminator = discriminator;
  collection.discriminatorsToModel = discriminatorsToModel;

  // Original Functions
  var buildKeyFromInput = collection.buildKeyFromInput;
  var parseModel = collection.parseModel;
  var clone = collection.clone;
  var cloneEmpty = collection.cloneEmpty;

  addMethods( collection,
  {

    /**
     * Builds a key from input. Discriminated collections only accept objects as
     * input - otherwise there's no way to determine the discriminator. If the
     * discriminator on the input doesn't map to a Rekord instance OR the input
     * is not an object the input will be returned instead of a model instance.
     *
     * @param {modelInput} input -
     *    The input to create a key for.
     * @return {Any} -
     *    The built key or the given input if a key could not be built.
     */
    buildKeyFromInput: function(input)
    {
      if ( isObject( input ) )
      {
        var discriminatedValue = input[ this.discriminator ];
        var model = this.discriminatorsToModel[ discriminatedValue ];

        if ( model )
        {
          return model.Database.buildKeyFromInput( input );
        }
      }

      return input;
    },

    /**
     * Takes input and returns a model instance. The input is expected to be an
     * object, any other type will return null.
     *
     * @param {modelInput} input -
     *    The input to parse to a model instance.
     * @param {Boolean} [remoteData=false] -
     *    Whether or not the input is coming from a remote source.
     * @return {Rekord.Model} -
     *    The model instance parsed or null if none was found.
     */
    parseModel: function(input, remoteData)
    {
      if ( input instanceof Model )
      {
        return input;
      }

      var discriminatedValue = isValue( input ) ? input[ this.discriminator ] : null;
      var model = this.discriminatorsToModel[ discriminatedValue ];

      return model ? model.Database.parseModel( input, remoteData ) : null;
    },

    /**
     * Returns a clone of this collection.
     *
     * @method
     * @memberof Rekord.Collection#
     * @return {Rekord.Collection} -
     *    The reference to a clone collection.
     */
    clone: function()
    {
      return DiscriminateCollection( clone.apply( this ), discriminator, discriminatorsToModel );
    },

    /**
     * Returns an empty clone of this collection.
     *
     * @method
     * @memberof Rekord.Collection#
     * @return {Rekord.Collection} -
     *    The reference to a clone collection.
     */
    cloneEmpty: function()
    {
      return DiscriminateCollection( cloneEmpty.apply( this ), discriminator, discriminatorsToModel );
    }

  });

  return collection;
}