define('ember-cli-mirage/orm/associations/has-many', ['exports', 'ember-cli-mirage/orm/associations/association', 'ember-cli-mirage/orm/collection', 'ember-cli-mirage/orm/polymorphic-collection', 'lodash/assign', 'lodash/compact', 'ember-cli-mirage/utils/inflector', 'ember-cli-mirage/utils/normalize-name', 'ember-cli-mirage/assert'], function (exports, _association, _collection, _polymorphicCollection, _assign2, _compact2, _inflector, _normalizeName, _assert) {
  'use strict';

  Object.defineProperty(exports, "__esModule", {
    value: true
  });

  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
    return typeof obj;
  } : function (obj) {
    return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
  };

  function _defineProperty(obj, key, value) {
    if (key in obj) {
      Object.defineProperty(obj, key, {
        value: value,
        enumerable: true,
        configurable: true,
        writable: true
      });
    } else {
      obj[key] = value;
    }

    return obj;
  }

  function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
      throw new TypeError("Cannot call a class as a function");
    }
  }

  var _createClass = function () {
    function defineProperties(target, props) {
      for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) descriptor.writable = true;
        Object.defineProperty(target, descriptor.key, descriptor);
      }
    }

    return function (Constructor, protoProps, staticProps) {
      if (protoProps) defineProperties(Constructor.prototype, protoProps);
      if (staticProps) defineProperties(Constructor, staticProps);
      return Constructor;
    };
  }();

  function _possibleConstructorReturn(self, call) {
    if (!self) {
      throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
    }

    return call && (typeof call === "object" || typeof call === "function") ? call : self;
  }

  function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
      throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
    }

    subClass.prototype = Object.create(superClass && superClass.prototype, {
      constructor: {
        value: subClass,
        enumerable: false,
        writable: true,
        configurable: true
      }
    });
    if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
  }

  var HasMany = function (_Association) {
    _inherits(HasMany, _Association);

    function HasMany() {
      _classCallCheck(this, HasMany);

      return _possibleConstructorReturn(this, (HasMany.__proto__ || Object.getPrototypeOf(HasMany)).apply(this, arguments));
    }

    _createClass(HasMany, [{
      key: 'getForeignKeyArray',
      value: function getForeignKeyArray() {
        return [(0, _inflector.camelize)(this.ownerModelName), this.getForeignKey()];
      }
    }, {
      key: 'getForeignKey',
      value: function getForeignKey() {
        return (0, _inflector.singularize)((0, _inflector.camelize)(this.key)) + 'Ids';
      }
    }, {
      key: 'addMethodsToModelClass',
      value: function addMethodsToModelClass(ModelClass, key) {
        var modelPrototype = ModelClass.prototype;
        var association = this;
        var foreignKey = this.getForeignKey();
        var associationHash = _defineProperty({}, key, this);

        modelPrototype.hasManyAssociations = (0, _assign2.default)(modelPrototype.hasManyAssociations, associationHash);

        // Add to target's dependent associations array
        this.schema.addDependentAssociation(this, this.modelName);

        // TODO: look how this is used. Are these necessary, seems like they could be gotten from the above?
        // Or we could use a single data structure to store this information?
        modelPrototype.associationKeys.push(key);
        modelPrototype.associationIdKeys.push(foreignKey);

        Object.defineProperty(modelPrototype, foreignKey, {
          get: function get() {
            this._tempAssociations = this._tempAssociations || {};
            var tempChildren = this._tempAssociations[key];
            var ids = [];

            if (tempChildren) {
              if (association.isPolymorphic) {
                ids = tempChildren.models.map(function (model) {
                  return { type: model.modelName, id: model.id };
                });
              } else {
                ids = tempChildren.models.map(function (model) {
                  return model.id;
                });
              }
            } else {
              ids = this.attrs[foreignKey] || [];
            }

            return ids;
          },
          set: function set(ids) {
            var tempChildren = void 0;

            if (ids === null) {
              tempChildren = [];
            } else if (ids !== undefined) {
              (0, _assert.default)(Array.isArray(ids), 'You must pass an array in when setting ' + foreignKey + ' on ' + this);

              if (association.isPolymorphic) {
                (0, _assert.default)(ids.every(function (el) {
                  return (typeof el === 'undefined' ? 'undefined' : _typeof(el)) === 'object' && _typeof(el.type) !== undefined && _typeof(el.id) !== undefined;
                }), 'You must pass in an array of polymorphic identifiers (objects of shape { type, id }) when setting ' + foreignKey + ' on ' + this);

                var models = ids.map(function (_ref) {
                  var type = _ref.type,
                      id = _ref.id;

                  return association.schema[(0, _normalizeName.toCollectionName)(type)].find(id);
                });
                tempChildren = new _polymorphicCollection.default(models);
              } else {
                tempChildren = association.schema[(0, _normalizeName.toCollectionName)(association.modelName)].find(ids);
              }
            }

            this[key] = tempChildren;
          }
        });

        Object.defineProperty(modelPrototype, key, {
          get: function get() {
            this._tempAssociations = this._tempAssociations || {};
            var collection = null;

            if (this._tempAssociations[key]) {
              collection = this._tempAssociations[key];
            } else {
              if (association.isPolymorphic) {
                if (this[foreignKey]) {
                  var polymorphicIds = this[foreignKey];
                  var models = polymorphicIds.map(function (_ref2) {
                    var type = _ref2.type,
                        id = _ref2.id;

                    return association.schema[(0, _normalizeName.toCollectionName)(type)].find(id);
                  });

                  collection = new _polymorphicCollection.default(models);
                } else {
                  collection = new _polymorphicCollection.default(association.modelName);
                }
              } else {
                if (this[foreignKey]) {
                  collection = association.schema[(0, _normalizeName.toCollectionName)(association.modelName)].find(this[foreignKey]);
                } else {
                  collection = new _collection.default(association.modelName);
                }
              }

              this._tempAssociations[key] = collection;
            }

            return collection;
          },
          set: function set(models) {
            var _this2 = this;

            if (models instanceof _collection.default || models instanceof _polymorphicCollection.default) {
              models = models.models;
            }

            models = models ? (0, _compact2.default)(models) : [];
            this._tempAssociations = this._tempAssociations || {};

            var collection = void 0;
            if (association.isPolymorphic) {
              collection = new _polymorphicCollection.default(models);
            } else {
              collection = new _collection.default(association.modelName, models);
            }
            this._tempAssociations[key] = collection;

            models.forEach(function (model) {
              if (model.hasInverseFor(association)) {
                var inverse = model.inverseFor(association);

                model.associate(_this2, inverse);
              }
            });
          }
        });

        /*
          object.newChild
            - creates a new unsaved associated child
        */
        modelPrototype['new' + (0, _inflector.capitalize)((0, _inflector.camelize)((0, _inflector.singularize)(association.key)))] = function () {
          var modelName = void 0,
              attrs = void 0;
          if (association.isPolymorphic) {
            modelName = arguments.length <= 0 ? undefined : arguments[0];
            attrs = arguments.length <= 1 ? undefined : arguments[1];
          } else {
            modelName = association.modelName;
            attrs = arguments.length <= 0 ? undefined : arguments[0];
          }

          var child = association.schema[(0, _normalizeName.toCollectionName)(modelName)].new(attrs);
          var children = this[key].models;

          children.push(child);
          this[key] = children;

          return child;
        };

        /*
          object.createChild
            - creates a new saved associated child, and immediately persists both models
           TODO: forgot why this[key].add(child) doesn't work, most likely
          because these external APIs trigger saving cascades. Should probably
          have an internal method like this[key]._add.
        */
        modelPrototype['create' + (0, _inflector.capitalize)((0, _inflector.camelize)((0, _inflector.singularize)(association.key)))] = function () {
          var modelName = void 0,
              attrs = void 0;
          if (association.isPolymorphic) {
            modelName = arguments.length <= 0 ? undefined : arguments[0];
            attrs = arguments.length <= 1 ? undefined : arguments[1];
          } else {
            modelName = association.modelName;
            attrs = arguments.length <= 0 ? undefined : arguments[0];
          }

          var child = association.schema[(0, _normalizeName.toCollectionName)(modelName)].create(attrs);
          var children = this[key].models;

          children.push(child);
          this[key] = children;

          this.save();

          return child.reload();
        };
      }
    }, {
      key: 'disassociateAllDependentsFromTarget',
      value: function disassociateAllDependentsFromTarget(model) {
        var _this3 = this;

        var owner = this.ownerModelName;
        var fk = void 0;

        if (this.isPolymorphic) {
          fk = { type: model.modelName, id: model.id };
        } else {
          fk = model.id;
        }

        var dependents = this.schema[(0, _normalizeName.toCollectionName)(owner)].where(function (potentialOwner) {
          var currentIds = potentialOwner[_this3.getForeignKey()];

          // Need this check because currentIds could be null
          return currentIds && currentIds.find(function (id) {
            if ((typeof id === 'undefined' ? 'undefined' : _typeof(id)) === 'object') {
              return id.type === fk.type && id.id === fk.id;
            } else {
              return id === fk;
            }
          });
        });

        dependents.models.forEach(function (dependent) {
          dependent.disassociate(model, _this3);
          dependent.save();
        });
      }
    }]);

    return HasMany;
  }(_association.default);

  exports.default = HasMany;
});