{"_id":"@eflexsystems/ember-data-model-fragments","_rev":"3-a041df84142778d07fa60a5c81cd2445","name":"@eflexsystems/ember-data-model-fragments","dist-tags":{"latest":"5.0.0-beta.8-2"},"versions":{"5.0.0-beta.8-1":{"name":"@eflexsystems/ember-data-model-fragments","version":"5.0.0-beta.8-1","keywords":["ember-addon","ember","ember-data","ember-cli","fragments"],"author":{"name":"Steven Lindberg","email":"steven@lytics.io"},"license":"MIT","_id":"@eflexsystems/ember-data-model-fragments@5.0.0-beta.8-1","maintainers":[{"name":"eflex","email":"jacobjewell@eflexsystems.com"},{"name":"jakesjews","email":"jakesjews@immersiveapplications.com"},{"name":"rrglomsk","email":"rachelglomski@eflexsystems.com"},{"name":"nevans54","email":"nate544@gmail.com"},{"name":"josephdickens87","email":"josephdickens87@gmail.com"}],"dist":{"shasum":"acf1470d4a984ad0639e821ec54cb06abe1b2123","tarball":"https://registry.npmjs.org/@eflexsystems/ember-data-model-fragments/-/ember-data-model-fragments-5.0.0-beta.8-1.tgz","fileCount":59,"integrity":"sha512-q4gprumlMQC63TCpwuwwH7lzALs9On+1fq7JA5Cp+gesTPCZ+g5HehJIgquX+ngehS+JUD800JCxo2hVaUDf2w==","signatures":[{"sig":"MEQCIE2xd09iutnnEAxYCHy0iE0V4tqTx5Gu8u/zWSRYdPztAiBqdFFkhv3CezIhVqQzACSNH3WY8S81BUm8e8LyN4rMQg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":118965,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjbA6/ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoffhAAkHJfs5iXLzbsvuC7jpjVN9Z3wdxG56fXRfBxpr14gDBv2lH1\r\nqRgMcTquFxcCvsKYYHgWNyNiDBIGouDCRJN31nHneaSSwx+ehcnXjgt3SUwQ\r\nMfQRYtdA91Z+DVDPAMw/FUDMIq+ZXATKWCOX0msKgH+FgCtC7EYztLJQltFP\r\nFxjvtf0xG4uZahV7V+aqp7JAVnkuHoEIY3e8R2+IkxHcz37eWkzGYRPPT+Pi\r\nqrO6uwFT2eH9tkoaGc/7uabanY8BDc0G6i9w6Dsh/Ds7/akDYijgl6AbMLDo\r\nH/ChoKyumhJvIxg80JMEMnH7//p7A5DjoJnuHXJhDl04xT9+6NIs31iGbH8f\r\nZMT1xFTQ7jR6uZoWJkZQxH4lODK3KZjPd6gToW6YB14YIMvSl+G2rMSW7gv6\r\ncYzv98du4PBh10YrDSqclsQZ9PmcBYlpobEKBUH1FBKUlegrPzv7tP7XAPCS\r\nNyXGOMhXRlI/57Z8wsgJmLWO1JwgIKF5VO5gv5PAAuueq3etCEn5pTP8yued\r\nkb+5VTtN71zraCwNF1ZWfJpVtcQSCoJmltkpnlNsErcjcMkcH02MR+IrowM1\r\ncv9MsgYqjASbU3RSlKy0NB8oauuSR5i1jrfWcS5vl67YQp42mbuMXBMZONMY\r\nemDQDO+/fk6dU5orPUyhCBfzEDO3ktcTZCc=\r\n=XpzY\r\n-----END PGP SIGNATURE-----\r\n"},"ember":{"edition":"octane"},"engines":{"node":"10.* || >= 12"},"scripts":{"lint":"npm-run-all --aggregate-output --continue-on-error --parallel lint:*","test":"npm-run-all lint:* test:*","build":"ember build --environment=production","start":"ember serve","lint:js":"eslint .","lint:hbs":"ember-template-lint .","test:ember":"ember test","test:ember-compatibility":"ember try:each"},"_npmUser":{"name":"jakesjews","email":"jakesjews@immersiveapplications.com"},"release-it":{"git":{"tagName":"v${version}"},"github":{"release":true,"tokenRef":"GITHUB_AUTH"},"plugins":{"release-it-lerna-changelog":{"infile":"CHANGELOG.md","launchEditor":false}}},"repository":{"url":"https://github.com/adopted-ember-addons/ember-data-model-fragments.git","type":"git"},"description":"Ember Data addon to support nested JSON documents","directories":{},"ember-addon":{"configPath":"tests/dummy/config"},"licenseText":"Copyright (c) 2018 Lytics, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n","dependencies":{"ember-copy":"2.0.1","npm-git-info":"^1.0.3","git-repo-info":"^2.1.1","ember-cli-babel":"^7.26.6","broccoli-merge-trees":"^3.0.0","broccoli-file-creator":"^2.1.1","ember-compatibility-helpers":"^1.2.1","calculate-cache-key-for-tree":"^1.1.0"},"publishConfig":{"registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^7.5.0","ember-cli":"~3.20.2","ember-try":"^1.4.0","loader.js":"^4.7.0","pretender":"^3.4.3","qunit-dom":"^1.6.0","ember-data":"~3.28.3","release-it":"^14.2.1","ember-qunit":"^4.6.0","npm-run-all":"^4.1.5","babel-eslint":"^10.1.0","ember-source":"~3.28.3","ember-resolver":"^8.0.3","ember-cli-uglify":"^3.0.0","@glimmer/tracking":"^1.0.4","ember-auto-import":"^1.12.0","@glimmer/component":"^1.0.4","broccoli-asset-rev":"^3.0.0","ember-cli-htmlbars":"^5.2.0","eslint-plugin-node":"^11.1.0","@ember/test-helpers":"^2.6.0","ember-template-lint":"^2.9.1","eslint-plugin-ember":"^8.9.1","ember-load-initializers":"^2.1.1","@ember/optional-features":"^1.3.0","ember-source-channel-url":"^2.0.1","eslint-plugin-ember-suave":"^1.0.0","ember-qunit-assert-helpers":"^0.2.0","release-it-lerna-changelog":"^3.1.0","ember-cli-dependency-checker":"^3.2.0","ember-cli-inject-live-reload":"^2.0.2","ember-maybe-import-regenerator":"^1.0.0","ember-disable-prototype-extensions":"^1.1.3"},"_npmOperationalInternal":{"tmp":"tmp/ember-data-model-fragments_5.0.0-beta.8-1_1668026046812_0.25027385026992577","host":"s3://npm-registry-packages"}},"5.0.0-beta.8-2":{"name":"@eflexsystems/ember-data-model-fragments","version":"5.0.0-beta.8-2","keywords":["ember-addon","ember","ember-data","ember-cli","fragments"],"author":{"name":"Steven Lindberg","email":"steven@lytics.io"},"license":"MIT","_id":"@eflexsystems/ember-data-model-fragments@5.0.0-beta.8-2","maintainers":[{"name":"eflex","email":"jacobjewell@eflexsystems.com"},{"name":"jakesjews","email":"jakesjews@immersiveapplications.com"},{"name":"rrglomsk","email":"rachelglomski@eflexsystems.com"},{"name":"nevans54","email":"nate544@gmail.com"},{"name":"josephdickens87","email":"josephdickens87@gmail.com"}],"dist":{"shasum":"0c5524ecfeab1ebfe835f97fc44b11afac06d941","tarball":"https://registry.npmjs.org/@eflexsystems/ember-data-model-fragments/-/ember-data-model-fragments-5.0.0-beta.8-2.tgz","fileCount":59,"integrity":"sha512-0bUQxlCqD+9g3qmbA5QpygmcCkvcvfZSwRWkGhgbi/ZOl3uso6Btgj1mKgkrIY7fde22/70RohDAVwyduN/QLA==","signatures":[{"sig":"MEUCIQDP3StpP7yWlzEV4IHwyX+lCXffXbUibfKb141R3YtHkwIgEy9q7bczZSJEwQ+sZnYVWTYuEH3aiOWiL57OvduRsGo=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":119283,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjbBNsACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmozAw//bFRYPu1CNzmtfLvbKwXpJo4ks8wUgdtvD5WoCfAWf+Na18Yx\r\nKu2mQt3fasF4gIAWjD3Ns/cIpe7b1AgGGtZZREdQwvP9IfHNlsld90MJnN2M\r\nyXwA9SpiKDgm23eISXQM7hN3BmOaqeyU+SHvaK/7NlAXvB0XnGEnKqPBBfSb\r\nING9SjInqKUtTa+1tmfNUGnfEqzcM3+tDCvN/daS3gx+XKa9HrM1uF3m6wyf\r\nWcYHHgsXrZMx1rFGFsSasxwmFn0Bx4cBbc8lDZ2oI0BCQ5Zg5LgYCHeQFV9P\r\np3Iof3hcVhgazEdcvL2yoSctWQnrDFy9sgOLqmruWnFqoPJbfexdZgWElsRv\r\nsPLmLwfd5qrTa6yIoHW8uqbHEQ3RDO86Oh0AeXuMzsapeKC4ABWX3EQDu+im\r\naF+iSpCojiMsofFW3oDHgvBewkZS3etkrEXbGH5C2tyLIvZEK8eyZYrGJ8JS\r\nI/HxtECA6oEohS8ozwKXQ6i7T5w2EMXffrahV0iqjk6uSkdBlG7dM65Nu/F/\r\nH4T17C2hHSJcBvo1pev28h5V/CNbohdrhOa+a5qnDz7n+flkJaGGgBaDQmmd\r\nk9v8jugtLYtITj/2NDwP2+f6/cMlWiahoXIrE7Il/9T4XvV7DNDOEGbpZZkf\r\n94T2jMtVRQ6EzOly1bglyjl2NhOR1cHVQNk=\r\n=UEU0\r\n-----END PGP SIGNATURE-----\r\n"},"ember":{"edition":"octane"},"engines":{"node":"10.* || >= 12"},"scripts":{"lint":"npm-run-all --aggregate-output --continue-on-error --parallel lint:*","test":"npm-run-all lint:* test:*","build":"ember build --environment=production","start":"ember serve","lint:js":"eslint .","lint:hbs":"ember-template-lint .","test:ember":"ember test","test:ember-compatibility":"ember try:each"},"_npmUser":{"name":"jakesjews","email":"jakesjews@immersiveapplications.com"},"release-it":{"git":{"tagName":"v${version}"},"github":{"release":true,"tokenRef":"GITHUB_AUTH"},"plugins":{"release-it-lerna-changelog":{"infile":"CHANGELOG.md","launchEditor":false}}},"repository":{"url":"https://github.com/adopted-ember-addons/ember-data-model-fragments.git","type":"git"},"description":"Ember Data addon to support nested JSON documents","directories":{},"ember-addon":{"configPath":"tests/dummy/config"},"licenseText":"Copyright (c) 2018 Lytics, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n","dependencies":{"ember-copy":"2.0.1","npm-git-info":"^1.0.3","git-repo-info":"^2.1.1","ember-cli-babel":"^7.26.6","broccoli-merge-trees":"^3.0.0","broccoli-file-creator":"^2.1.1","ember-compatibility-helpers":"^1.2.1","calculate-cache-key-for-tree":"^1.1.0"},"publishConfig":{"registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^7.5.0","ember-cli":"~3.20.2","ember-try":"^1.4.0","loader.js":"^4.7.0","pretender":"^3.4.3","qunit-dom":"^1.6.0","ember-data":"~3.28.3","release-it":"^14.2.1","ember-qunit":"^4.6.0","npm-run-all":"^4.1.5","babel-eslint":"^10.1.0","ember-source":"~3.28.3","ember-resolver":"^8.0.3","ember-cli-uglify":"^3.0.0","@glimmer/tracking":"^1.0.4","ember-auto-import":"^1.12.0","@glimmer/component":"^1.0.4","broccoli-asset-rev":"^3.0.0","ember-cli-htmlbars":"^5.2.0","eslint-plugin-node":"^11.1.0","@ember/test-helpers":"^2.6.0","ember-template-lint":"^2.9.1","eslint-plugin-ember":"^8.9.1","ember-load-initializers":"^2.1.1","@ember/optional-features":"^1.3.0","ember-source-channel-url":"^2.0.1","eslint-plugin-ember-suave":"^1.0.0","ember-qunit-assert-helpers":"^0.2.0","release-it-lerna-changelog":"^3.1.0","ember-cli-dependency-checker":"^3.2.0","ember-cli-inject-live-reload":"^2.0.2","ember-maybe-import-regenerator":"^1.0.0","ember-disable-prototype-extensions":"^1.1.3"},"_npmOperationalInternal":{"tmp":"tmp/ember-data-model-fragments_5.0.0-beta.8-2_1668027243851_0.6279239973831767","host":"s3://npm-registry-packages"}}},"time":{"created":"2022-11-09T20:34:06.755Z","modified":"2026-05-05T19:32:27.376Z","5.0.0-beta.8-1":"2022-11-09T20:34:07.027Z","5.0.0-beta.8-2":"2022-11-09T20:54:04.013Z"},"author":{"name":"Steven Lindberg","email":"steven@lytics.io"},"license":"MIT","keywords":["ember-addon","ember","ember-data","ember-cli","fragments"],"repository":{"url":"https://github.com/adopted-ember-addons/ember-data-model-fragments.git","type":"git"},"description":"Ember Data addon to support nested JSON documents","maintainers":[{"email":"nate.evans@epicor.com","name":"eflex"},{"email":"rachelglomski@eflexsystems.com","name":"rrglomsk"},{"email":"nate544@gmail.com","name":"nevans54"}],"readme":"# Ember Data Model Fragments\n\n[![CI](https://github.com/adopted-ember-addons/ember-data-model-fragments/actions/workflows/ci.yml/badge.svg)](https://github.com/adopted-ember-addons/ember-data-model-fragments/actions/workflows/ci.yml)\n[![NPM Version](https://badge.fury.io/js/ember-data-model-fragments.svg)](http://badge.fury.io/js/ember-data-model-fragments)\n[![Ember Observer Score](http://emberobserver.com/badges/ember-data-model-fragments.svg)](http://emberobserver.com/addons/ember-data-model-fragments)\n\nThis package provides support for sub-models that can be treated much like `belongsTo` and `hasMany` relationships are, but whose persistence is managed completely through the parent object.\n\n:warning: Deprecated APIs have been removed. See the [changelog](CHANGELOG.md) for more information on breaking changes.\n\n## Compatibility\n\nThis project makes extensive use of private Ember Data APIs and is therefore sensitive to minor changes in new Ember Data releases, regardless of semver guarantees. Every effort is made to maintain compatibility with the latest version, but updates always take time. See the [contributing](#contributing) section if you'd like to help out :shipit:\n\nUse the following table to decide which version of this project to use with your app:\n\n| Ember Data | Model Fragments |\n|------------|-----------------|\n| > v1.0.0-beta.7 <= v1.0.0-beta.11 | v0.2.3 |\n| v1.0.0-beta.14 | v0.2.8 |\n| >= v1.0.0-beta.15 <= v1.0.0-beta.18 | v0.3.3 |\n| >= v1.13.x < v2.0.0 | v1.13.x |\n| >= v2.0.x < v2.1.0 | v2.0.x |\n| >= v2.1.x < v2.3.x | v2.1.x |\n| >= v2.3.x < v2.11.x | v2.3.x |\n| >= v2.11.x < v2.13.x | v2.11.x |\n| >= v2.14.x < v3.0.x | v2.14.x |\n| >= v3.0.x < v3.2.x | v3.0.x-beta.1 |\n| >= v3.2.x < v3.4.x | v3.3.x |\n| >= v3.5.x < v3.12.x | v4.0.x |\n| >= v3.13.x | v5.0.x |\n| >= v3.28.x | Not fully compatible (See [issue](https://github.com/adopted-ember-addons/ember-data-model-fragments/issues/406)) |\n\n#### Notes\n\n- Ember Data v1.0.0-beta.12 introduced a bug that makes it incompatible with any version of this project.\n- Ember Data v1.0.0-beta.15 introduced a breaking change to the serializer API with [Snapshots](https://github.com/emberjs/data/pull/2623). Since this affected fragment serialization as well, support for it was added in v0.3.0. See the [serializing](#serializing) section below for more information.\n- Ember Data v1.0.0-beta.19 refactored a large number of internal APIs this project relied on and is not officially supported. Compatibility was added in v0.4.0 and targeted at Ember Data v1.13.x.\n- Ember Data 2.3 converted to a full Ember CLI addon. Removing the global `DS` namespace and switching to an import module strategy. More: [Ember Data 2.3 Released](http://emberjs.com/blog/2016/01/12/ember-data-2-3-released.html). Following ember-data's lead, the `MF` namespace was also removed. Import modules directly.\n- Ember Data 2.11 changed the implementation of their `ContainerInstanceCache`. We had to follow suite with our patches so that we could continue offering fragments their own default serializer. See [#224](https://github.com/lytics/ember-data-model-fragments/issues/224).\n- Ember Data 2.14 changed `-private` import paths. See [#266](https://github.com/lytics/ember-data-model-fragments/issues/266).\n- Ember Data 3.0 changed `ContainerInstanceCache` import paths. See [e4749c10](https://github.com/lytics/ember-data-model-fragments/pull/287/commits/e4749c107610a6d0dd6032a58c66356e6064562a).\n- Ember Data 3.2 changed `InternalModel#fields`. See: [#310](https://github.com/lytics/ember-data-model-fragments/pull/310).\n- Ember Data 3.5 added `RecordData` interfaces. See: [#324](https://github.com/lytics/ember-data-model-fragments/pull/324), [emberjs/rfcs#293](https://github.com/emberjs/rfcs/pull/293), and [emberjs/data#5616](https://github.com/emberjs/data/pull/5616).\n- Ember Data 3.13 changed `InternalModel` Private APIs. See: [#360] (https://github.com/lytics/ember-data-model-fragments/pull/360)\n\n## Installation\n\nTo install as an Ember CLI addon:\n\n```sh\n$ ember install ember-data-model-fragments\n```\n\nYou may then start creating fragments with:\n\n```sh\n$ ember generate fragment foo someAttr:string anotherAttr:boolean\n```\n\nWhich will create the module `app/models/foo.js` which exports a `Fragment` class with the given attributes.\n\nYou might also want to take a look at [FEDITOR's Ember Data model generator](http://feditor.tech/content/gist/6478b5134893399879c0), which can generate `Model` and `Fragment` classes based on your API's JSON response.\n\n## Example\n\n```javascript\n// app/models/person.js\nimport Model from 'ember-data/model';\nimport {\n  fragment,\n  fragmentArray,\n  array\n} from 'ember-data-model-fragments/attributes';\n\nexport default Model.extend({\n  name      : fragment('name'),\n  addresses : fragmentArray('address'),\n  titles    : array()\n});\n```\n\n```javascript\n// app/models/name.js\nimport attr from 'ember-data/attr';\nimport Fragment from 'ember-data-model-fragments/fragment';\n\nexport default Fragment.extend({\n  first : attr('string'),\n  last  : attr('string')\n});\n```\n\n```javascript\n// app/models/address.js\nimport attr from 'ember-data/attr';\nimport Fragment from 'ember-data-model-fragments/fragment';\n\nexport default Fragment.extend({\n  street  : attr('string'),\n  city    : attr('string'),\n  region  : attr('string'),\n  country : attr('string')\n});\n```\n\nWith a JSON payload of:\n\n```json\n{\n  \"person\": {\n    \"id\": \"1\",\n    \"name\": {\n      \"first\": \"Tyrion\",\n      \"last\": \"Lannister\"\n    },\n    \"addresses\": [\n      {\n        \"street\": \"1 Sky Cell\",\n        \"city\": \"Eyre\",\n        \"region\": \"Vale of Arryn\",\n        \"country\": \"Westeros\"\n      },\n      {\n        \"street\": \"1 Tower of the Hand\",\n        \"city\": \"King's Landing\",\n        \"region\": \"Crownlands\",\n        \"country\": \"Westeros\"\n      }\n    ],\n    \"titles\": [ \"Imp\", \"Hand of the King\" ]\n  }\n}\n```\n\nThe `name` attribute can be treated similar to a `belongsTo` relationship:\n\n```javascript\nlet person = store.getById('person', '1');\nlet name = person.get('name');\n\nperson.get('isDirty'); // false\nname.get('first'); // 'Tyrion'\n\nname.set('first', 'Jamie');\nperson.get('isDirty'); // true\n\nperson.rollback();\nname.get('first'); // 'Tyrion'\n\n// New fragments are created through the store and assigned directly\nperson.set('name', store.createFragment('name', {\n  first : 'Hugor',\n  last  : 'Hill'\n}));\nperson.get('isDirty'); // true\n\n// Fragments can also be set with hashes\nperson.set('name', {\n  'first' : 'Tyrion',\n  'last'  : 'Lannister'\n});\nperson.get('isDirty'); // false\n```\n\nThe `addresses` attribute can be treated similar to a `hasMany` relationship:\n\n```javascript\nlet person = store.getById('person', '1');\nlet addresses = person.get('addresses');\nlet address = addresses.get('lastObject');\n\nperson.get('isDirty'); // false\naddress.get('country'); // 'Westeros'\n\naddress.set('country', 'Essos');\nperson.get('isDirty'); // true\n\nperson.rollback();\naddress.get('country'); // 'Westeros'\n\n// Fragments can be created and added directly through the fragment array\naddresses.get('length'); // 2\naddresses.createFragment({\n  street  : '1 Shy Maid',\n  city    : 'Rhoyne River',\n  region  : 'Free Cities',\n  country : 'Essos'\n});\naddresses.get('length'); // 3\nperson.get('isDirty'); // true\n\n// Or with arrays of objects\nperson.set('addresses', [\n  {\n    street  : '1 Great Pyramid',\n    city    : 'Meereen',\n    region  : 'Slaver\\'s Bay',\n    country : 'Essos'\n  }\n]);\n```\n\nThe `titles` attribute can be treated as an `Ember.Array`:\n\n```javascript\nlet person = store.getById('person', '1');\nlet titles = person.get('titles');\n\nperson.get('isDirty'); // false\ntitles.get('length'); // 2\n\ntitles.pushObject('Halfman');\ntitles.get('length'); // 3\nperson.get('isDirty'); // true\n\nperson.rollback();\ntitles.get('length'); // 2\n```\n\n## Default Values\n\nEmber Data attributes [support a `defaultValue` config option](http://emberjs.com/api/data/classes/DS.html#method_attr) that provides a default value when a model is created through `store#createRecord()`. Similarly, `fragment` and `fragmentArray` properties support a `defaultValue` option:\n\n```javascript\n// app/models/person.js\nimport Model from 'ember-data/model';\nimport {\n  fragment,\n  fragmentArray,\n  array\n} from 'ember-data-model-fragments/attributes';\n\nexport default Model.extend({\n  name      : fragment('name', { defaultValue: { first: 'Faceless', last: 'Man' } }),\n  addresses : fragmentArray('address'),\n  titles    : array('string')\n});\n```\n\nSince JavaScript objects and arrays are passed by reference, the value of `defaultValue` is copied using `Ember.copy` in order to prevent all instances sharing the same value. If a `defaultValue` option is not specified, `fragment` properties default to `null` and `fragmentArray` properties default to an empty array. Note that this may cause confusion when creating a record with a `fragmentArray` property:\n\n```javascript\nlet person = store.createRecord('person');\nlet addresses = person.get('addresses'); // null\n\n// Fails with \"Cannot read property 'createFragment' of null\"\naddresses.createFragment({\n  ...\n});\n```\n\nLike `attr`, the `defaultValue` option can be a function that is invoked to generate the default value:\n\n```javascript\n// app/models/person.js\nimport Model from 'ember-data/model';\nimport { fragment } from 'ember-data-model-fragments/attributes';\n\nexport default Model.extend({\n  name: fragment('name', {\n    defaultValue() {\n      return {\n        first: 'Unsullied',\n        last: Ember.uuid()\n      }\n    }\n  })\n});\n```\n## Serializing\n\nSerializing records with fragment attributes works using a special `Transform` that serializes each fragment or fragment array. This results in fragments being nested in JSON as expected, and avoids the need for any custom serialization logic for most cases. This also means that model fragments can have their own custom serializers, just as normal models can:\n\n```javascript\n// app/models/name.js\nimport attr from 'ember-data/attr';\nimport Fragment from 'ember-data-model-fragments/fragment';\n\nexport default Fragment.extend({\n  given  : attr('string'),\n  family : attr('string')\n});\n```\n\n```javascript\n// apps/serializers/name.js\n// Serializers for fragments work just as with models\nimport JSONSerializer from 'ember-data/serializers/json';\n\nexport default JSONSerializer.extend({\n  attrs: {\n    given  : 'first',\n    family : 'last'\n  }\n});\n```\n\nSince fragment deserialization uses the value of a single attribute in the parent model, the `normalizeResponse` method of the serializer is never used. And since the attribute value is not a full-fledged [JSON API](http://jsonapi.org/) response, `JSONAPISerializer` cannot be used with fragments. Because of this, auto-generated fragment serializers **do not use the application serializer** and instead use `JSONSerializer`.\n\nIf common logic must be added to auto-generated fragment serializers, apps can register a custom `serializer:-fragment` with the application in an initializer.\n\n```javascript\n// app/serializers/fragment.js\nimport JSONSerializer from 'ember-data/serializers/json';\n\nexport default JSONSerializer.extend({\n\n});\n```\n\n```javascript\n// app/initializers/fragment-serializer.js\nimport FragmentSerializer from '../serializers/fragment';\n\nexport function initialize(application) {\n\tapplication.register('serializer:-fragment', FragmentSerializer);\n}\n\nexport default {\n\tname: 'fragment-serializer',\n\tinitialize: initialize\n};\n```\n\nIf custom serialization of the owner record is needed, fragment [snapshots](http://emberjs.com/api/data/classes/DS.Snapshot.html) can be accessed using the [`Snapshot#attr`](http://emberjs.com/api/data/classes/DS.Snapshot.html#method_attr) method. Note that this differs from how relationships are accessed on snapshots (using `belongsTo`/`hasMany` methods):\n\n```javascript\n// apps/serializers/person.js\n// Fragment snapshots are accessed using `snapshot.attr()`\nimport JSONSerializer from 'ember-data/serializers/json';\n\nexport default JSONSerializer.extend({\n  serialize(snapshot, options) {\n    let json = this._super(...arguments);\n\n    // Returns a `Snapshot` instance of the fragment\n    let nameSnapshot = snapshot.attr('name');\n\n    json.full_name = nameSnapshot.attr('given') + ' ' + nameSnapshot.attr('family');\n\n    // Returns a plain array of `Snapshot` instances\n    let addressSnapshots = snapshot.attr('addresses');\n\n    json.countries = addressSnapshots.map(function(addressSnapshot) {\n      return addressSnapshot.attr('country');\n    });\n\n    // Returns a plain array of primitives\n    let titlesSnapshot = snapshot.attr('titles');\n\n    json.title_count = titlesSnapshot.length;\n\n    return json;\n  }\n});\n```\n\n## Nesting\n\nNesting of fragments is fully supported:\n\n```javascript\n// app/models/user.js\nimport Model from 'ember-data/model';\nimport attr from 'ember-data/attr';\nimport { fragmentArray } from 'ember-data-model-fragments/attributes';\n\nexport default Model.extend({\n  name   : attr('string'),\n  orders : fragmentArray('order')\n});\n```\n\n```javascript\n// app/models/order.js\nimport attr from 'ember-data/attr';\nimport Fragment from 'ember-data-model-fragments/fragment';\nimport { fragmentArray } from 'ember-data-model-fragments/attributes';\n\nexport default Fragment.extend({\n  amount   : attr('string'),\n  products : fragmentArray('product')\n});\n```\n\n```javascript\n// app/models/product.js\nimport attr from 'ember-data/attr';\nimport Fragment from 'ember-data-model-fragments/fragment';\n\nexport default Fragment.extend({\n  name  : attr('string'),\n  sku   : attr('string'),\n  price : attr('string')\n});\n```\n\nWith a JSON payload of:\n\n```json\n{\n  \"id\": \"1\",\n  \"name\": \"Tyrion Lannister\",\n  \"orders\": [\n    {\n      \"amount\": \"799.98\",\n      \"products\" : [\n        {\n          \"name\": \"Tears of Lys\",\n          \"sku\": \"poison-bd-32\",\n          \"price\": \"499.99\"\n        },\n        {\n          \"name\": \"The Strangler\",\n          \"sku\": \"poison-md-24\",\n          \"price\": \"299.99\"\n        }\n      ]\n    },\n    {\n      \"amount\": \"10999.99\",\n      \"products\": [\n        {\n          \"name\": \"Lives of Four Kings\",\n          \"sku\": \"old-book-32\",\n          \"price\": \"10999.99\"\n        }\n      ]\n    }\n  ]\n}\n```\n\nDirty state propagates up to the parent record, rollback cascades down:\n\n```javascript\nlet user = store.getById('user', '1');\nlet product = user.get('orders.firstObject.products.lastObject');\n\nuser.get('isDirty'); // false\nproduct.get('price'); // '299.99'\n\nproduct.set('price', '1.99');\nuser.get('isDirty'); // true\n\nuser.rollback();\nuser.get('isDirty'); // false\nproduct.get('price'); // '299.99'\n```\n\nHowever, note that fragments do not currently support `belongsTo` or `hasMany` properties. See the [Limitations](#relationships-to-models) section below.\n\n## Polymorphism\n\nEmber Data: Model Fragments has support for *reading* polymorphic fragments. To use this feature, pass an options object to `fragment` or `fragmentArray`\nwith `polymorphic` set to true. In addition the `typeKey` can be set, which defaults to `'type'`.\n\nThe `typeKey` option might be a `String` or a `Function` returning a `String`. If you use a function, the `data` and the `owner` will be passed as parameter.\n\nThe `typeKey`'s value must be the lowercase name of a class that is assignment-compatible to the declared type of the fragment attribute. That is, it must be the declared type itself or a subclass. Additionally, the `typeKey`'s value must be a field on the parent class.\n\nIn the following example the declared type of `animals` is `animal`, which corresponds to the class `Animal`. `Animal` has two subclasses: `Elephant` and `Lion`,\nso to `typeKey`'s value can be `'animal'`, `'elephant'` or `'lion'`.\n\n```javascript\n// app/models/zoo.js\nimport Model from 'ember-data/model';\nimport attr from 'ember-data/attr';\nimport { fragmentArray } from 'ember-data-model-fragments/attributes';\n\nexport default Model.extend({\n  name: attr('string'),\n  city: attr('string'),\n  animals: fragmentArray('animal', { polymorphic: true, typeKey: '$type' }),\n  bestAnimal: fragment('animal', { polymorphic: true, typeKey: (data) => `my-model-prefix-${data.name}` })\n});\n```\n\n```javascript\n// app/models/animal.js\nimport Fragment from 'ember-data-model-fragments/fragment';\nimport attr from 'ember-data/attr';\n\nexport default Fragment.extend({\n  $type: attr('string'),\n  name: attr('string'),\n});\n```\n\n```javascript\n// app/models/elephant.js\nimport Animal from './Animal';\nimport attr from 'ember-data/attr';\n\nexport default Animal.extend({\n  trunkLength: attr('number'),\n});\n```\n\n```javascript\n// app/models/lion.js\nimport Animal from './Animal';\nimport attr from 'ember-data/attr';\n\nexport default Animal.extend({\n  hasManes: attr('boolean'),\n});\n```\n\nThe expected JSON payload is as follows:\n```json\n{\n  \"Zoo\" : {\n    \"id\" : \"1\",\n    \"name\" : \"Winterfell Zoo\",\n    \"city\" : \"Winterfell\",\n    \"animals\" : [\n      {\n        \"$type\" : \"lion\",\n        \"name\" : \"Simba\",\n        \"hasManes\" : false\n      },\n      {\n        \"$type\" : \"lion\",\n        \"name\" : \"Leonard\",\n        \"hasManes\" : true\n      },\n      {\n        \"$type\" : \"elephant\",\n        \"name\" : \"Trunky\",\n        \"trunkLength\" : 10\n      },\n      {\n        \"$type\" : \"elephant\",\n        \"name\" : \"Snuffles\",\n        \"trunkLength\" : 9\n      }\n    ]\n  }\n}\n```\n\nSerializing the fragment type back to JSON is not currently supported out of the box. To serialize the polymorphic type, create a custom serializer to perform manual introspection:\n\n```javascript\n// app/serializers/animal.js\nimport JSONSerializer from 'ember-data/serializers/json';\nimport Elephant from 'app/models/elephant';\nimport Lion from 'app/models/elephant';\n\nexport default JSONSerializer.extend({\n  serialize(record, options) {\n    let json = this._super(...arguments);\n\n    if (record instanceof Elephant) {\n      json.$type = 'elephant';\n    } else if (record instanceof Lion) {\n      json.$type = 'lion';\n    } else {\n      json.$type = 'animal';\n    }\n\n    return json;\n  }\n});\n```\n\n```javascript\n// app/serializers/elephant.js\nimport AnimalSerializer from './animal';\n\nexport default AnimalSerializer;\n```\n\n```javascript\n// app/serializers/lion.js\nimport AnimalSerializer from './animal';\n\nexport default AnimalSerializer;\n```\n\n## TypeScript\n\nTypeScript declarations are included out of the box. For additional type safety for `createFragment`, `push`, etc. you can index your fragment classes in the `FragmentRegistry`:\n\n```typescript\n// app/models/address.ts\nimport Fragment from 'ember-data-model-fragments/fragment';\nimport { attr } from '@ember-data/model';\n\nexport default class AddressFragment extends Fragment {\n  @attr('string')\n  declare street: string;\n\n  @attr('string')\n  declare city: string;\n\n  @attr('string')\n  declare region: string;\n\n  @attr('string')\n  declare country: string;\n}\n\ndeclare module 'ember-data-model-fragments/types/registries/fragment' {\n  export default interface FragmentRegistry {\n    address: AddressFragment;\n  }\n}\n```\n\n## Limitations\n\n### Conflict Resolution\n\nThere is a very good reason that support for id-less embedded records has not been added to Ember Data: merging conflicts is very difficult. Imagine a scenario where your app requests a record with an array of simple embedded objects, and then a minute later makes the same request again. If the array of objects has changed – for instance an object is added to the beginning – without unique identifiers there is no reliable way to map those objects onto the array of records in memory.\n\nThis plugin handles merging fragment arrays *by swapping out the data of existing fragments*. For example, when a record is fetched with a fragment array property, a fragment model is created for each object in the array. Then, after the record is reloaded via `reload` or `save`, the data received is mapped directly onto those existing fragment instances, adding or removing from the end when necessary. This means that reordering the array will cause fragment objects' data to swap, rather than simply reordering the array of fragments in memory. The biggest implication of this behavior is when a fragment in a fragment array is dirty and the parent model gets reloaded. If the record is then saved, the change will likely affect the wrong object, causing data loss. Additionally, any time a reference to a model fragment is held onto, reloading can give it a completely different semantic meaning. If your app does not persist models with fragment arrays, this is of no concern (and indeed you may wish to use the `EmbeddedRecordMixin` instead).\n\n### Filtered Record Arrays\n\nAnother consequence of id-less records is that an ID map of all fragment instances of a given type is not possible. This means no `store.all('<fragment_type>')`, and no ability to display all known fragments (e.g. names or addresses) without iterating over all owner records and manually building a list.\n\n### Relationships to Models\n\nCurrently, fragments cannot have normal `belongsTo` or `hasMany` relationships. This is not a technical limitation, but rather due to the fact that relationship management in Ember Data is in a state of flux and would require accessing private (and changing) APIs.\n\n## Testing\n\nBuilding requires [Ember CLI](http://www.ember-cli.com/) and running tests requires [Test 'Em](https://github.com/airportyh/testem), which can all be installed globally with:\n\n```sh\n$ yarn global add ember-cli\n```\n\nThen install NPM packages and start the development test server:\n\n```sh\n$ yarn\n$ ember test --server\n```\n\nIt is also possible to run the tests in a headless fashion. This requires [PhantomJS 2](http://phantomjs.org) to be installed.\n\n```sh\n$ ember test\n\n# Using `yarn test` will invoke `ember try:testall`.\n# This will test each version of ember supported by this addon.\n$ yarn test\n```\n\n## Contributing\n\nWhen reporting an issue, follow the [Ember guidelines](https://github.com/emberjs/ember.js/blob/master/CONTRIBUTING.md#reporting-a-bug). When contributing features, follow [Github guidelines](https://help.github.com/articles/fork-a-repo) for forking and creating a new pull request. All existing tests must pass (or be suitably modified), and all new features must be accompanied by tests to be considered.\n","readmeFilename":"README.md"}