lazybensch/ember-cli-copyable

View on GitHub
addon/mixins/copyable.js

Summary

Maintainability
B
5 hrs
Test Coverage
import Ember from 'ember';
import DS from 'ember-data';

export default Ember.Mixin.create({
  copyable: true,
  copy: function(options, copied) {
    options = options || {};
    copied = copied || {};

    var _this = this;
    return new Ember.RSVP.Promise(function(resolve) {

      var model = _this.constructor;
      var modelName = model.modelName || model.typeKey;
      var id = modelName + "--" + _this.get('id');
      if (copied.hasOwnProperty(id)) {
        return resolve(copied[id]);
      }

      var copy = _this.get('store').createRecord(modelName);
      copied[id] = copy;
      var queue = [];

      model.eachAttribute(function(attr) {
        switch(Ember.typeOf(options[attr])) {
          case 'undefined':
            copy.set(attr, _this.get(attr));
            break;
          case 'null':
            copy.set(attr, null);
            break;
          default:
            copy.set(attr, options[attr]);
        }
      });

      model.eachRelationship(function(relName, meta) {
        var rel = _this.get(relName);
        if (!rel) { return; }

        var overwrite;
        var passedOptions = {};
        switch(Ember.typeOf(options[relName])) {
          case 'null':
          return;
          case 'instance':
            overwrite = options[relName];
            break;
          case 'object':
            passedOptions = options[relName];
            break;
          case 'array':
            overwrite = options[relName];
            break;
          default:
        }

        if (rel.constructor === DS.PromiseObject) {

          queue.push(rel.then(function(obj) {

            if (obj && obj.get('copyable') && !overwrite) {
              return obj.copy(passedOptions, copied).then(function(objCopy) {
                copy.set(relName, objCopy);
              });

            } else {
              copy.set(relName, overwrite || obj);
            }

          }));


        } else if (rel.constructor === DS.PromiseManyArray) {

          if (overwrite) {
            copy.get(relName).setObjects(overwrite);
          } else {
            queue.push(rel.then(function(array) {
              var resolvedCopies =
                array.map(function(obj) {
                  if (obj.get('copyable')) {
                    return obj.copy(passedOptions, copied);
                  } else {
                    return obj;
                  }
                });
              return Ember.RSVP.all(resolvedCopies).then(function(copies){
                copy.get(relName).setObjects(copies);
              });
            }));
          }
        } else {
          if (meta.kind === 'belongsTo') {
            var obj = rel;

            if (obj && obj.get('copyable') && !overwrite) {
              queue.push( obj.copy(passedOptions, copied).then(function(objCopy) {
                copy.set(relName, objCopy);
              }));
            } else {
              copy.set(relName, overwrite || obj);
            }

          } else {
            var objs = rel;

            if (objs.get('content')) {
              objs = objs.get('content').compact();
            }

            if (objs.get('firstObject.copyable') && !overwrite) {

              var copies = objs.map(function(obj) {
                return obj.copy(passedOptions, copied);
              });

              queue.push( Ember.RSVP.all(copies).then( function(resolvedCopies) {
                copy.get(relName).setObjects(resolvedCopies);
              }));

            } else {
              copy.get(relName).setObjects(overwrite || objs);
            }
          }

        }
      });


      Ember.RSVP.all(queue).then(function() {
        resolve(copy);
      });
    });
  }
});