Git Product home page Git Product logo

ember-data-copyable's Introduction

Ember Data Copyable

Build Status npm version

Intelligently copy an Ember Data model and all of its relationships

Features

  • Shallow & deep copy an Ember Data model
  • Shallow & deep copy model relationships
  • Handles cyclical relationships
  • Handles custom transforms to create true copies
  • Overwrite, ignore attributes, and copy objects by reference
  • Intelligent failure and cleanup
  • Uses ember-concurrency to allow cancelling a copy task

Installation

ember install ember-data-copyable

Helpful Links

Looking for help?

If it is a bug please open an issue on GitHub.

Setup

This addon provides a Copyable mixin which allows you to copy a model. To get started, just import the mixin and add it to your model.

// models/user.js

import DS from 'ember-data';
import Copyable from 'ember-data-copyable';

export default DS.Model.extend(Copyable, {
  guid: DS.attr('number'),
  firstName: DS.attr('string'),
  lastName: DS.attr('string'),
  address: DS.belongsTo('address'),
  friends: DS.hasMany('user'),

  // Specific copy options for the model
  copyableOptions: {}
});

In your model you can specify default options via the copyableOptions object. Please see options for more details.

Copying Relationships

To copy a model's relationship, that relational model must have the Copyable mixin or else it will just be copied by reference.

Usage

Once the model is setup, we can use the copy method on an instance to duplicate it.

Copy Method Signature

async function copy(deep = false, options = {}) {}
  • deep : Boolean

    If false a shallow copy of the model's attributes will be created. All relationships will be copied over by reference.

    If true, a deep copy of the model and it's relationships will be created. If a relational model has the Copyable mixin, it will also be deep copied.

  • options : Object

    Copy options. See options for more details.

    NOTE: Options passed into the copy method take precedence over those specified on the model.

Returns a cancelable promise like ember-concurrency TaskInstance.

Examples

Normal Usage

const model = this.get('store').peekRecord('user', 1);

model
  .copy(true, {
    ignoreAttributes: ['guid'],
    copyByReference: ['address'],
    overwrite: {
      id: 2,
      firstName: 'Offir'
    }
  })
  .then(
    copy => {
      // Handle success
      return copy.save();
    },
    e => {
      // Handle error or cancellation
    }
  );

Task Cancellation

Since the copy method returns an ember-concurrency TaskInstance, we have the ability to cancel a running copy task at any time.

const model = this.get('store').peekRecord('user', 1);
const copyTaskInstance = model.copy(true);

// Cancel our copy task
copyTaskInstance.cancel();

Options

These options can either be specified via the copyableOptions object on the DS.Model class or passed into the copy method.

ignoreAttributes

Attributes to ignore when copying.

ignoreAttributes: ['guid', 'address'];

otherAttributes

Other attributes to copy over that are not defined via DS.attr, DS.belongsTo, or DS.hasMany.

otherAttributes: ['timestamp', 'someFlag'];

copyByReference

Attributes to copy only by reference. If the attribute has the Copyable mixin, it will be ignored and not be copied, just copied by reference.

copyByReference: ['friends'];

overwrite

Overwrite attributes with the specified values. This will also add properties that are not found on the model.

overwrite: {
  id: 2,
  firstName: 'Offir - Copy',
  address: this.get('store').createRecord('address', { /* ... */ }),
  unknownProperty: 'Foo Bar'
}

relationships

Specify options to nested models. Nested relationships options can also include a deep option. If set to false, the relationship will be shallow copied.

relationships: {
  address: {
    ignoreAttributes: ['streetName'],
    overwrite: {
      state: 'CA'
    }
  },
  friends: {
    copyByReference: ['address']
  },
  profile: {
    deep: false
  }
}

ember-data-copyable's People

Contributors

acorncom avatar alexander-alvarez avatar bjornharrtell avatar ember-tomster avatar jakesjews avatar john-griffin avatar miguelcobain avatar mpirio avatar offirgolan avatar onumossn avatar xaseracheron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

ember-data-copyable's Issues

fragment error

Hi,

can ember-data-copyable work with fragments? As soon as I make a fragment copyable the base model will not copy anymore Fragment.extend(Copyable.

Assertion Failed: You can only assign null, an object literal or a 'dossier/consumer' fragment instance to this property"

property is 'consumer'.
and value is an 'instance'
error comes from here : https://github.com/lytics/ember-data-model-fragments/blob/master/addon/attributes.js#L118

adding console.log(value) reveals two passing calls, and the last one fails, which looks different to me.

[Log] Class {__ember1513363568481: "ember1394", store: Class, _internalModel: InternalModel, currentState: Object, …} (vendor.js, line 128420)
[Log] Class {__ember1513363568481: "ember1395", store: Class, _internalModel: InternalModel, currentState: Object, …} (vendor.js, line 128420)
[Log] Class {__ember1513363568481: null, fn: function, args: [false], context: Class, owner: Class, …} (vendor.js, line 128420)
export default Model.extend(Copyable, Validations, {
  dossierNumber: attr('string'),
  openedDate: attr('date', { defaultValue: () => new Date() }),
  owningCustomerId: attr('string'),
  owningPracticeId: attr('string'),

  consumer: fragment('dossier/consumer', { defaultValue: {} }),
});

export default Fragment.extend(Copyable, Validations, {
  address: fragment('fragment/geography/address', { defaultValue: {} }),
  birthday: attr('date'),
  email: attr('string'),
  name: fragment('fragment/person/name/personname', { defaultValue: {} }),
  phone: attr('string'),
  sex: attr('string'),
});

Allow for copying to an object other than models

When ever we edit a model, we make a copy first to an object, then edit that. This means that a cancel just throws the object away. To help this all computed properties are put in a mixin, only data fields are put in the model. This allows us to add the mixin to an object and simulate the model.

It would be nice to be able to use this addon to copy the data to an object instead of a new model and it looks like that could happen with a very small change where you create the model. It would have been nice if there was a method that just created the attr hash and then used that to apply. That also is easily doable except for the code at 194 using the private API. What is that accomplishing that the attrs[name] = this.get(name); didnt accomplish?

It would also be nice to expose the attrs[] because I could use that to copy the object back to the original model.

DEPRECATION: ember-cli-babel 5.x has been deprecated.

Getting deprecation warnings for ember-cli-material-design-icons in Ember 3.x

DEPRECATION: ember-cli-babel 5.x has been deprecated. Please upgrade to at least ember-cli-babel 6.6.0

Environment

ember: 3.1.2
ember-cli: 3.1.4
ember-data-copyable: 0.3.2

TaskInstance '__DS_COPY_TASK_RUNNER__' was canceled because it belongs to a 'drop' Task that was already running.

Hello.

I am using ember-data-copyable (0.2.1) to copy models, its very cool! And had no problems till today :( when I tried to copy same model in multiple times.

I have Promise.all(promises), in every of that promises I copy one or more models, but those are always the same models for all promises.

For example, I have 3 models (taskAsignments) , and I want copy all 3 of them in for example 6 promises.

What I encounter is, that all 3 models are copied in firstProcessedPromise and will fail in all other (five) promises with message :

TaskCancelation: TaskInstance 'DS_COPY_TASK_RUNNER' was canceled because it belongs to a 'drop' Task that was already running. For more information, see: http://ember-concurrency.com/#/docs/task-cancelation-help

I tried to rewrite Promise.all with reduce, so all 6 promises would be called in synchronized way, but result was same sadly. I also tried deep and not deep .copy with same result.

If possible please advice if have any idea.

Model with fragment error

Hi, I have an 2.14 ember-data model that includes a fragment.

After updating ember-data-copyable (which now internally uses ember-copy) I get "Fatal error: TypeError: Cannot read property 'serialize' of undefined" errors.

I narrowed it down to a check that is done to see if the fragment has the copyable mixin. It returns false while true is expected. The Fragment has the Copyable Mixin.

if (Copyable && Copyable.detect(value)) {

I don't understand where the detect method comes from. Can't find it here https://github.com/emberjs/ember-copy/search?q=detect

For now I downgraded...

overwrite with default values

Maybe so

overwrite: {
      status: true
    }
export default Model.extend Copyable,
  status: attr defaultValue: 'draft'

after copy

copyedModel.status === 'draft'

indirect nested models not copied

I have models like these :

Model page (Copyable without copyableOptions)
Model article (Copyable without copyableOptions)
Model media (Copyable without copyableOptions)
Model image (Copyable without copyableOptions)

page -> hasMany article -> belongsTo media -> belongsTo image.
page -> belongsTo media

When a page is copied its direct articles and media are copied too, but nested media (and there nested images) from articles aren't.

My copy's call :

return this.get('page').copy(true, {
  relationships: {
    media: {
      deep: true,
      copyByReference: ['image'],
    },
    articles: {
      deep: true,
      relationships: {
        media: {
          deep: true,
          copyByReference: ['image']
        }
      }
    }
  }
}).then(copy => this.get('duplicateAction')(copy));

I am on [email protected] / [email protected] / [email protected]

overwrite id must be string

wrong

copy( false, overwrite: {
      id: 2
}
)

[ember-data-copyable] Error: Assertion Failed: You cannot index an internalModel by an empty id'
at Object.assert (index.js:163)
at InternalModelMap.set (-private.js:6662)

this works

copy( false, overwrite: {
      id: '2'
}
)

copying deep instance with relationships does not behave as expected

issue description

I have a parent that has 1 child relationship and 1 grand child. It is returned by a route's model hook. When I execute model.copy(true) I expected it to duplicate the parent and all relationships. Instead it appears to overwrite the current controller.model. Is this expected behavior?

reproduction

  1. clone this dummy ember-app: https://github.com/efx/poc-bug/tree/copyable-bug. (git clone --single-branch -b copyable-bug https://github.com/efx/poc-bug)
  2. run npm install && ember server
  3. navigate to localhost:4200 and click the 'copy' button

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.