dist/globals/ember-data.prod.js in ember-data-source-2.12.2 vs dist/globals/ember-data.prod.js in ember-data-source-2.13.0.beta.1

- old
+ new

@@ -1,329 +1,8 @@ (function(){ "use strict"; -/*! - * @overview Ember Data - * @copyright Copyright 2011-2016 Tilde Inc. and contributors. - * Portions Copyright 2011 LivingSocial Inc. - * @license Licensed under MIT license (see license.js) - * @version 2.12.2 - */ - -var loader, define, requireModule, require, requirejs; - -(function (global) { - 'use strict'; - - var heimdall = global.heimdall; - - function dict() { - var obj = Object.create(null); - obj['__'] = undefined; - delete obj['__']; - return obj; - } - - // Save off the original values of these globals, so we can restore them if someone asks us to - var oldGlobals = { - loader: loader, - define: define, - requireModule: requireModule, - require: require, - requirejs: requirejs - }; - - requirejs = require = requireModule = function (name) { - var pending = []; - var mod = findModule(name, '(require)', pending); - - for (var i = pending.length - 1; i >= 0; i--) { - pending[i].exports(); - } - - return mod.module.exports; - }; - - loader = { - noConflict: function (aliases) { - var oldName, newName; - - for (oldName in aliases) { - if (aliases.hasOwnProperty(oldName)) { - if (oldGlobals.hasOwnProperty(oldName)) { - newName = aliases[oldName]; - - global[newName] = global[oldName]; - global[oldName] = oldGlobals[oldName]; - } - } - } - } - }; - - var _isArray; - if (!Array.isArray) { - _isArray = function (x) { - return Object.prototype.toString.call(x) === '[object Array]'; - }; - } else { - _isArray = Array.isArray; - } - - var registry = dict(); - var seen = dict(); - - var uuid = 0; - - function unsupportedModule(length) { - throw new Error('an unsupported module was defined, expected `define(name, deps, module)` instead got: `' + length + '` arguments to define`'); - } - - var defaultDeps = ['require', 'exports', 'module']; - - function Module(name, deps, callback, alias) { - this.id = uuid++; - this.name = name; - this.deps = !deps.length && callback.length ? defaultDeps : deps; - this.module = { exports: {} }; - this.callback = callback; - this.hasExportsAsDep = false; - this.isAlias = alias; - this.reified = new Array(deps.length); - - /* - Each module normally passes through these states, in order: - new : initial state - pending : this module is scheduled to be executed - reifying : this module's dependencies are being executed - reified : this module's dependencies finished executing successfully - errored : this module's dependencies failed to execute - finalized : this module executed successfully - */ - this.state = 'new'; - } - - Module.prototype.makeDefaultExport = function () { - var exports = this.module.exports; - if (exports !== null && (typeof exports === 'object' || typeof exports === 'function') && exports['default'] === undefined && Object.isExtensible(exports)) { - exports['default'] = exports; - } - }; - - Module.prototype.exports = function () { - // if finalized, there is no work to do. If reifying, there is a - // circular dependency so we must return our (partial) exports. - if (this.state === 'finalized' || this.state === 'reifying') { - return this.module.exports; - } - - if (loader.wrapModules) { - this.callback = loader.wrapModules(this.name, this.callback); - } - - this.reify(); - - var result = this.callback.apply(this, this.reified); - this.state = 'finalized'; - - if (!(this.hasExportsAsDep && result === undefined)) { - this.module.exports = result; - } - this.makeDefaultExport(); - return this.module.exports; - }; - - Module.prototype.unsee = function () { - this.state = 'new'; - this.module = { exports: {} }; - }; - - Module.prototype.reify = function () { - if (this.state === 'reified') { - return; - } - this.state = 'reifying'; - try { - this.reified = this._reify(); - this.state = 'reified'; - } finally { - if (this.state === 'reifying') { - this.state = 'errored'; - } - } - }; - - Module.prototype._reify = function () { - var reified = this.reified.slice(); - for (var i = 0; i < reified.length; i++) { - var mod = reified[i]; - reified[i] = mod.exports ? mod.exports : mod.module.exports(); - } - return reified; - }; - - Module.prototype.findDeps = function (pending) { - if (this.state !== 'new') { - return; - } - - this.state = 'pending'; - - var deps = this.deps; - - for (var i = 0; i < deps.length; i++) { - var dep = deps[i]; - var entry = this.reified[i] = { exports: undefined, module: undefined }; - if (dep === 'exports') { - this.hasExportsAsDep = true; - entry.exports = this.module.exports; - } else if (dep === 'require') { - entry.exports = this.makeRequire(); - } else if (dep === 'module') { - entry.exports = this.module; - } else { - entry.module = findModule(resolve(dep, this.name), this.name, pending); - } - } - }; - - Module.prototype.makeRequire = function () { - var name = this.name; - var r = function (dep) { - return require(resolve(dep, name)); - }; - r['default'] = r; - r.has = function (dep) { - return has(resolve(dep, name)); - }; - return r; - }; - - define = function (name, deps, callback) { - var module = registry[name]; - - // If a module for this name has already been defined and is in any state - // other than `new` (meaning it has been or is currently being required), - // then we return early to avoid redefinition. - if (module && module.state !== 'new') { - return; - } - - if (arguments.length < 2) { - unsupportedModule(arguments.length); - } - - if (!_isArray(deps)) { - callback = deps; - deps = []; - } - - if (callback instanceof Alias) { - registry[name] = new Module(callback.name, deps, callback, true); - } else { - registry[name] = new Module(name, deps, callback, false); - } - }; - - // we don't support all of AMD - // define.amd = {}; - - function Alias(path) { - this.name = path; - } - - define.alias = function (path) { - return new Alias(path); - }; - - function missingModule(name, referrer) { - throw new Error('Could not find module `' + name + '` imported from `' + referrer + '`'); - } - - function findModule(name, referrer, pending) { - var mod = registry[name] || registry[name + '/index']; - - while (mod && mod.isAlias) { - mod = registry[mod.name]; - } - - if (!mod) { - missingModule(name, referrer); - } - - if (pending && mod.state !== 'pending' && mod.state !== 'finalized') { - mod.findDeps(pending); - pending.push(mod); - } - return mod; - } - - function resolve(child, name) { - if (child.charAt(0) !== '.') { - return child; - } - - var parts = child.split('/'); - var nameParts = name.split('/'); - var parentBase = nameParts.slice(0, -1); - - for (var i = 0, l = parts.length; i < l; i++) { - var part = parts[i]; - - if (part === '..') { - if (parentBase.length === 0) { - throw new Error('Cannot access parent module of root'); - } - parentBase.pop(); - } else if (part === '.') { - continue; - } else { - parentBase.push(part); - } - } - - return parentBase.join('/'); - } - - function has(name) { - return !!(registry[name] || registry[name + '/index']); - } - - requirejs.entries = requirejs._eak_seen = registry; - requirejs.has = has; - requirejs.unsee = function (moduleName) { - findModule(moduleName, '(unsee)', false).unsee(); - }; - - requirejs.clear = function () { - requirejs.entries = requirejs._eak_seen = registry = dict(); - seen = dict(); - }; - - // This code primes the JS engine for good performance by warming the - // JIT compiler for these functions. - define('foo', function () {}); - define('foo/bar', [], function () {}); - define('foo/asdf', ['module', 'exports', 'require'], function (module, exports, require) { - if (require.has('foo/bar')) { - require('foo/bar'); - } - }); - define('foo/baz', [], define.alias('foo')); - define('foo/quz', define.alias('foo')); - define('foo/bar', ['foo', './quz', './baz', './asdf', './bar', '../foo'], function () {}); - define('foo/main', ['foo/bar'], function () {}); - - require('foo/main'); - require.unsee('foo/bar'); - - requirejs.clear(); - - if (typeof exports === 'object' && typeof module === 'object' && module.exports) { - module.exports = { require: require, define: define }; - } -})(this); define("ember-data/-private/adapters", ["exports", "ember-data/adapters/json-api", "ember-data/adapters/rest"], function (exports, _emberDataAdaptersJsonApi, _emberDataAdaptersRest) { exports.JSONAPIAdapter = _emberDataAdaptersJsonApi.default; exports.RESTAdapter = _emberDataAdaptersRest.default; }); /** @@ -411,14 +90,14 @@ @param {String} modelName @param {String} id @return {String} url */ _buildURL: function (modelName, id) { + var path = undefined; var url = []; var host = get(this, 'host'); var prefix = this.urlPrefix(); - var path; if (modelName) { path = this.pathForType(modelName); if (path) { url.push(path); @@ -835,12 +514,13 @@ function assertPolymorphicType(parentInternalModel, relationshipMeta, addedInternalModel) { var addedModelName = addedInternalModel.modelName; var parentModelName = parentInternalModel.modelName; var key = relationshipMeta.key; - var relationshipClass = parentInternalModel.store.modelFor(relationshipMeta.type); - var assertionMessage = 'You cannot add a record of modelClass \'' + addedModelName + '\' to the \'' + parentModelName + '.' + key + '\' relationship (only \'' + relationshipClass.modelName + '\' allowed)'; + var relationshipModelName = relationshipMeta.type; + var relationshipClass = parentInternalModel.store.modelFor(relationshipModelName); + var assertionMessage = 'You cannot add a record of modelClass \'' + addedModelName + '\' to the \'' + parentModelName + '.' + key + '\' relationship (only \'' + relationshipModelName + '\' allowed)'; assert(assertionMessage, checkPolymorphic(relationshipClass, addedInternalModel.modelClass)); } }); define('ember-data/-private/ext/date', ['exports', 'ember', 'ember-data/-private/debug'], function (exports, _ember, _emberDataPrivateDebug) { @@ -861,20 +541,21 @@ var origParse = Date.parse; var numericKeys = [1, 4, 5, 6, 7, 10, 11]; var parseDate = function (date) { - var timestamp, struct; + var timestamp = undefined, + struct = undefined; var minutesOffset = 0; // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string // before falling back to any implementation-specific date parsing, so that’s what we do, even if native // implementations could be faster // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm if (struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2}):?(?:(\d{2}))?)?)?$/.exec(date)) { // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC - for (var i = 0, k; k = numericKeys[i]; ++i) { + for (var i = 0, k = undefined; k = numericKeys[i]; ++i) { struct[k] = +struct[k] || 0; } // allow undefined days and months struct[2] = (+struct[2] || 1) - 1; @@ -1029,25 +710,58 @@ registry.register('transform:date', _emberDataPrivateTransforms.DateTransform); registry.register('transform:number', _emberDataPrivateTransforms.NumberTransform); registry.register('transform:string', _emberDataPrivateTransforms.StringTransform); } }); -define('ember-data/-private/instance-initializers/initialize-store-service', ['exports'], function (exports) { +define('ember-data/-private/instance-initializers/initialize-store-service', ['exports', 'ember-data/-private/debug'], function (exports, _emberDataPrivateDebug) { exports.default = initializeStoreService; + /* - Configures a registry for use with an Ember-Data - store. + Configures a registry for use with an Ember-Data + store. - @method initializeStoreService - @param {Ember.ApplicationInstance} applicationOrRegistry - */ + @method initializeStoreService + @param {Ember.ApplicationInstance} applicationOrRegistry + */ function initializeStoreService(application) { var container = application.lookup ? application : application.container; // Eagerly generate the store so defaultStore is populated. container.lookup('service:store'); + + var initializers = application.application.constructor.initializers; + deprecateOldEmberDataInitializers(initializers); } + + var deprecatedInitializerNames = ['data-adapter', 'injectStore', 'transforms', 'store']; + + function matchesDeprecatedInititalizer(name) { + return deprecatedInitializerNames.indexOf(name) !== -1; + } + + function deprecateOldEmberDataInitializers(initializers) { + // collect all of the initializers + var initializersArray = Object.keys(initializers).map(function (key) { + return initializers[key]; + }); + + // filter out all of the Ember Data initializer. We have some + // deprecated initializers that depend on other deprecated + // initializers which may trigger the deprecation warning + // unintentionally. + var nonEmberDataInitializers = initializersArray.filter(function (initializer) { + return !matchesDeprecatedInititalizer(initializer.name); + }); + + nonEmberDataInitializers.forEach(warnForDeprecatedInitializers); + } + + function warnForDeprecatedInitializers(initializer) { + var deprecatedBeforeInitializer = matchesDeprecatedInititalizer(initializer.before); + var deprecatedAfterInitializer = matchesDeprecatedInititalizer(initializer.after); + var deprecatedProp = deprecatedBeforeInitializer ? 'before' : 'after'; + } }); define("ember-data/-private/serializers", ["exports", "ember-data/serializers/json-api", "ember-data/serializers/json", "ember-data/serializers/rest"], function (exports, _emberDataSerializersJsonApi, _emberDataSerializersJson, _emberDataSerializersRest) { exports.JSONAPISerializer = _emberDataSerializersJsonApi.default; exports.JSONSerializer = _emberDataSerializersJson.default; exports.RESTSerializer = _emberDataSerializersRest.default; @@ -1084,14 +798,14 @@ }); /** @module ember-data */ define('ember-data/-private/system/debug/debug-adapter', ['exports', 'ember', 'ember-data/model'], function (exports, _ember, _emberDataModel) { - var get = _ember.default.get; var capitalize = _ember.default.String.capitalize; var underscore = _ember.default.String.underscore; var assert = _ember.default.assert; + var get = _ember.default.get; /* Extend `Ember.DataAdapter` with ED specific code. @class DebugAdapter @@ -1148,12 +862,11 @@ record.eachAttribute(function (key) { if (count++ > _this.attributeLimit) { return false; } - var value = get(record, key); - columnValues[key] = value; + columnValues[key] = get(record, key); }); return columnValues; }, getRecordKeywords: function (record) { @@ -1216,10 +929,72 @@ }); }); /** @module ember-data */ +define("ember-data/-private/system/diff-array", ["exports"], function (exports) { + exports.default = diffArray; + /** + @namespace + @method diff-array + @for DS + @param {Array} oldArray the old array + @param {Array} newArray the new array + @return {hash} { + firstChangeIndex: <integer>, // null if no change + addedCount: <integer>, // 0 if no change + removedCount: <integer> // 0 if no change + } + */ + + function diffArray(oldArray, newArray) { + var oldLength = oldArray.length; + var newLength = newArray.length; + + var shortestLength = Math.min(oldLength, newLength); + var firstChangeIndex = null; // null signifies no changes + + // find the first change + for (var i = 0; i < shortestLength; i++) { + // compare each item in the array + if (oldArray[i] !== newArray[i]) { + firstChangeIndex = i; + break; + } + } + + if (firstChangeIndex === null && newLength !== oldLength) { + // no change found in the overlapping block + // and array lengths differ, + // so change starts at end of overlap + firstChangeIndex = shortestLength; + } + + var addedCount = 0; + var removedCount = 0; + if (firstChangeIndex !== null) { + // we found a change, find the end of the change + var unchangedEndBlockLength = shortestLength - firstChangeIndex; + // walk back from the end of both arrays until we find a change + for (var i = 1; i <= shortestLength; i++) { + // compare each item in the array + if (oldArray[oldLength - i] !== newArray[newLength - i]) { + unchangedEndBlockLength = i - 1; + break; + } + } + addedCount = newLength - unchangedEndBlockLength - firstChangeIndex; + removedCount = oldLength - unchangedEndBlockLength - firstChangeIndex; + } + + return { + firstChangeIndex: firstChangeIndex, + addedCount: addedCount, + removedCount: removedCount + }; + } +}); define("ember-data/-private/system/empty-object", ["exports"], function (exports) { exports.default = EmptyObject; // This exists because `Object.create(null)` is absurdly slow compared // to `new EmptyObject()`. In either case, you want a null prototype // when you're treating the object instances as arbitrary dictionaries @@ -1237,11 +1012,11 @@ function EmptyObject() {} EmptyObject.prototype = proto; }); -define('ember-data/-private/system/identity-map', ['exports', 'ember-data/-private/system/record-map'], function (exports, _emberDataPrivateSystemRecordMap) { +define('ember-data/-private/system/identity-map', ['exports', 'ember-data/-private/system/internal-model-map'], function (exports, _emberDataPrivateSystemInternalModelMap) { 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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } /** @@ -1256,53 +1031,203 @@ function IdentityMap() { this._map = Object.create(null); } /** - Retrieves the `RecordMap` for a given modelName, + Retrieves the `InternalModelMap` for a given modelName, creating one if one did not already exist. This is similar to `getWithDefault` or `get` on a `MapWithDefault` @method retrieve @param modelName a previously normalized modelName - @returns {RecordMap} the RecordMap for the given modelName + @returns {InternalModelMap} the InternalModelMap for the given modelName */ _createClass(IdentityMap, [{ key: 'retrieve', value: function retrieve(modelName) { - var recordMap = this._map[modelName]; + var map = this._map[modelName]; - if (!recordMap) { - recordMap = this._map[modelName] = new _emberDataPrivateSystemRecordMap.default(modelName); + if (!map) { + map = this._map[modelName] = new _emberDataPrivateSystemInternalModelMap.default(modelName); } - return recordMap; + return map; } /** Clears the contents of all known `RecordMaps`, but does - not remove the RecordMap instances. + not remove the InternalModelMap instances. @method clear */ }, { key: 'clear', value: function clear() { - var recordMaps = this._map; - var keys = Object.keys(recordMaps); + var map = this._map; + var keys = Object.keys(map); for (var i = 0; i < keys.length; i++) { var key = keys[i]; - recordMaps[key].clear(); + map[key].clear(); } } }]); return IdentityMap; })(); exports.default = IdentityMap; }); +define('ember-data/-private/system/internal-model-map', ['exports', 'ember-data/-private/debug', 'ember-data/-private/system/model/internal-model'], function (exports, _emberDataPrivateDebug, _emberDataPrivateSystemModelInternalModel) { + 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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + + /** + `InternalModelMap` is a custom storage map for internalModels of a given modelName + used by `IdentityMap`. + + It was extracted from an implicit pojo based "internalModel map" and preserves + that interface while we work towards a more official API. + + @class InternalModelMap + @private + */ + + var InternalModelMap = (function () { + function InternalModelMap(modelName) { + this.modelName = modelName; + this._idToModel = Object.create(null); + this._models = []; + this._metadata = null; + } + + /** + A "map" of records based on their ID for this modelName + */ + + _createClass(InternalModelMap, [{ + key: 'get', + + /** + * + * @param id + * @returns {InternalModel} + */ + value: function get(id) { + var r = this._idToModel[id]; + return r; + } + }, { + key: 'has', + value: function has(id) { + return !!this._idToModel[id]; + } + }, { + key: 'set', + value: function set(id, internalModel) { + + this._idToModel[id] = internalModel; + } + }, { + key: 'add', + value: function add(internalModel, id) { + + if (id) { + this._idToModel[id] = internalModel; + } + + this._models.push(internalModel); + } + }, { + key: 'remove', + value: function remove(internalModel, id) { + if (id) { + delete this._idToModel[id]; + } + + var loc = this._models.indexOf(internalModel); + + if (loc !== -1) { + this._models.splice(loc, 1); + } + } + }, { + key: 'contains', + value: function contains(internalModel) { + return this._models.indexOf(internalModel) !== -1; + } + + /** + An array of all models of this modelName + */ + }, { + key: 'clear', + + /** + Destroy all models in the internalModelTest and wipe metadata. + @method clear + */ + value: function clear() { + if (this._models) { + var models = this._models; + this._models = []; + + for (var i = 0; i < models.length; i++) { + var model = models[i]; + model.unloadRecord(); + } + } + + this._metadata = null; + } + }, { + key: 'destroy', + value: function destroy() { + this._store = null; + this._modelClass = null; + } + }, { + key: 'idToRecord', + get: function () { + return this._idToModel; + } + }, { + key: 'length', + get: function () { + return this._models.length; + } + }, { + key: 'models', + get: function () { + return this._models; + } + + /** + * meta information about internalModels + */ + }, { + key: 'metadata', + get: function () { + return this._metadata || (this._metadata = Object.create(null)); + } + + /** + deprecated (and unsupported) way of accessing modelClass + @deprecated + */ + }, { + key: 'type', + get: function () { + throw new Error('InternalModelMap.type is no longer available'); + } + }]); + + return InternalModelMap; + })(); + + exports.default = InternalModelMap; +}); define('ember-data/-private/system/is-array-like', ['exports', 'ember'], function (exports, _ember) { exports.default = isArrayLike; /* We're using this to detect arrays and "array-like" objects. @@ -1334,11 +1259,11 @@ return true; } return false; } }); -define("ember-data/-private/system/many-array", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/system/promise-proxies", "ember-data/-private/system/store/common"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemStoreCommon) { +define("ember-data/-private/system/many-array", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/system/promise-proxies", "ember-data/-private/system/store/common", "ember-data/-private/system/diff-array"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemStoreCommon, _emberDataPrivateSystemDiffArray) { var get = _ember.default.get; var set = _ember.default.set; /** A `ManyArray` is a `MutableArray` that represents the contents of a has-many @@ -1446,32 +1371,32 @@ @property {ManyRelationship} relationship @private */ this.relationship = this.relationship || null; - this.currentState = _ember.default.A([]); + this.currentState = []; this.flushCanonical(false); }, objectAt: function (index) { + var object = this.currentState[index]; //Ember observers such as 'firstObject', 'lastObject' might do out of bounds accesses - if (!this.currentState[index]) { - return undefined; + if (object === undefined) { + return; } - return this.currentState[index].getRecord(); + return object.getRecord(); }, flushCanonical: function () { var isInitialized = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0]; - // TODO make this smarter, currently its plenty stupid - // TODO this filtering was re-introduced as a bugfix, but seems unneeded in 2.13 - // with the changes to internalModel cleanup in that version. - var toSet = this.canonicalState.filter(function (internalModel) { - return internalModel.currentState.stateName !== 'root.deleted.saved'; - }); + // It’s possible the parent side of the relationship may have been unloaded by this point + if (!(0, _emberDataPrivateSystemStoreCommon._objectIsAlive)(this)) { + return; + } + var toSet = this.canonicalState; //a hack for not removing new records //TODO remove once we have proper diffing var newRecords = this.currentState.filter( // only add new records which are not yet in the canonical state of this @@ -1479,23 +1404,27 @@ // been 'acknowleged' to be in the relationship via a store.push) function (internalModel) { return internalModel.isNew() && toSet.indexOf(internalModel) === -1; }); toSet = toSet.concat(newRecords); - var oldLength = this.length; - this.arrayContentWillChange(0, this.length, toSet.length); - // It’s possible the parent side of the relationship may have been unloaded by this point - if ((0, _emberDataPrivateSystemStoreCommon._objectIsAlive)(this)) { + + // diff to find changes + var diff = (0, _emberDataPrivateSystemDiffArray.default)(this.currentState, toSet); + + if (diff.firstChangeIndex !== null) { + // it's null if no change found + // we found a change + this.arrayContentWillChange(diff.firstChangeIndex, diff.removedCount, diff.addedCount); this.set('length', toSet.length); + this.currentState = toSet; + this.arrayContentDidChange(diff.firstChangeIndex, diff.removedCount, diff.addedCount); + if (isInitialized && diff.addedCount > 0) { + //notify only on additions + //TODO only notify if unloaded + this.relationship.notifyHasManyChanged(); + } } - this.currentState = toSet; - this.arrayContentDidChange(0, oldLength, this.length); - - if (isInitialized) { - //TODO Figure out to notify only on additions and maybe only if unloaded - this.relationship.notifyHasManyChanged(); - } }, internalReplace: function (idx, amt, objects) { if (!objects) { objects = []; @@ -1539,20 +1468,20 @@ @method loadingRecordsCount @param {Number} count @private */ loadingRecordsCount: function (count) { - this.loadingRecordsCount = count; + this._loadingRecordsCount = count; }, /** @method loadedRecord @private */ loadedRecord: function () { - this.loadingRecordsCount--; - if (this.loadingRecordsCount === 0) { + this._loadingRecordsCount--; + if (this._loadingRecordsCount === 0) { set(this, 'isLoaded', true); this.trigger('didLoad'); } }, @@ -1613,13 +1542,12 @@ @return {DS.Model} record */ createRecord: function (hash) { var store = get(this, 'store'); var type = get(this, 'type'); - var record; - record = store.createRecord(type.modelName, hash); + var record = store.createRecord(type.modelName, hash); this.pushObject(record); return record; } }); @@ -1660,18 +1588,18 @@ ```app/models/user.js import DS from 'ember-data'; export default DS.Model.extend({ - username: attr('string'), - email: attr('string') + username: DS.attr('string'), + email: DS.attr('string') }); ``` And you attempted to save a record that did not validate on the backend: ```javascript - var user = store.createRecord('user', { + let user = store.createRecord('user', { username: 'tomster', email: 'invalidEmail' }); user.save(); ``` @@ -1762,11 +1690,11 @@ }), /** Returns errors for a given attribute ```javascript - var user = store.createRecord('user', { + let user = store.createRecord('user', { username: 'tomster', email: 'invalidEmail' }); user.save().catch(function(){ user.get('errors').errorsFor('email'); // returns: @@ -2029,11 +1957,11 @@ has: function (attribute) { return !isEmpty(this.errorsFor(attribute)); } }); }); -define("ember-data/-private/system/model/internal-model", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/system/model/states", "ember-data/-private/system/relationships/state/create", "ember-data/-private/system/snapshot", "ember-data/-private/system/empty-object", "ember-data/-private/features", "ember-data/-private/utils", "ember-data/-private/system/references"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateSystemModelStates, _emberDataPrivateSystemRelationshipsStateCreate, _emberDataPrivateSystemSnapshot, _emberDataPrivateSystemEmptyObject, _emberDataPrivateFeatures, _emberDataPrivateUtils, _emberDataPrivateSystemReferences) { +define("ember-data/-private/system/model/internal-model", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/system/model/states", "ember-data/-private/system/relationships/state/create", "ember-data/-private/system/snapshot", "ember-data/-private/system/empty-object", "ember-data/-private/features", "ember-data/-private/system/ordered-set", "ember-data/-private/utils", "ember-data/-private/system/references"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateSystemModelStates, _emberDataPrivateSystemRelationshipsStateCreate, _emberDataPrivateSystemSnapshot, _emberDataPrivateSystemEmptyObject, _emberDataPrivateFeatures, _emberDataPrivateSystemOrderedSet, _emberDataPrivateUtils, _emberDataPrivateSystemReferences) { 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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var get = _ember.default.get; @@ -2041,11 +1969,10 @@ var copy = _ember.default.copy; var EmberError = _ember.default.Error; var inspect = _ember.default.inspect; var isEmpty = _ember.default.isEmpty; var isEqual = _ember.default.isEqual; - var emberRun = _ember.default.run; var setOwner = _ember.default.setOwner; var RSVP = _ember.default.RSVP; var Promise = _ember.default.RSVP.Promise; var assign = _ember.default.assign || _ember.default.merge; @@ -2071,14 +1998,25 @@ function extractPivotName(name) { return _extractPivotNameCache[name] || (_extractPivotNameCache[name] = splitOnDot(name)[0]); } + function areAllModelsUnloaded(internalModels) { + for (var i = 0; i < internalModels.length; ++i) { + var record = internalModels[i].record; + if (record && !(record.get('isDestroyed') || record.get('isDestroying'))) { + return false; + } + } + return true; + } + // this (and all heimdall instrumentation) will be stripped by a babel transform // https://github.com/heimdalljs/babel5-plugin-strip-heimdall var InternalModelReferenceId = 1; + var nextBfsId = 1; /* `InternalModel` is the Model class that we use internally inside Ember Data to represent models. Internal ED methods should only deal with `InternalModel` objects. It is a fast, plain Javascript class. @@ -2096,36 +2034,44 @@ */ var InternalModel = (function () { function InternalModel(modelName, id, store, data) { this.id = id; - - // this ensure ordered set can quickly identify this as unique - this[_ember.default.GUID_KEY] = InternalModelReferenceId++ + 'internal-model'; - + this._internalId = InternalModelReferenceId++; this.store = store; - this._data = data || new _emberDataPrivateSystemEmptyObject.default(); this.modelName = modelName; - this.dataHasInitialized = false; this._loadingPromise = null; - this._recordArrays = undefined; this._record = null; - this.currentState = _emberDataPrivateSystemModelStates.default.empty; - this.isReloading = false; this._isDestroyed = false; this.isError = false; - this.error = null; + this._isUpdatingRecordArrays = false; + // During dematerialization we don't want to rematerialize the record. The + // reason this might happen is that dematerialization removes records from + // record arrays, and Ember arrays will always `objectAt(0)` and + // `objectAt(len - 1)` to test whether or not `firstObject` or `lastObject` + // have changed. + this._isDematerializing = false; + + this.resetRecord(); + + if (data) { + this.__data = data; + } + // caches for lazy getters this._modelClass = null; this.__deferredTriggers = null; + this.__recordArrays = null; this._references = null; this._recordReference = null; - this.__inFlightAttributes = null; this.__relationships = null; - this.__attributes = null; this.__implicitRelationships = null; + + // Used during the mark phase of unloading to avoid checking the same internal + // model twice in the same scan + this._bfsId = 0; } _createClass(InternalModel, [{ key: "isEmpty", value: function isEmpty() { @@ -2172,11 +2118,11 @@ return this.currentState.dirtyType; } }, { key: "getRecord", value: function getRecord() { - if (!this._record) { + if (!this._record && !this._isDematerializing) { // lookupFactory should really return an object that creates // instances with the injections applied var createOptions = { store: this.store, @@ -2200,15 +2146,33 @@ } return this._record; } }, { - key: "recordObjectWillDestroy", - value: function recordObjectWillDestroy() { + key: "resetRecord", + value: function resetRecord() { this._record = null; + this.dataHasInitialized = false; + this.isReloading = false; + this.error = null; + this.currentState = _emberDataPrivateSystemModelStates.default.empty; + this.__attributes = null; + this.__inFlightAttributes = null; + this._data = null; } }, { + key: "dematerializeRecord", + value: function dematerializeRecord() { + if (this.record) { + this._isDematerializing = true; + this.record.destroy(); + this.destroyRelationships(); + this.updateRecordArrays(); + this.resetRecord(); + } + } + }, { key: "deleteRecord", value: function deleteRecord() { this.send('deleteRecord'); } }, { @@ -2254,21 +2218,120 @@ }, "DS: Model#reload complete, update flags").finally(function () { internalModel.finishedReloading(); internalModel.updateRecordArrays(); }); } + + /** + Computes the set of internal models reachable from `this` across exactly one + relationship. + @return {Array} An array containing the internal models that `this` belongs + to or has many. + */ }, { + key: "_directlyRelatedInternalModels", + value: function _directlyRelatedInternalModels() { + var _this = this; + + var array = []; + this.type.eachRelationship(function (key, relationship) { + if (_this._relationships.has(key)) { + var _relationship = _this._relationships.get(key); + var localRelationships = _relationship.members.toArray(); + var serverRelationships = _relationship.canonicalMembers.toArray(); + + array = array.concat(localRelationships, serverRelationships); + } + }); + return array; + } + + /** + Computes the set of internal models reachable from this internal model. + Reachability is determined over the relationship graph (ie a graph where + nodes are internal models and edges are belongs to or has many + relationships). + @return {Array} An array including `this` and all internal models reachable + from `this`. + */ + }, { + key: "_allRelatedInternalModels", + value: function _allRelatedInternalModels() { + var array = []; + var queue = []; + var bfsId = nextBfsId++; + queue.push(this); + this._bfsId = bfsId; + while (queue.length > 0) { + var node = queue.shift(); + array.push(node); + var related = node._directlyRelatedInternalModels(); + for (var i = 0; i < related.length; ++i) { + var internalModel = related[i]; + + if (internalModel._bfsId < bfsId) { + queue.push(internalModel); + internalModel._bfsId = bfsId; + } + } + } + return array; + } + + /** + Unload the record for this internal model. This will cause the record to be + destroyed and freed up for garbage collection. It will also do a check + for cleaning up internal models. + This check is performed by first computing the set of related internal + models. If all records in this set are unloaded, then the entire set is + destroyed. Otherwise, nothing in the set is destroyed. + This means that this internal model will be freed up for garbage collection + once all models that refer to it via some relationship are also unloaded. + */ + }, { key: "unloadRecord", value: function unloadRecord() { this.send('unloadRecord'); + this.dematerializeRecord(); + _ember.default.run.schedule('destroy', this, '_checkForOrphanedInternalModels'); } }, { + key: "_checkForOrphanedInternalModels", + value: function _checkForOrphanedInternalModels() { + this._isDematerializing = false; + if (this.isDestroyed) { + return; + } + + this._cleanupOrphanedInternalModels(); + } + }, { + key: "_cleanupOrphanedInternalModels", + value: function _cleanupOrphanedInternalModels() { + var relatedInternalModels = this._allRelatedInternalModels(); + if (areAllModelsUnloaded(relatedInternalModels)) { + for (var i = 0; i < relatedInternalModels.length; ++i) { + var internalModel = relatedInternalModels[i]; + if (!internalModel.isDestroyed) { + internalModel.destroy(); + } + } + } + } + }, { key: "eachRelationship", value: function eachRelationship(callback, binding) { return this.modelClass.eachRelationship(callback, binding); } }, { + key: "destroy", + value: function destroy() { + + this.store._removeFromIdMap(this); + this._isDestroyed = true; + } + }, { key: "eachAttribute", value: function eachAttribute(callback, binding) { return this.modelClass.eachAttribute(callback, binding); } }, { @@ -2277,46 +2340,44 @@ return this.modelClass.inverseFor(key); } }, { key: "setupData", value: function setupData(data) { - var changedKeys = this._changedKeys(data.attributes); + var changedKeys = undefined; + + if (this.hasRecord) { + changedKeys = this._changedKeys(data.attributes); + } + assign(this._data, data.attributes); this.pushedData(); + if (this.hasRecord) { this.record._notifyProperties(changedKeys); } this.didInitializeData(); } }, { key: "becameReady", value: function becameReady() { - emberRun.schedule('actions', this.store.recordArrayManager, this.store.recordArrayManager.recordWasLoaded, this); + this.store.recordArrayManager.recordWasLoaded(this); } }, { key: "didInitializeData", value: function didInitializeData() { if (!this.dataHasInitialized) { this.becameReady(); this.dataHasInitialized = true; } } }, { - key: "destroy", - value: function destroy() { - this._isDestroyed = true; - if (this.hasRecord) { - return this.record.destroy(); - } - } + key: "createSnapshot", /* @method createSnapshot @private */ - }, { - key: "createSnapshot", value: function createSnapshot(options) { return new _emberDataPrivateSystemSnapshot.default(this, options); } /* @@ -2439,11 +2500,11 @@ */ }, { key: "adapterDidDirty", value: function adapterDidDirty() { this.send('becomeDirty'); - this.updateRecordArraysLater(); + this.updateRecordArrays(); } /* @method send @private @@ -2585,11 +2646,11 @@ for (i = 0, l = setups.length; i < l; i++) { setups[i].setup(this); } - this.updateRecordArraysLater(); + this.updateRecordArrays(); } }, { key: "_unhandledEvent", value: function _unhandledEvent(state, name, context) { var errorMessage = "Attempted to handle event `" + name + "` "; @@ -2610,11 +2671,12 @@ } if (this._deferredTriggers.push(args) !== 1) { return; } - emberRun.schedule('actions', this, this._triggerDeferredTriggers); + + this.store._updateInternalModel(this); } }, { key: "_triggerDeferredTriggers", value: function _triggerDeferredTriggers() { //TODO: Before 1.0 we want to remove all the events that happen on the pre materialized record, @@ -2635,25 +2697,40 @@ @private */ }, { key: "clearRelationships", value: function clearRelationships() { - var _this = this; + var _this2 = this; this.eachRelationship(function (name, relationship) { - if (_this._relationships.has(name)) { - var rel = _this._relationships.get(name); + if (_this2._relationships.has(name)) { + var rel = _this2._relationships.get(name); rel.clear(); rel.destroy(); } }); Object.keys(this._implicitRelationships).forEach(function (key) { - _this._implicitRelationships[key].clear(); - _this._implicitRelationships[key].destroy(); + _this2._implicitRelationships[key].clear(); + _this2._implicitRelationships[key].destroy(); }); } + }, { + key: "destroyRelationships", + value: function destroyRelationships() { + var _this3 = this; + this.eachRelationship(function (name, relationship) { + if (_this3._relationships.has(name)) { + var rel = _this3._relationships.get(name); + rel.destroy(); + } + }); + Object.keys(this._implicitRelationships).forEach(function (key) { + _this3._implicitRelationships[key].destroy(); + }); + } + /* When a find request is triggered on the store, the user can optionally pass in attributes and relationships to be preloaded. These are meant to behave as if they came back from the server, except the user obtained them out of band and is informing the store of their existence. The most common use case is for supporting client side @@ -2666,20 +2743,20 @@ @param {Object} preload */ }, { key: "preloadData", value: function preloadData(preload) { - var _this2 = this; + var _this4 = this; //TODO(Igor) consider the polymorphic case Object.keys(preload).forEach(function (key) { var preloadValue = get(preload, key); - var relationshipMeta = _this2.modelClass.metaForProperty(key); + var relationshipMeta = _this4.modelClass.metaForProperty(key); if (relationshipMeta.isRelationship) { - _this2._preloadRelationship(key, preloadValue); + _this4._preloadRelationship(key, preloadValue); } else { - _this2._data[key] = preloadValue; + _this4._data[key] = preloadValue; } }); } }, { key: "_preloadRelationship", @@ -2732,12 +2809,15 @@ @private */ }, { key: "updateRecordArrays", value: function updateRecordArrays() { - this._updatingRecordArraysLater = false; - this.store._dataWasUpdated(this); + if (this._isUpdatingRecordArrays) { + return; + } + this._isUpdatingRecordArrays = true; + this.store.recordArrayManager.recordDidChange(this); } }, { key: "setId", value: function setId(id) { this.id = id; @@ -2794,34 +2874,19 @@ } this._inFlightAttributes = new _emberDataPrivateSystemEmptyObject.default(); this.send('didCommit'); - this.updateRecordArraysLater(); + this.updateRecordArrays(); if (!data) { return; } this.record._notifyProperties(changedKeys); } - - /* - @method updateRecordArraysLater - @private - */ }, { - key: "updateRecordArraysLater", - value: function updateRecordArraysLater() { - // quick hack (something like this could be pushed into run.once - if (this._updatingRecordArraysLater) { - return; - } - this._updatingRecordArraysLater = true; - emberRun.schedule('actions', this, this.updateRecordArrays); - } - }, { key: "addErrorMessageToAttribute", value: function addErrorMessageToAttribute(attribute, message) { get(this.getRecord(), 'errors')._add(attribute, message); } }, { @@ -2998,10 +3063,18 @@ this._recordReference = new _emberDataPrivateSystemReferences.RecordReference(this.store, this); } return this._recordReference; } }, { + key: "_recordArrays", + get: function () { + if (this.__recordArrays === null) { + this.__recordArrays = _emberDataPrivateSystemOrderedSet.default.create(); + } + return this.__recordArrays; + } + }, { key: "references", get: function () { if (this._references === null) { this._references = new _emberDataPrivateSystemEmptyObject.default(); } @@ -3044,10 +3117,21 @@ return this.__inFlightAttributes; }, set: function (v) { this.__inFlightAttributes = v; } + }, { + key: "_data", + get: function () { + if (this.__data === null) { + this.__data = new _emberDataPrivateSystemEmptyObject.default(); + } + return this.__data; + }, + set: function (v) { + this.__data = v; + } /* implicit relationships are relationship which have not been declared but the inverse side exists on another record somewhere For example if there was @@ -3096,11 +3180,11 @@ return InternalModel; })(); exports.default = InternalModel; - if (false) { + if ((0, _emberDataPrivateFeatures.default)('ds-rollback-attribute')) { /* Returns the latest truth for an attribute - the canonical value, or the in-flight value. @method lastAcknowledgedValue @private @@ -3639,12 +3723,12 @@ this.deleteRecord(); return this.save(options); }, /** - @method unloadRecord - @private + Unloads the record from the store. This will cause the record to be destroyed and freed up for garbage collection. + @method unloadRecord */ unloadRecord: function () { if (this.isDestroyed) { return; } @@ -3673,12 +3757,12 @@ empty since the adapter hasn't acknowledged the attributes yet: Example ```app/models/mascot.js import DS from 'ember-data'; export default DS.Model.extend({ - name: attr('string'), - isAdmin: attr('boolean', { + name: DS.attr('string'), + isAdmin: DS.attr('boolean', { defaultValue: false }) }); ``` ```javascript @@ -3840,18 +3924,10 @@ _ember.default.tryInvoke(this, name, args); this._super.apply(this, arguments); }, - willDestroy: function () { - //TODO Move! - this._super.apply(this, arguments); - this._internalModel.clearRelationships(); - this._internalModel.recordObjectWillDestroy(); - //TODO should we set internalModel to null here? - }, - // This is a temporary solution until we refactor DS.Model to not // rely on the data property. willMergeMixin: function (props) { var constructor = this.constructor; }, @@ -4153,12 +4229,12 @@ @method create @private @static */ /** - Represents the model's class name as a string. This can be used to look up the model through - DS.Store's modelFor method. + Represents the model's class name as a string. This can be used to look up the model's class name through + `DS.Store`'s modelFor method. `modelName` is generated for you by Ember Data. It will be a lowercased, dasherized string. For example: ```javascript store.modelFor('post').modelName; // 'post' store.modelFor('blog-post').modelName; // 'blog-post' @@ -4231,12 +4307,14 @@ import DS from 'ember-data'; export default DS.Model.extend({ owner: DS.belongsTo('post') }); ``` - store.modelFor('post').inverseFor('comments', store) -> { type: App.Message, name: 'owner', kind: 'belongsTo' } - store.modelFor('message').inverseFor('owner', store) -> { type: App.Post, name: 'comments', kind: 'hasMany' } + ``` js + store.modelFor('post').inverseFor('comments', store) // { type: App.Message, name: 'owner', kind: 'belongsTo' } + store.modelFor('message').inverseFor('owner', store) // { type: App.Post, name: 'comments', kind: 'hasMany' } + ``` @method inverseFor @static @param {String} name the name of the relationship @param {DS.Store} store @return {Object} the inverse relationship, or null @@ -4549,13 +4627,13 @@ property. Example ```app/models/person.js import DS from 'ember-data'; export default DS.Model.extend({ - firstName: attr('string'), - lastName: attr('string'), - birthday: attr('date') + firstName: DS.attr('string'), + lastName: DS.attr('string'), + birthday: DS.attr('date') }); ``` ```javascript import Ember from 'ember'; import Person from 'app/models/person'; @@ -4594,13 +4672,13 @@ attributes that do not have an transformation type. Example ```app/models/person.js import DS from 'ember-data'; export default DS.Model.extend({ - firstName: attr(), - lastName: attr('string'), - birthday: attr('date') + firstName: DS.attr(), + lastName: DS.attr('string'), + birthday: DS.attr('date') }); ``` ```javascript import Ember from 'ember'; import Person from 'app/models/person'; @@ -4643,13 +4721,13 @@ object that will be set as `this` on the context. Example ```javascript import DS from 'ember-data'; let Person = DS.Model.extend({ - firstName: attr('string'), - lastName: attr('string'), - birthday: attr('date') + firstName: DS.attr('string'), + lastName: DS.attr('string'), + birthday: DS.attr('date') }); Person.eachAttribute(function(name, meta) { console.log(name, meta); }); // prints: @@ -4684,13 +4762,13 @@ object that will be set as `this` on the context. Example ```javascript import DS from 'ember-data'; let Person = DS.Model.extend({ - firstName: attr(), - lastName: attr('string'), - birthday: attr('date') + firstName: DS.attr(), + lastName: DS.attr('string'), + birthday: DS.attr('date') }); Person.eachTransformedAttribute(function(name, type) { console.log(name, type); }); // prints: @@ -4723,11 +4801,11 @@ return this.store.container; } }); } - if (false) { + if ((0, _emberDataPrivateFeatures.default)('ds-rollback-attribute')) { Model.reopen({ /** Discards any unsaved changes to the given attribute. This feature is not enabled by default. You must enable `ds-rollback-attribute` and be running a canary build. Example ```javascript @@ -4926,11 +5004,11 @@ internalModel.send('propertyWasReset', context.name); } else if (context.value !== context.oldValue) { internalModel.send('becomeDirty'); } - internalModel.updateRecordArraysLater(); + internalModel.updateRecordArrays(); } // Implementation notes: // // Each state has a boolean value for all of the following flags: @@ -5202,16 +5280,11 @@ // Trying to roll back if you're not in the dirty state // doesn't change your state. For example, if you're in the // in-flight state, rolling back the record doesn't move // you out of the in-flight state. rolledBack: function () {}, - unloadRecord: function (internalModel) { - // clear relationships before moving to deleted state - // otherwise it fails - internalModel.clearRelationships(); - internalModel.transitionTo('deleted.saved'); - }, + unloadRecord: function (internalModel) {}, propertyWasReset: function () {}, // SUBSTATES @@ -5316,16 +5389,11 @@ deleteRecord: function (internalModel) { internalModel.transitionTo('deleted.uncommitted'); }, - unloadRecord: function (internalModel) { - // clear relationships before moving to deleted state - // otherwise it fails - internalModel.clearRelationships(); - internalModel.transitionTo('deleted.saved'); - }, + unloadRecord: function (internalModel) {}, didCommit: function () {}, // loaded.saved.notFound would be triggered by a failed // `reload()` on an unchanged record @@ -5424,12 +5492,10 @@ // FLAGS isDirty: false, setup: function (internalModel) { internalModel.clearRelationships(); - var store = internalModel.store; - store._dematerializeRecord(internalModel); }, invokeLifecycleCallbacks: function (internalModel) { internalModel.triggerLater('didDelete', internalModel); internalModel.triggerLater('didCommit', internalModel); @@ -5610,11 +5676,11 @@ documentation](/api/classes/Ember.PromiseProxyMixin.html). Example ```javascript - var promiseArray = DS.PromiseArray.create({ + let promiseArray = DS.PromiseArray.create({ promise: $.getJSON('/some/remote/data.json') }); promiseArray.get('length'); // 0 @@ -5642,11 +5708,11 @@ documentation](/api/classes/Ember.PromiseProxyMixin.html). Example ```javascript - var promiseObject = DS.PromiseObject.create({ + let promiseObject = DS.PromiseObject.create({ promise: $.getJSON('/some/remote/data.json') }); promiseObject.get('name'); // null @@ -5702,15 +5768,12 @@ }; } var PromiseManyArray = PromiseArray.extend({ reload: function () { - return PromiseManyArray.create({ - promise: get(this, 'content').reload() - }); - - //I don't think this should ever happen right now, but worth guarding if we refactor the async relationships + this.set('promise', this.get('content').reload()); + return this; }, createRecord: proxyToContent('createRecord'), on: proxyToContent('on'), @@ -5730,25 +5793,32 @@ return PromiseManyArray.create({ promise: Promise.resolve(promise, label) }); } }); -define("ember-data/-private/system/record-array-manager", ["exports", "ember", "ember-data/-private/system/record-arrays", "ember-data/-private/system/ordered-set", "ember-data/-private/debug"], function (exports, _ember, _emberDataPrivateSystemRecordArrays, _emberDataPrivateSystemOrderedSet, _emberDataPrivateDebug) { +define('ember-data/-private/system/record-array-manager', ['exports', 'ember', 'ember-data/-private/system/record-arrays', 'ember-data/-private/debug'], function (exports, _ember, _emberDataPrivateSystemRecordArrays, _emberDataPrivateDebug) { + 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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + var get = _ember.default.get; var MapWithDefault = _ember.default.MapWithDefault; var emberRun = _ember.default.run; /** @class RecordArrayManager @namespace DS @private - @extends Ember.Object */ - exports.default = _ember.default.Object.extend({ - init: function () { + + var RecordArrayManager = (function () { + function RecordArrayManager(options) { var _this = this; + this.store = options.store; + this.isDestroying = false; + this.isDestroyed = false; this.filteredRecordArrays = MapWithDefault.create({ defaultValue: function () { return []; } }); @@ -5758,305 +5828,368 @@ return _this.createRecordArray(modelName); } }); this.changedRecords = []; + this.loadedRecords = []; this._adapterPopulatedRecordArrays = []; - }, + } - recordDidChange: function (record) { - if (this.changedRecords.push(record) !== 1) { - return; + _createClass(RecordArrayManager, [{ + key: 'recordDidChange', + value: function recordDidChange(internalModel) { + if (this.changedRecords.push(internalModel) !== 1) { + return; + } + + emberRun.schedule('actions', this, this.updateRecordArrays); } + }, { + key: 'recordArraysForRecord', + value: function recordArraysForRecord(internalModel) { - emberRun.schedule('actions', this, this.updateRecordArrays); - }, + return internalModel._recordArrays; + } - recordArraysForRecord: function (internalModel) { - internalModel._recordArrays = internalModel._recordArrays || _emberDataPrivateSystemOrderedSet.default.create(); - return internalModel._recordArrays; - }, + /** + This method is invoked whenever data is loaded into the store by the + adapter or updated by the adapter, or when a record has changed. + It updates all record arrays that a record belongs to. + To avoid thrashing, it only runs at most once per run loop. + @method updateRecordArrays + */ + }, { + key: 'updateRecordArrays', + value: function updateRecordArrays() { + var updated = this.changedRecords; - /** - This method is invoked whenever data is loaded into the store by the - adapter or updated by the adapter, or when a record has changed. - It updates all record arrays that a record belongs to. - To avoid thrashing, it only runs at most once per run loop. - @method updateRecordArrays - */ - updateRecordArrays: function () { - var _this2 = this; + for (var i = 0, l = updated.length; i < l; i++) { + var internalModel = updated[i]; - this.changedRecords.forEach(function (internalModel) { + // During dematerialization we don't want to rematerialize the record. + // recordWasDeleted can cause other records to rematerialize because it + // removes the internal model from the array and Ember arrays will always + // `objectAt(0)` and `objectAt(len -1)` to check whether `firstObject` or + // `lastObject` have changed. When this happens we don't want those + // models to rematerialize their records. + if (internalModel._isDematerializing || internalModel.isDestroyed || internalModel.currentState.stateName === 'root.deleted.saved') { + this._recordWasDeleted(internalModel); + } else { + this._recordWasChanged(internalModel); + } - if (internalModel.isDestroyed || internalModel.currentState.stateName === 'root.deleted.saved') { - _this2._recordWasDeleted(internalModel); - } else { - _this2._recordWasChanged(internalModel); + internalModel._isUpdatingRecordArrays = false; } - }); - this.changedRecords.length = 0; - }, + updated.length = 0; + } + }, { + key: '_recordWasDeleted', + value: function _recordWasDeleted(internalModel) { + var recordArrays = internalModel.__recordArrays; - _recordWasDeleted: function (internalModel) { - var recordArrays = internalModel._recordArrays; + if (!recordArrays) { + return; + } - if (!recordArrays) { - return; + recordArrays.forEach(function (array) { + return array._removeInternalModels([internalModel]); + }); + + internalModel.__recordArrays = null; } + }, { + key: '_recordWasChanged', + value: function _recordWasChanged(internalModel) { + var _this2 = this; - recordArrays.forEach(function (array) { - return array._removeInternalModels([internalModel]); - }); + var modelName = internalModel.modelName; + var recordArrays = this.filteredRecordArrays.get(modelName); + var filter = undefined; + recordArrays.forEach(function (array) { + filter = get(array, 'filterFunction'); + _this2.updateFilterRecordArray(array, filter, modelName, internalModel); + }); + } - internalModel._recordArrays = null; - }, + //Need to update live arrays on loading + }, { + key: 'recordWasLoaded', + value: function recordWasLoaded(internalModel) { + if (this.loadedRecords.push(internalModel) !== 1) { + return; + } - _recordWasChanged: function (internalModel) { - var _this3 = this; + emberRun.schedule('actions', this, this._flushLoadedRecords); + } + }, { + key: '_flushLoadedRecords', + value: function _flushLoadedRecords() { + var internalModels = this.loadedRecords; - var modelName = internalModel.modelName; - var recordArrays = this.filteredRecordArrays.get(modelName); - var filter = undefined; - recordArrays.forEach(function (array) { - filter = get(array, 'filterFunction'); - _this3.updateFilterRecordArray(array, filter, modelName, internalModel); - }); - }, + for (var i = 0, l = internalModels.length; i < l; i++) { + var internalModel = internalModels[i]; + var modelName = internalModel.modelName; - //Need to update live arrays on loading - recordWasLoaded: function (internalModel) { - var _this4 = this; + var recordArrays = this.filteredRecordArrays.get(modelName); + var filter = undefined; - var modelName = internalModel.modelName; - var recordArrays = this.filteredRecordArrays.get(modelName); - var filter = undefined; + for (var j = 0, rL = recordArrays.length; j < rL; j++) { + var array = recordArrays[j]; + filter = get(array, 'filterFunction'); + this.updateFilterRecordArray(array, filter, modelName, internalModel); + } - recordArrays.forEach(function (array) { - filter = get(array, 'filterFunction'); - _this4.updateFilterRecordArray(array, filter, modelName, internalModel); - }); + if (this.liveRecordArrays.has(modelName)) { + var liveRecordArray = this.liveRecordArrays.get(modelName); + this._addInternalModelToRecordArray(liveRecordArray, internalModel); + } + } - if (this.liveRecordArrays.has(modelName)) { - var liveRecordArray = this.liveRecordArrays.get(modelName); - this._addInternalModelToRecordArray(liveRecordArray, internalModel); + this.loadedRecords.length = 0; } - }, - /** - Update an individual filter. - @method updateFilterRecordArray - @param {DS.FilteredRecordArray} array - @param {Function} filter - @param {String} modelName - @param {InternalModel} internalModel - */ - updateFilterRecordArray: function (array, filter, modelName, internalModel) { - var shouldBeInArray = filter(internalModel.getRecord()); - var recordArrays = this.recordArraysForRecord(internalModel); - if (shouldBeInArray) { - this._addInternalModelToRecordArray(array, internalModel); - } else { - recordArrays.delete(array); - array._removeInternalModels([internalModel]); + /** + Update an individual filter. + @method updateFilterRecordArray + @param {DS.FilteredRecordArray} array + @param {Function} filter + @param {String} modelName + @param {InternalModel} internalModel + */ + }, { + key: 'updateFilterRecordArray', + value: function updateFilterRecordArray(array, filter, modelName, internalModel) { + var shouldBeInArray = filter(internalModel.getRecord()); + var recordArrays = this.recordArraysForRecord(internalModel); + if (shouldBeInArray) { + this._addInternalModelToRecordArray(array, internalModel); + } else { + recordArrays.delete(array); + array._removeInternalModels([internalModel]); + } } - }, - - _addInternalModelToRecordArray: function (array, internalModel) { - var recordArrays = this.recordArraysForRecord(internalModel); - if (!recordArrays.has(array)) { - array._pushInternalModels([internalModel]); - recordArrays.add(array); + }, { + key: '_addInternalModelToRecordArray', + value: function _addInternalModelToRecordArray(array, internalModel) { + var recordArrays = this.recordArraysForRecord(internalModel); + if (!recordArrays.has(array)) { + array._pushInternalModels([internalModel]); + recordArrays.add(array); + } } - }, + }, { + key: 'syncLiveRecordArray', + value: function syncLiveRecordArray(array, modelName) { + var hasNoPotentialDeletions = this.changedRecords.length === 0; + var map = this.store._internalModelsFor(modelName); + var hasNoInsertionsOrRemovals = map.length === array.length; - syncLiveRecordArray: function (array, modelName) { - var hasNoPotentialDeletions = this.changedRecords.length === 0; - var recordMap = this.store._recordMapFor(modelName); - var hasNoInsertionsOrRemovals = recordMap.length === array.length; + /* + Ideally the recordArrayManager has knowledge of the changes to be applied to + liveRecordArrays, and is capable of strategically flushing those changes and applying + small diffs if desired. However, until we've refactored recordArrayManager, this dirty + check prevents us from unnecessarily wiping out live record arrays returned by peekAll. + */ + if (hasNoPotentialDeletions && hasNoInsertionsOrRemovals) { + return; + } - /* - Ideally the recordArrayManager has knowledge of the changes to be applied to - liveRecordArrays, and is capable of strategically flushing those changes and applying - small diffs if desired. However, until we've refactored recordArrayManager, this dirty - check prevents us from unnecessarily wiping out live record arrays returned by peekAll. - */ - if (hasNoPotentialDeletions && hasNoInsertionsOrRemovals) { - return; + this.populateLiveRecordArray(array, modelName); } + }, { + key: 'populateLiveRecordArray', + value: function populateLiveRecordArray(array, modelName) { + var modelMap = this.store._internalModelsFor(modelName); + var internalModels = modelMap.models; - this.populateLiveRecordArray(array, modelName); - }, + for (var i = 0; i < internalModels.length; i++) { + var internalModel = internalModels[i]; - populateLiveRecordArray: function (array, modelName) { - var recordMap = this.store._recordMapFor(modelName); - var records = recordMap.records; - var record = undefined; - - for (var i = 0; i < records.length; i++) { - record = records[i]; - - if (!record.isDeleted() && !record.isEmpty()) { - this._addInternalModelToRecordArray(array, record); + if (!internalModel.isDeleted() && !internalModel.isEmpty()) { + this._addInternalModelToRecordArray(array, internalModel); + } } } - }, - /** - This method is invoked if the `filterFunction` property is - changed on a `DS.FilteredRecordArray`. - It essentially re-runs the filter from scratch. This same - method is invoked when the filter is created in th first place. - @method updateFilter - @param {Array} array - @param {String} modelName - @param {Function} filter - */ - updateFilter: function (array, modelName, filter) { - var recordMap = this.store._recordMapFor(modelName); - var records = recordMap.records; - var record = undefined; + /** + This method is invoked if the `filterFunction` property is + changed on a `DS.FilteredRecordArray`. + It essentially re-runs the filter from scratch. This same + method is invoked when the filter is created in th first place. + @method updateFilter + @param {Array} array + @param {String} modelName + @param {Function} filter + */ + }, { + key: 'updateFilter', + value: function updateFilter(array, modelName, filter) { + var modelMap = this.store._internalModelsFor(modelName); + var internalModels = modelMap.models; - for (var i = 0; i < records.length; i++) { - record = records[i]; + for (var i = 0; i < internalModels.length; i++) { + var internalModel = internalModels[i]; - if (!record.isDeleted() && !record.isEmpty()) { - this.updateFilterRecordArray(array, filter, modelName, record); + if (!internalModel.isDeleted() && !internalModel.isEmpty()) { + this.updateFilterRecordArray(array, filter, modelName, internalModel); + } } } - }, - /** - Get the `DS.RecordArray` for a modelName, which contains all loaded records of - given modelName. - @method liveRecordArrayFor - @param {String} modelName - @return {DS.RecordArray} - */ - liveRecordArrayFor: function (modelName) { - return this.liveRecordArrays.get(modelName); - }, + /** + Get the `DS.RecordArray` for a modelName, which contains all loaded records of + given modelName. + @method liveRecordArrayFor + @param {String} modelName + @return {DS.RecordArray} + */ + }, { + key: 'liveRecordArrayFor', + value: function liveRecordArrayFor(modelName) { + return this.liveRecordArrays.get(modelName); + } - /** - Create a `DS.RecordArray` for a modelName. - @method createRecordArray - @param {String} modelName - @return {DS.RecordArray} - */ - createRecordArray: function (modelName) { - return _emberDataPrivateSystemRecordArrays.RecordArray.create({ - modelName: modelName, - content: _ember.default.A(), - store: this.store, - isLoaded: true, - manager: this - }); - }, + /** + Create a `DS.RecordArray` for a modelName. + @method createRecordArray + @param {String} modelName + @return {DS.RecordArray} + */ + }, { + key: 'createRecordArray', + value: function createRecordArray(modelName) { + return _emberDataPrivateSystemRecordArrays.RecordArray.create({ + modelName: modelName, + content: _ember.default.A(), + store: this.store, + isLoaded: true, + manager: this + }); + } - /** - Create a `DS.FilteredRecordArray` for a modelName and register it for updates. - @method createFilteredRecordArray - @param {String} modelName - @param {Function} filter - @param {Object} query (optional - @return {DS.FilteredRecordArray} - */ - createFilteredRecordArray: function (modelName, filter, query) { - var array = _emberDataPrivateSystemRecordArrays.FilteredRecordArray.create({ - query: query, - modelName: modelName, - content: _ember.default.A(), - store: this.store, - manager: this, - filterFunction: filter - }); + /** + Create a `DS.FilteredRecordArray` for a modelName and register it for updates. + @method createFilteredRecordArray + @param {String} modelName + @param {Function} filter + @param {Object} query (optional + @return {DS.FilteredRecordArray} + */ + }, { + key: 'createFilteredRecordArray', + value: function createFilteredRecordArray(modelName, filter, query) { + var array = _emberDataPrivateSystemRecordArrays.FilteredRecordArray.create({ + query: query, + modelName: modelName, + content: _ember.default.A(), + store: this.store, + manager: this, + filterFunction: filter + }); - this.registerFilteredRecordArray(array, modelName, filter); + this.registerFilteredRecordArray(array, modelName, filter); - return array; - }, + return array; + } - /** - Create a `DS.AdapterPopulatedRecordArray` for a modelName with given query. - @method createAdapterPopulatedRecordArray - @param {String} modelName - @param {Object} query - @return {DS.AdapterPopulatedRecordArray} - */ - createAdapterPopulatedRecordArray: function (modelName, query) { + /** + Create a `DS.AdapterPopulatedRecordArray` for a modelName with given query. + @method createAdapterPopulatedRecordArray + @param {String} modelName + @param {Object} query + @return {DS.AdapterPopulatedRecordArray} + */ + }, { + key: 'createAdapterPopulatedRecordArray', + value: function createAdapterPopulatedRecordArray(modelName, query) { - var array = _emberDataPrivateSystemRecordArrays.AdapterPopulatedRecordArray.create({ - modelName: modelName, - query: query, - content: _ember.default.A(), - store: this.store, - manager: this - }); + var array = _emberDataPrivateSystemRecordArrays.AdapterPopulatedRecordArray.create({ + modelName: modelName, + query: query, + content: _ember.default.A(), + store: this.store, + manager: this + }); - this._adapterPopulatedRecordArrays.push(array); + this._adapterPopulatedRecordArrays.push(array); - return array; - }, + return array; + } - /** - Register a RecordArray for a given modelName to be backed by - a filter function. This will cause the array to update - automatically when records of that modelName change attribute - values or states. - @method registerFilteredRecordArray - @param {DS.RecordArray} array - @param {String} modelName - @param {Function} filter - */ - registerFilteredRecordArray: function (array, modelName, filter) { + /** + Register a RecordArray for a given modelName to be backed by + a filter function. This will cause the array to update + automatically when records of that modelName change attribute + values or states. + @method registerFilteredRecordArray + @param {DS.RecordArray} array + @param {String} modelName + @param {Function} filter + */ + }, { + key: 'registerFilteredRecordArray', + value: function registerFilteredRecordArray(array, modelName, filter) { - var recordArrays = this.filteredRecordArrays.get(modelName); - recordArrays.push(array); + var recordArrays = this.filteredRecordArrays.get(modelName); + recordArrays.push(array); - this.updateFilter(array, modelName, filter); - }, + this.updateFilter(array, modelName, filter); + } - /** - Unregister a RecordArray. - So manager will not update this array. - @method unregisterRecordArray - @param {DS.RecordArray} array - */ - unregisterRecordArray: function (array) { + /** + Unregister a RecordArray. + So manager will not update this array. + @method unregisterRecordArray + @param {DS.RecordArray} array + */ + }, { + key: 'unregisterRecordArray', + value: function unregisterRecordArray(array) { - var modelName = array.modelName; + var modelName = array.modelName; - // unregister filtered record array - var recordArrays = this.filteredRecordArrays.get(modelName); - var removedFromFiltered = remove(recordArrays, array); + // unregister filtered record array + var recordArrays = this.filteredRecordArrays.get(modelName); + var removedFromFiltered = remove(recordArrays, array); - // remove from adapter populated record array - var removedFromAdapterPopulated = remove(this._adapterPopulatedRecordArrays, array); + // remove from adapter populated record array + var removedFromAdapterPopulated = remove(this._adapterPopulatedRecordArrays, array); - if (!removedFromFiltered && !removedFromAdapterPopulated) { + if (!removedFromFiltered && !removedFromAdapterPopulated) { - // unregister live record array - if (this.liveRecordArrays.has(modelName)) { - var liveRecordArrayForType = this.liveRecordArrayFor(modelName); - if (array === liveRecordArrayForType) { - this.liveRecordArrays.delete(modelName); + // unregister live record array + if (this.liveRecordArrays.has(modelName)) { + var liveRecordArrayForType = this.liveRecordArrayFor(modelName); + if (array === liveRecordArrayForType) { + this.liveRecordArrays.delete(modelName); + } } } } - }, + }, { + key: 'willDestroy', + value: function willDestroy() { + this.filteredRecordArrays.forEach(function (value) { + return flatten(value).forEach(destroy); + }); + this.liveRecordArrays.forEach(destroy); + this._adapterPopulatedRecordArrays.forEach(destroy); + this.isDestroyed = true; + } + }, { + key: 'destroy', + value: function destroy() { + this.isDestroying = true; + _ember.default.run.schedule('actions', this, this.willDestroy); + } + }]); - willDestroy: function () { - this._super.apply(this, arguments); + return RecordArrayManager; + })(); - this.filteredRecordArrays.forEach(function (value) { - return flatten(value).forEach(destroy); - }); - this.liveRecordArrays.forEach(destroy); - this._adapterPopulatedRecordArrays.forEach(destroy); - } - }); + exports.default = RecordArrayManager; function destroy(entry) { entry.destroy(); } @@ -6164,11 +6297,10 @@ @param {Array} internalModels @param {Object} payload normalized payload @private */ _setInternalModels: function (internalModels, payload) { - var _this = this; // TODO: initial load should not cause change events at all, only // subsequent. This requires changing the public api of adapter.query, but // hopefully we can do that soon. this.get('content').setObjects(internalModels); @@ -6178,13 +6310,14 @@ isUpdating: false, meta: (0, _emberDataPrivateSystemCloneNull.default)(payload.meta), links: (0, _emberDataPrivateSystemCloneNull.default)(payload.links) }); - internalModels.forEach(function (internalModel) { - return _this.manager.recordArraysForRecord(internalModel).add(_this); - }); + for (var i = 0, l = internalModels.length; i < l; i++) { + var internalModel = internalModels[i]; + this.manager.recordArraysForRecord(internalModel).add(this); + } // TODO: should triggering didLoad event be the last action of the runLoop? _ember.default.run.once(this, 'trigger', 'didLoad'); } }); @@ -6446,11 +6579,11 @@ _dissociateFromOwnRecords: function () { var _this3 = this; this.get('content').forEach(function (internalModel) { - var recordArrays = internalModel._recordArrays; + var recordArrays = internalModel.__recordArrays; if (recordArrays) { recordArrays.delete(_this3); } }); @@ -6459,11 +6592,11 @@ /** @method _unregisterFromManager @private */ _unregisterFromManager: function () { - get(this, 'manager').unregisterRecordArray(this); + this.manager.unregisterRecordArray(this); }, willDestroy: function () { this._unregisterFromManager(); this._dissociateFromOwnRecords(); @@ -6477,21 +6610,21 @@ set(this, 'content', null); set(this, 'length', 0); this._super.apply(this, arguments); }, - /** - r @method _createSnapshot + /* + @method _createSnapshot @private */ _createSnapshot: function (options) { // this is private for users, but public for ember-data internals return new _emberDataPrivateSystemSnapshotRecordArray.default(this, this.get('meta'), options); }, - /** - r @method _takeSnapshot + /* + @method _takeSnapshot @private */ _takeSnapshot: function () { return get(this, 'content').map(function (internalModel) { return internalModel.createSnapshot(); @@ -6500,162 +6633,10 @@ }); }); /** @module ember-data */ -define('ember-data/-private/system/record-map', ['exports', 'ember-data/-private/debug', 'ember-data/-private/system/model/internal-model'], function (exports, _emberDataPrivateDebug, _emberDataPrivateSystemModelInternalModel) { - 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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } - - /** - `RecordMap` is a custom storage map for records of a given modelName - used by `IdentityMap`. - - It was extracted from an implicit pojo based "record map" and preserves - that interface while we work towards a more official API. - - @class RecordMap - @private - */ - - var RecordMap = (function () { - function RecordMap(modelName) { - this.modelName = modelName; - this._idToRecord = Object.create(null); - this._records = []; - this._metadata = null; - } - - /** - A "map" of records based on their ID for this modelName - */ - - _createClass(RecordMap, [{ - key: 'get', - - /** - * - * @param id - * @returns {InternalModel} - */ - value: function get(id) { - var r = this._idToRecord[id]; - return r; - } - }, { - key: 'has', - value: function has(id) { - return !!this._idToRecord[id]; - } - }, { - key: 'set', - value: function set(id, internalModel) { - - this._idToRecord[id] = internalModel; - } - }, { - key: 'add', - value: function add(internalModel, id) { - - if (id) { - this._idToRecord[id] = internalModel; - } - - this._records.push(internalModel); - } - }, { - key: 'remove', - value: function remove(internalModel, id) { - if (id) { - delete this._idToRecord[id]; - } - - var loc = this._records.indexOf(internalModel); - - if (loc !== -1) { - this._records.splice(loc, 1); - } - } - }, { - key: 'contains', - value: function contains(internalModel) { - return this._records.indexOf(internalModel) !== -1; - } - - /** - An array of all records of this modelName - */ - }, { - key: 'clear', - - /** - Destroy all records in the recordMap and wipe metadata. - @method clear - */ - value: function clear() { - if (this._records) { - var records = this._records; - this._records = []; - var record = undefined; - - for (var i = 0; i < records.length; i++) { - record = records[i]; - record.unloadRecord(); - record.destroy(); // maybe within unloadRecord - } - } - - this._metadata = null; - } - }, { - key: 'destroy', - value: function destroy() { - this._store = null; - this._modelClass = null; - } - }, { - key: 'idToRecord', - get: function () { - return this._idToRecord; - } - }, { - key: 'length', - get: function () { - return this._records.length; - } - }, { - key: 'records', - get: function () { - return this._records; - } - - /** - * meta information about records - */ - }, { - key: 'metadata', - get: function () { - return this._metadata || (this._metadata = Object.create(null)); - } - - /** - deprecated (and unsupported) way of accessing modelClass - @deprecated - */ - }, { - key: 'type', - get: function () { - throw new Error('RecordMap.type is no longer available'); - } - }]); - - return RecordMap; - })(); - - exports.default = RecordMap; -}); define('ember-data/-private/system/references', ['exports', 'ember-data/-private/system/references/record', 'ember-data/-private/system/references/belongs-to', 'ember-data/-private/system/references/has-many'], function (exports, _emberDataPrivateSystemReferencesRecord, _emberDataPrivateSystemReferencesBelongsTo, _emberDataPrivateSystemReferencesHasMany) { exports.RecordReference = _emberDataPrivateSystemReferencesRecord.default; exports.BelongsToReference = _emberDataPrivateSystemReferencesBelongsTo.default; exports.HasManyReference = _emberDataPrivateSystemReferencesHasMany.default; }); @@ -6694,26 +6675,26 @@ // models/blog.js export default DS.Model.extend({ user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ type: 'blog', id: 1, relationships: { user: { data: { type: 'user', id: 1 } } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); // get the identifier of the reference if (userRef.remoteType() === "id") { - var id = userRef.id(); + let id = userRef.id(); } else if (userRef.remoteType() === "link") { - var link = userRef.link(); + let link = userRef.link(); } ``` @method remoteType @return {String} The name of the remote type. This should either be "link" or "id" @@ -6739,26 +6720,26 @@ // models/blog.js export default DS.Model.extend({ user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, relationships: { user: { data: { type: 'user', id: 1 } } } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); // get the identifier of the reference if (userRef.remoteType() === "id") { - var id = userRef.id(); + let id = userRef.id(); } ``` @method id @return {String} The id of the record in this belongsTo relationship. @@ -6778,11 +6759,11 @@ // models/blog.js export default DS.Model.extend({ user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, relationships: { user: { @@ -6791,15 +6772,15 @@ } } } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); // get the identifier of the reference if (userRef.remoteType() === "link") { - var link = userRef.link(); + let link = userRef.link(); } ``` @method link @return {String} The link Ember Data will use to fetch or reload this belongs-to relationship. @@ -6817,11 +6798,11 @@ // models/blog.js export default DS.Model.extend({ user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, relationships: { user: { @@ -6836,11 +6817,11 @@ } } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); userRef.meta() // { lastUpdated: 1458014400000 } ``` @method meta @@ -6861,22 +6842,22 @@ // models/blog.js export default DS.Model.extend({ user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, relationships: { user: { data: { type: 'user', id: 1 } } } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); // provide data for reference userRef.push({ data: { type: 'user', @@ -6896,14 +6877,14 @@ */ BelongsToReference.prototype.push = function (objectOrPromise) { var _this = this; return _ember.default.RSVP.resolve(objectOrPromise).then(function (data) { - var record; + var record = undefined; if (data instanceof _emberDataModel.default) { - if (false) {} + if ((0, _emberDataPrivateFeatures.default)('ds-overhaul-references')) {} record = data; } else { record = _this.store.push(data); } @@ -6926,22 +6907,22 @@ // models/blog.js export default DS.Model.extend({ user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, relationships: { user: { data: { type: 'user', id: 1 } } } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); userRef.value(); // null // provide data for reference userRef.push({ @@ -6982,22 +6963,22 @@ // models/blog.js export default DS.Model.extend({ user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, relationships: { user: { data: { type: 'user', id: 1 } } } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); userRef.value(); // null userRef.load().then(function(user) { userRef.value() === user @@ -7032,22 +7013,22 @@ // models/blog.js export default DS.Model.extend({ user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, relationships: { user: { data: { type: 'user', id: 1 } } } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); userRef.reload().then(function(user) { userRef.value() === user }); @@ -7100,11 +7081,11 @@ comments: DS.hasMany({ async: true }) }); ``` ```javascript - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, relationships: { comments: { @@ -7112,17 +7093,17 @@ } } } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); // get the identifier of the reference if (commentsRef.remoteType() === "ids") { - var ids = commentsRef.ids(); + let ids = commentsRef.ids(); } else if (commentsRef.remoteType() === "link") { - var link = commentsRef.link(); + let link = commentsRef.link(); } ``` @method remoteType @return {String} The name of the remote type. This should either be "link" or "ids" @@ -7146,11 +7127,11 @@ comments: DS.hasMany({ async: true }) }); ``` ```javascript - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, relationships: { comments: { @@ -7160,11 +7141,11 @@ } } } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); commentsRef.link(); // '/posts/1/comments' ``` @method link @@ -7184,11 +7165,11 @@ comments: DS.hasMany({ async: true }) }); ``` ```javascript - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, relationships: { comments: { @@ -7196,11 +7177,11 @@ } } } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); commentsRef.ids(); // ['1'] ``` @method remoteType @@ -7225,11 +7206,11 @@ comments: DS.hasMany({ async: true }) }); ``` ```javascript - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, relationships: { comments: { @@ -7244,11 +7225,11 @@ } } } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); commentsRef.meta(); // { count: 10 } ``` @method meta @@ -7270,11 +7251,11 @@ comments: DS.hasMany({ async: true }) }); ``` ``` - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, relationships: { comments: { @@ -7282,11 +7263,11 @@ } } } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); commentsRef.ids(); // ['1'] commentsRef.push([ [{ type: 'comment', id: 2 }], @@ -7304,21 +7285,21 @@ var _this = this; return resolve(objectOrPromise).then(function (payload) { var array = payload; - if (false) {} + if ((0, _emberDataPrivateFeatures.default)("ds-overhaul-references")) {} var useLegacyArrayPush = true; if (typeof payload === "object" && payload.data) { array = payload.data; useLegacyArrayPush = array.length && array[0].data; - if (false) {} + if ((0, _emberDataPrivateFeatures.default)('ds-overhaul-references')) {} } - if (!false) { + if (!(0, _emberDataPrivateFeatures.default)('ds-overhaul-references')) { useLegacyArrayPush = true; } var internalModels = undefined; if (useLegacyArrayPush) { @@ -7332,11 +7313,11 @@ internalModels = _ember.default.A(records).mapBy('_internalModel'); } _this.hasManyRelationship.computeChanges(internalModels); - return _this.hasManyRelationship.getManyArray(); + return _this.hasManyRelationship.manyArray; }); }; HasManyReference.prototype._isLoaded = function () { var hasData = get(this.hasManyRelationship, 'hasData'); @@ -7365,11 +7346,11 @@ comments: DS.hasMany({ async: true }) }); ``` ```javascript - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, relationships: { comments: { @@ -7377,11 +7358,11 @@ } } } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); post.get('comments').then(function(comments) { commentsRef.value() === comments }) ``` @@ -7389,11 +7370,11 @@ @method value @return {DS.ManyArray} */ HasManyReference.prototype.value = function () { if (this._isLoaded()) { - return this.hasManyRelationship.getManyArray(); + return this.hasManyRelationship.manyArray; } return null; }; @@ -7409,11 +7390,11 @@ comments: DS.hasMany({ async: true }) }); ``` ```javascript - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, relationships: { comments: { @@ -7421,11 +7402,11 @@ } } } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); commentsRef.load().then(function(comments) { //... }); ``` @@ -7437,11 +7418,11 @@ HasManyReference.prototype.load = function () { if (!this._isLoaded()) { return this.hasManyRelationship.getRecords(); } - return resolve(this.hasManyRelationship.getManyArray()); + return resolve(this.hasManyRelationship.manyArray); }; /** Reloads this has-many relationship. @@ -7452,11 +7433,11 @@ comments: DS.hasMany({ async: true }) }); ``` ```javascript - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, relationships: { comments: { @@ -7464,11 +7445,11 @@ } } } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); commentsRef.reload().then(function(comments) { //... }); ``` @@ -7508,11 +7489,11 @@ the identity map. Example ```javascript - var userRef = store.getReference('user', 1); + let userRef = store.getReference('user', 1); userRef.id(); // '1' ``` @method id @@ -7528,11 +7509,11 @@ loaded by the `type` and `id`. Example ```javascript - var userRef = store.getReference('user', 1); + const userRef = store.getReference('user', 1); userRef.remoteType(); // 'identity' ``` @method remoteType @@ -7558,21 +7539,21 @@ record. Example ```javascript - var userRef = store.getReference('user', 1); + let userRef = store.getReference('user', 1); // provide data for reference userRef.push({ data: { id: 1, username: "@user" }}).then(function(user) { userRef.value() === user; }); ``` - @method + @method push @param {Promise|Object} - @returns Promise<record> a promise for the value (record or relationship) + @return Promise<record> a promise for the value (record or relationship) */ RecordReference.prototype.push = function (objectOrPromise) { var _this = this; return _ember.default.RSVP.resolve(objectOrPromise).then(function (data) { @@ -7586,11 +7567,11 @@ is `null`. Example ```javascript - var userRef = store.getReference('user', 1); + let userRef = store.getReference('user', 1); userRef.value(); // user ``` @method value @@ -7605,11 +7586,11 @@ (see `remoteType` definitions per reference type). Example ```javascript - var userRef = store.getReference('user', 1); + let userRef = store.getReference('user', 1); // load user (via store.find) userRef.load().then(...) ``` @@ -7625,11 +7606,11 @@ loaded it will load the record via `store.findRecord` Example ```javascript - var userRef = store.getReference('user', 1); + let userRef = store.getReference('user', 1); // or trigger a reload userRef.reload().then(...) ``` @@ -7662,11 +7643,11 @@ define('ember-data/-private/system/relationship-meta', ['exports', 'ember-inflector', 'ember-data/-private/system/normalize-model-name'], function (exports, _emberInflector, _emberDataPrivateSystemNormalizeModelName) { exports.typeForRelationshipMeta = typeForRelationshipMeta; exports.relationshipFromMeta = relationshipFromMeta; function typeForRelationshipMeta(meta) { - var modelName; + var modelName = undefined; modelName = meta.type || meta.key; if (meta.kind === 'hasMany') { modelName = (0, _emberInflector.singularize)((0, _emberDataPrivateSystemNormalizeModelName.default)(modelName)); } @@ -7760,11 +7741,12 @@ @param {Object} options (optional) a hash of options @return {Ember.computed} relationship */ function belongsTo(modelName, options) { - var opts, userEnteredModelName; + var opts = undefined, + userEnteredModelName = undefined; if (typeof modelName === 'object') { opts = modelName; userEnteredModelName = undefined; } else { opts = options; @@ -7849,11 +7831,11 @@ var relatedTypesDescriptor = _ember.default.computed(function () { if (_ember.default.testing === true && relatedTypesDescriptor._cacheable === true) { relatedTypesDescriptor._cacheable = false; } - var modelName; + var modelName = undefined; var types = _ember.default.A(); // Loop through each computed property on the class, // and create an array of the unique types involved // in relationships @@ -7892,10 +7874,11 @@ }).readOnly(); exports.relationshipsByNameDescriptor = relationshipsByNameDescriptor; }); define("ember-data/-private/system/relationships/has-many", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/system/normalize-model-name", "ember-data/-private/system/is-array-like"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateSystemNormalizeModelName, _emberDataPrivateSystemIsArrayLike) { exports.default = hasMany; + var get = _ember.default.get; /** `DS.hasMany` is used to define One-To-Many and Many-To-Many relationships on a [DS.Model](/api/data/classes/DS.Model.html). @@ -7964,11 +7947,11 @@ one another. In the one-to-many code above, for example, Ember Data can figure out that changing the `comments` relationship should update the `post` relationship on the inverse because post is the only relationship to that model. - However, sometimes you may have multiple `belongsTo`/`hasManys` for the + However, sometimes you may have multiple `belongsTo`/`hasMany` for the same type. You can specify which property on the related model is the inverse using `DS.hasMany`'s `inverse` option: ```app/models/comment.js import DS from 'ember-data'; @@ -8018,27 +8001,28 @@ // the relationship. This is used for introspection and // serialization. Note that `key` is populated lazily // the first time the CP is called. var meta = { type: type, - isRelationship: true, options: options, + isRelationship: true, kind: 'hasMany', name: 'Has Many', key: null }; return _ember.default.computed({ get: function (key) { - var relationship = this._internalModel._relationships.get(key); - return relationship.getRecords(); + return this._internalModel._relationships.get(key).getRecords(); }, set: function (key, records) { var relationship = this._internalModel._relationships.get(key); relationship.clear(); - relationship.addRecords(_ember.default.A(records).mapBy('_internalModel')); + relationship.addRecords(records.map(function (record) { + return get(record, '_internalModel'); + })); return relationship.getRecords(); } }).meta(meta); } }); @@ -8099,20 +8083,25 @@ this.canonicalState = newRecord; _get(Object.getPrototypeOf(BelongsToRelationship.prototype), "addCanonicalRecord", this).call(this, newRecord); } }, { + key: "inverseDidDematerialize", + value: function inverseDidDematerialize() { + this.notifyBelongsToChanged(); + } + }, { key: "flushCanonical", value: function flushCanonical() { //temporary fix to not remove newly created records if server returned null. //TODO remove once we have proper diffing if (this.inverseRecord && this.inverseRecord.isNew() && !this.canonicalState) { return; } if (this.inverseRecord !== this.canonicalState) { this.inverseRecord = this.canonicalState; - this.internalModel.notifyBelongsToChanged(this.key); + this.notifyBelongsToChanged(); } _get(Object.getPrototypeOf(BelongsToRelationship.prototype), "flushCanonical", this).call(this); } }, { @@ -8126,11 +8115,11 @@ this.removeRecord(this.inverseRecord); } this.inverseRecord = newRecord; _get(Object.getPrototypeOf(BelongsToRelationship.prototype), "addRecord", this).call(this, newRecord); - this.internalModel.notifyBelongsToChanged(this.key); + this.notifyBelongsToChanged(); } }, { key: "setRecordPromise", value: function setRecordPromise(newPromise) { var content = newPromise.get && newPromise.get('content'); @@ -8143,10 +8132,15 @@ if (!this.members.has(record)) { return; } this.inverseRecord = null; _get(Object.getPrototypeOf(BelongsToRelationship.prototype), "removeRecordFromOwn", this).call(this, record); + this.notifyBelongsToChanged(); + } + }, { + key: "notifyBelongsToChanged", + value: function notifyBelongsToChanged() { this.internalModel.notifyBelongsToChanged(this.key); } }, { key: "removeCanonicalRecordFromOwn", value: function removeCanonicalRecordFromOwn(record) { @@ -8182,11 +8176,11 @@ value: function getRecord() { var _this2 = this; //TODO(Igor) flushCanonical here once our syncing is not stupid if (this.isAsync) { - var promise; + var promise = undefined; if (this.link) { if (this.hasLoaded) { promise = this.findRecord(); } else { promise = this.findLink().then(function () { @@ -8285,18 +8279,23 @@ } }, { key: "get", value: function get(key) { var relationships = this.initializedRelationships; - var internalModel = this.internalModel; - var relationshipsByName = _get(internalModel.type, 'relationshipsByName'); + var relationship = relationships[key]; - if (!relationships[key] && relationshipsByName.get(key)) { - relationships[key] = createRelationshipFor(internalModel, relationshipsByName.get(key), internalModel.store); + if (!relationship) { + var internalModel = this.internalModel; + var relationshipsByName = _get(internalModel.type, 'relationshipsByName'); + var rel = relationshipsByName.get(key); + + if (rel) { + relationship = relationships[key] = createRelationshipFor(internalModel, rel, internalModel.store); + } } - return relationships[key]; + return relationship; } }, { key: "record", get: function () { return this.internalModel; @@ -8306,85 +8305,103 @@ return Relationships; })(); exports.default = Relationships; }); -define("ember-data/-private/system/relationships/state/has-many", ["exports", "ember-data/-private/debug", "ember-data/-private/system/promise-proxies", "ember-data/-private/system/relationships/state/relationship", "ember-data/-private/system/ordered-set", "ember-data/-private/system/many-array"], function (exports, _emberDataPrivateDebug, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemRelationshipsStateRelationship, _emberDataPrivateSystemOrderedSet, _emberDataPrivateSystemManyArray) { - 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; }; })(); +define('ember-data/-private/system/relationships/state/has-many', ['exports', 'ember-data/-private/debug', 'ember-data/-private/system/promise-proxies', 'ember-data/-private/system/relationships/state/relationship', 'ember-data/-private/system/ordered-set', 'ember-data/-private/system/many-array'], function (exports, _emberDataPrivateDebug, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemRelationshipsStateRelationship, _emberDataPrivateSystemOrderedSet, _emberDataPrivateSystemManyArray) { + 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; }; })(); - var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } - 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; } + 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 ManyRelationship = (function (_Relationship) { _inherits(ManyRelationship, _Relationship); function ManyRelationship(store, record, inverseKey, relationshipMeta) { - _get(Object.getPrototypeOf(ManyRelationship.prototype), "constructor", this).call(this, store, record, inverseKey, relationshipMeta); + _get(Object.getPrototypeOf(ManyRelationship.prototype), 'constructor', this).call(this, store, record, inverseKey, relationshipMeta); this.belongsToType = relationshipMeta.type; this.canonicalState = []; this.isPolymorphic = relationshipMeta.options.polymorphic; + this._manyArray = null; + this.__loadingPromise = null; } _createClass(ManyRelationship, [{ - key: "getManyArray", - value: function getManyArray() { - if (!this._manyArray) { - this._manyArray = _emberDataPrivateSystemManyArray.default.create({ - canonicalState: this.canonicalState, - store: this.store, - relationship: this, - type: this.store.modelFor(this.belongsToType), - record: this.record, - meta: this.meta, - isPolymorphic: this.isPolymorphic + key: '_updateLoadingPromise', + value: function _updateLoadingPromise(promise, content) { + if (this.__loadingPromise) { + if (content) { + this.__loadingPromise.set('content', content); + } + this.__loadingPromise.set('promise', promise); + } else { + this.__loadingPromise = new _emberDataPrivateSystemPromiseProxies.PromiseManyArray({ + promise: promise, + content: content }); } - return this._manyArray; + + return this.__loadingPromise; } }, { - key: "destroy", + key: 'destroy', value: function destroy() { + _get(Object.getPrototypeOf(ManyRelationship.prototype), 'destroy', this).call(this); if (this._manyArray) { this._manyArray.destroy(); + this._manyArray = null; } + + if (this._loadingPromise) { + this._loadingPromise.destroy(); + } } }, { - key: "updateMeta", + key: 'updateMeta', value: function updateMeta(meta) { - _get(Object.getPrototypeOf(ManyRelationship.prototype), "updateMeta", this).call(this, meta); + _get(Object.getPrototypeOf(ManyRelationship.prototype), 'updateMeta', this).call(this, meta); if (this._manyArray) { this._manyArray.set('meta', meta); } } }, { - key: "addCanonicalRecord", + key: 'addCanonicalRecord', value: function addCanonicalRecord(record, idx) { if (this.canonicalMembers.has(record)) { return; } if (idx !== undefined) { this.canonicalState.splice(idx, 0, record); } else { this.canonicalState.push(record); } - _get(Object.getPrototypeOf(ManyRelationship.prototype), "addCanonicalRecord", this).call(this, record, idx); + _get(Object.getPrototypeOf(ManyRelationship.prototype), 'addCanonicalRecord', this).call(this, record, idx); } }, { - key: "addRecord", + key: 'inverseDidDematerialize', + value: function inverseDidDematerialize() { + if (this._manyArray) { + this._manyArray.destroy(); + this._manyArray = null; + } + this.notifyHasManyChanged(); + } + }, { + key: 'addRecord', value: function addRecord(record, idx) { if (this.members.has(record)) { return; } - _get(Object.getPrototypeOf(ManyRelationship.prototype), "addRecord", this).call(this, record, idx); + _get(Object.getPrototypeOf(ManyRelationship.prototype), 'addRecord', this).call(this, record, idx); // make lazy later - this.getManyArray().internalAddRecords([record], idx); + this.manyArray.internalAddRecords([record], idx); } }, { - key: "removeCanonicalRecordFromOwn", + key: 'removeCanonicalRecordFromOwn', value: function removeCanonicalRecordFromOwn(record, idx) { var i = idx; if (!this.canonicalMembers.has(record)) { return; } @@ -8392,45 +8409,45 @@ i = this.canonicalState.indexOf(record); } if (i > -1) { this.canonicalState.splice(i, 1); } - _get(Object.getPrototypeOf(ManyRelationship.prototype), "removeCanonicalRecordFromOwn", this).call(this, record, idx); + _get(Object.getPrototypeOf(ManyRelationship.prototype), 'removeCanonicalRecordFromOwn', this).call(this, record, idx); } }, { - key: "flushCanonical", + key: 'flushCanonical', value: function flushCanonical() { if (this._manyArray) { this._manyArray.flushCanonical(); } - _get(Object.getPrototypeOf(ManyRelationship.prototype), "flushCanonical", this).call(this); + _get(Object.getPrototypeOf(ManyRelationship.prototype), 'flushCanonical', this).call(this); } }, { - key: "removeRecordFromOwn", + key: 'removeRecordFromOwn', value: function removeRecordFromOwn(record, idx) { if (!this.members.has(record)) { return; } - _get(Object.getPrototypeOf(ManyRelationship.prototype), "removeRecordFromOwn", this).call(this, record, idx); - var manyArray = this.getManyArray(); + _get(Object.getPrototypeOf(ManyRelationship.prototype), 'removeRecordFromOwn', this).call(this, record, idx); + var manyArray = this.manyArray; if (idx !== undefined) { //TODO(Igor) not used currently, fix manyArray.currentState.removeAt(idx); } else { manyArray.internalRemoveRecords([record]); } } }, { - key: "notifyRecordRelationshipAdded", + key: 'notifyRecordRelationshipAdded', value: function notifyRecordRelationshipAdded(record, idx) { this.record.notifyHasManyAdded(this.key, record, idx); } }, { - key: "reload", + key: 'reload', value: function reload() { - var manyArray = this.getManyArray(); + var manyArray = this.manyArray; var manyArrayLoadedState = manyArray.get('isLoaded'); if (this._loadingPromise) { if (this._loadingPromise.get('isPending')) { return this._loadingPromise; @@ -8438,103 +8455,90 @@ if (this._loadingPromise.get('isRejected')) { manyArray.set('isLoaded', manyArrayLoadedState); } } + var promise = undefined; if (this.link) { - this._loadingPromise = (0, _emberDataPrivateSystemPromiseProxies.promiseManyArray)(this.fetchLink(), 'Reload with link'); - return this._loadingPromise; + promise = this.fetchLink(); } else { - this._loadingPromise = (0, _emberDataPrivateSystemPromiseProxies.promiseManyArray)(this.store._scheduleFetchMany(manyArray.currentState).then(function () { + promise = this.store._scheduleFetchMany(manyArray.currentState).then(function () { return manyArray; - }), 'Reload with ids'); - return this._loadingPromise; + }); } + + this._updateLoadingPromise(promise); + return this._loadingPromise; } }, { - key: "computeChanges", + key: 'computeChanges', value: function computeChanges(records) { var members = this.canonicalMembers; var recordsToRemove = []; - var length; - var record; - var i; + var recordSet = setForArray(records); - records = setForArray(records); - members.forEach(function (member) { - if (records.has(member)) { + if (recordSet.has(member)) { return; } recordsToRemove.push(member); }); this.removeCanonicalRecords(recordsToRemove); - // Using records.toArray() since currently using - // removeRecord can modify length, messing stuff up - // forEach since it directly looks at "length" each - // iteration - records = records.toArray(); - length = records.length; - for (i = 0; i < length; i++) { - record = records[i]; + for (var i = 0, l = records.length; i < l; i++) { + var record = records[i]; this.removeCanonicalRecord(record); this.addCanonicalRecord(record, i); } } }, { - key: "fetchLink", + key: 'fetchLink', value: function fetchLink() { var _this = this; return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function (records) { if (records.hasOwnProperty('meta')) { _this.updateMeta(records.meta); } _this.store._backburner.join(function () { _this.updateRecordsFromAdapter(records); - _this.getManyArray().set('isLoaded', true); + _this.manyArray.set('isLoaded', true); }); - return _this.getManyArray(); + return _this.manyArray; }); } }, { - key: "findRecords", + key: 'findRecords', value: function findRecords() { - var manyArray = this.getManyArray(); - var array = manyArray.toArray(); - var internalModels = new Array(array.length); + var manyArray = this.manyArray; + var internalModels = manyArray.currentState; - for (var i = 0; i < array.length; i++) { - internalModels[i] = array[i]._internalModel; - } - //TODO CLEANUP return this.store.findMany(internalModels).then(function () { if (!manyArray.get('isDestroyed')) { //Goes away after the manyArray refactor manyArray.set('isLoaded', true); } return manyArray; }); } }, { - key: "notifyHasManyChanged", + key: 'notifyHasManyChanged', value: function notifyHasManyChanged() { this.record.notifyHasManyAdded(this.key); } }, { - key: "getRecords", + key: 'getRecords', value: function getRecords() { var _this2 = this; //TODO(Igor) sync server here, once our syncing is not stupid - var manyArray = this.getManyArray(); + var manyArray = this.manyArray; if (this.isAsync) { - var promise; + var promise = undefined; if (this.link) { if (this.hasLoaded) { promise = this.findRecords(); } else { promise = this.findLink().then(function () { @@ -8542,15 +8546,11 @@ }); } } else { promise = this.findRecords(); } - this._loadingPromise = _emberDataPrivateSystemPromiseProxies.PromiseManyArray.create({ - content: manyArray, - promise: promise - }); - return this._loadingPromise; + return this._updateLoadingPromise(promise, manyArray); } else { //TODO(Igor) WTF DO I DO HERE? // TODO @runspired equal WTFs to Igor if (!manyArray.get('isDestroyed')) { @@ -8558,15 +8558,36 @@ } return manyArray; } } }, { - key: "updateData", + key: 'updateData', value: function updateData(data) { var internalModels = this.store._pushResourceIdentifiers(this, data); this.updateRecordsFromAdapter(internalModels); } + }, { + key: '_loadingPromise', + get: function () { + return this.__loadingPromise; + } + }, { + key: 'manyArray', + get: function () { + if (!this._manyArray) { + this._manyArray = _emberDataPrivateSystemManyArray.default.create({ + canonicalState: this.canonicalState, + store: this.store, + relationship: this, + type: this.store.modelFor(this.belongsToType), + record: this.record, + meta: this.meta, + isPolymorphic: this.isPolymorphic + }); + } + return this._manyArray; + } }]); return ManyRelationship; })(_emberDataPrivateSystemRelationshipsStateRelationship.default); @@ -8582,14 +8603,14 @@ } return set; } }); -define("ember-data/-private/system/relationships/state/relationship", ["exports", "ember-data/-private/debug", "ember-data/-private/system/ordered-set", "ember-data/-private/system/normalize-link"], function (exports, _emberDataPrivateDebug, _emberDataPrivateSystemOrderedSet, _emberDataPrivateSystemNormalizeLink) { - 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; }; })(); +define('ember-data/-private/system/relationships/state/relationship', ['exports', 'ember-data/-private/debug', 'ember-data/-private/system/ordered-set', 'ember-data/-private/system/normalize-link'], function (exports, _emberDataPrivateDebug, _emberDataPrivateSystemOrderedSet, _emberDataPrivateSystemNormalizeLink) { + 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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } var Relationship = (function () { function Relationship(store, internalModel, inverseKey, relationshipMeta) { var async = relationshipMeta.options.async; this.members = new _emberDataPrivateSystemOrderedSet.default(); @@ -8610,62 +8631,91 @@ } // TODO @runspired deprecate this as it was never truly a record instance _createClass(Relationship, [{ - key: "destroy", - value: function destroy() {} + key: 'destroy', + value: function destroy() { + var _this = this; + + if (!this.inverseKey) { + return; + } + + var allMembers = + // we actually want a union of members and canonicalMembers + // they should be disjoint but currently are not due to a bug + this.members.toArray().concat(this.canonicalMembers.toArray()); + + allMembers.forEach(function (inverseInternalModel) { + var relationship = inverseInternalModel._relationships.get(_this.inverseKey); + // TODO: there is always a relationship in this case; this guard exists + // because there are tests that fail in teardown after putting things in + // invalid state + if (relationship) { + relationship.inverseDidDematerialize(); + } + }); + } }, { - key: "updateMeta", + key: 'inverseDidDematerialize', + value: function inverseDidDematerialize() {} + }, { + key: 'updateMeta', value: function updateMeta(meta) { this.meta = meta; } }, { - key: "clear", + key: 'clear', value: function clear() { - var members = this.members.list; - var member; + var members = this.members.list; while (members.length > 0) { - member = members[0]; + var member = members[0]; this.removeRecord(member); } + + var canonicalMembers = this.canonicalMembers.list; + while (canonicalMembers.length > 0) { + var member = canonicalMembers[0]; + this.removeCanonicalRecord(member); + } } }, { - key: "removeRecords", + key: 'removeRecords', value: function removeRecords(records) { - var _this = this; + var _this2 = this; records.forEach(function (record) { - return _this.removeRecord(record); + return _this2.removeRecord(record); }); } }, { - key: "addRecords", + key: 'addRecords', value: function addRecords(records, idx) { - var _this2 = this; + var _this3 = this; records.forEach(function (record) { - _this2.addRecord(record, idx); + _this3.addRecord(record, idx); if (idx !== undefined) { idx++; } }); } }, { - key: "addCanonicalRecords", + key: 'addCanonicalRecords', value: function addCanonicalRecords(records, idx) { for (var i = 0; i < records.length; i++) { if (idx !== undefined) { this.addCanonicalRecord(records[i], i + idx); } else { this.addCanonicalRecord(records[i]); } } } }, { - key: "addCanonicalRecord", + key: 'addCanonicalRecord', value: function addCanonicalRecord(record, idx) { if (!this.canonicalMembers.has(record)) { this.canonicalMembers.add(record); if (this.inverseKey) { record._relationships.get(this.inverseKey).addCanonicalRecord(this.record); @@ -8678,22 +8728,22 @@ } this.flushCanonicalLater(); this.setHasData(true); } }, { - key: "removeCanonicalRecords", + key: 'removeCanonicalRecords', value: function removeCanonicalRecords(records, idx) { for (var i = 0; i < records.length; i++) { if (idx !== undefined) { this.removeCanonicalRecord(records[i], i + idx); } else { this.removeCanonicalRecord(records[i]); } } } }, { - key: "removeCanonicalRecord", + key: 'removeCanonicalRecord', value: function removeCanonicalRecord(record, idx) { if (this.canonicalMembers.has(record)) { this.removeCanonicalRecordFromOwn(record); if (this.inverseKey) { this.removeCanonicalRecordFromInverse(record); @@ -8704,11 +8754,11 @@ } } this.flushCanonicalLater(); } }, { - key: "addRecord", + key: 'addRecord', value: function addRecord(record, idx) { if (!this.members.has(record)) { this.members.addWithIndex(record, idx); this.notifyRecordRelationshipAdded(record, idx); if (this.inverseKey) { @@ -8717,16 +8767,16 @@ if (!record._implicitRelationships[this.inverseKeyForImplicit]) { record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, { options: {} }); } record._implicitRelationships[this.inverseKeyForImplicit].addRecord(this.record); } - this.record.updateRecordArraysLater(); + this.record.updateRecordArrays(); } this.setHasData(true); } }, { - key: "removeRecord", + key: 'removeRecord', value: function removeRecord(record) { if (this.members.has(record)) { this.removeRecordFromOwn(record); if (this.inverseKey) { this.removeRecordFromInverse(record); @@ -8736,81 +8786,79 @@ } } } } }, { - key: "removeRecordFromInverse", + key: 'removeRecordFromInverse', value: function removeRecordFromInverse(record) { var inverseRelationship = record._relationships.get(this.inverseKey); //Need to check for existence, as the record might unloading at the moment if (inverseRelationship) { inverseRelationship.removeRecordFromOwn(this.record); } } }, { - key: "removeRecordFromOwn", + key: 'removeRecordFromOwn', value: function removeRecordFromOwn(record) { this.members.delete(record); this.notifyRecordRelationshipRemoved(record); this.record.updateRecordArrays(); } }, { - key: "removeCanonicalRecordFromInverse", + key: 'removeCanonicalRecordFromInverse', value: function removeCanonicalRecordFromInverse(record) { var inverseRelationship = record._relationships.get(this.inverseKey); //Need to check for existence, as the record might unloading at the moment if (inverseRelationship) { inverseRelationship.removeCanonicalRecordFromOwn(this.record); } } }, { - key: "removeCanonicalRecordFromOwn", + key: 'removeCanonicalRecordFromOwn', value: function removeCanonicalRecordFromOwn(record) { this.canonicalMembers.delete(record); this.flushCanonicalLater(); } }, { - key: "flushCanonical", + key: 'flushCanonical', value: function flushCanonical() { + var list = this.members.list; this.willSync = false; //a hack for not removing new records //TODO remove once we have proper diffing var newRecords = []; - for (var i = 0; i < this.members.list.length; i++) { - if (this.members.list[i].isNew()) { - newRecords.push(this.members.list[i]); + for (var i = 0; i < list.length; i++) { + if (list[i].isNew()) { + newRecords.push(list[i]); } } + //TODO(Igor) make this less abysmally slow this.members = this.canonicalMembers.copy(); - for (i = 0; i < newRecords.length; i++) { + for (var i = 0; i < newRecords.length; i++) { this.members.add(newRecords[i]); } } }, { - key: "flushCanonicalLater", + key: 'flushCanonicalLater', value: function flushCanonicalLater() { - var _this3 = this; - if (this.willSync) { return; } this.willSync = true; - this.store._backburner.join(function () { - return _this3.store._backburner.schedule('syncRelationships', _this3, _this3.flushCanonical); - }); + this.store._updateRelationshipState(this); } }, { - key: "updateLink", + key: 'updateLink', value: function updateLink(link) { this.link = link; this.linkPromise = null; this.record.notifyPropertyChange(this.key); } }, { - key: "findLink", + key: 'findLink', value: function findLink() { if (this.linkPromise) { return this.linkPromise; } else { var promise = this.fetchLink(); @@ -8819,21 +8867,21 @@ return result; }); } } }, { - key: "updateRecordsFromAdapter", + key: 'updateRecordsFromAdapter', value: function updateRecordsFromAdapter(records) { //TODO(Igor) move this to a proper place //TODO Once we have adapter support, we need to handle updated and canonical changes this.computeChanges(records); } }, { - key: "notifyRecordRelationshipAdded", + key: 'notifyRecordRelationshipAdded', value: function notifyRecordRelationshipAdded() {} }, { - key: "notifyRecordRelationshipRemoved", + key: 'notifyRecordRelationshipRemoved', value: function notifyRecordRelationshipRemoved() {} /* `hasData` for a relationship is a flag to indicate if we consider the content of this relationship "known". Snapshots uses this to tell the @@ -8842,11 +8890,11 @@ as that might overwrite remote state. All relationships for a newly created (`store.createRecord()`) are considered known (`hasData === true`). */ }, { - key: "setHasData", + key: 'setHasData', value: function setHasData(value) { this.hasData = value; } /* @@ -8856,11 +8904,11 @@ the local data in scenarios where the local state is considered known (`hasData === true`). Updating the link will automatically set `hasLoaded` to `false`. */ }, { - key: "setHasLoaded", + key: 'setHasLoaded', value: function setHasLoaded(value) { this.hasLoaded = value; } /* @@ -8869,11 +8917,11 @@ meta, data and links of that relationship. `push` use `updateMeta`, `updateData` and `updateLink` to update the state of the relationship. */ }, { - key: "push", + key: 'push', value: function push(payload) { var hasData = false; var hasLink = false; @@ -8910,19 +8958,19 @@ } else if (hasLink) { this.setHasLoaded(false); } } }, { - key: "updateData", + key: 'updateData', value: function updateData() {} }, { - key: "record", + key: 'record', get: function () { return this.internalModel; } }, { - key: "parentType", + key: 'parentType', get: function () { return this.internalModel.modelName; } }]); @@ -9078,350 +9126,374 @@ return this._snapshots; }; }); define("ember-data/-private/system/snapshot", ["exports", "ember", "ember-data/-private/system/empty-object"], function (exports, _ember, _emberDataPrivateSystemEmptyObject) { - exports.default = Snapshot; + 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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + var get = _ember.default.get; /** @class Snapshot @namespace DS @private @constructor @param {DS.Model} internalModel The model to create a snapshot from */ - function Snapshot(internalModel) { - var _this = this; + var Snapshot = (function () { + function Snapshot(internalModel) { + var _this = this; - var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; - this._attributes = new _emberDataPrivateSystemEmptyObject.default(); - this._belongsToRelationships = new _emberDataPrivateSystemEmptyObject.default(); - this._belongsToIds = new _emberDataPrivateSystemEmptyObject.default(); - this._hasManyRelationships = new _emberDataPrivateSystemEmptyObject.default(); - this._hasManyIds = new _emberDataPrivateSystemEmptyObject.default(); + this._attributes = new _emberDataPrivateSystemEmptyObject.default(); + this._belongsToRelationships = new _emberDataPrivateSystemEmptyObject.default(); + this._belongsToIds = new _emberDataPrivateSystemEmptyObject.default(); + this._hasManyRelationships = new _emberDataPrivateSystemEmptyObject.default(); + this._hasManyIds = new _emberDataPrivateSystemEmptyObject.default(); + this._internalModel = internalModel; - var record = internalModel.getRecord(); - this.record = record; - record.eachAttribute(function (keyName) { - return _this._attributes[keyName] = get(record, keyName); - }); + var record = internalModel.getRecord(); - this.id = internalModel.id; - this._internalModel = internalModel; - this.type = internalModel.type; - this.modelName = internalModel.type.modelName; + /** + The underlying record for this snapshot. Can be used to access methods and + properties defined on the record. + Example + ```javascript + let json = snapshot.record.toJSON(); + ``` + @property record + @type {DS.Model} + */ + this.record = record; + record.eachAttribute(function (keyName) { + return _this._attributes[keyName] = get(record, keyName); + }); - /** - A hash of adapter options - @property adapterOptions - @type {Object} - */ - this.adapterOptions = options.adapterOptions; - this.include = options.include; + /** + The id of the snapshot's underlying record + Example + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postSnapshot.id; // => '1' + ``` + @property id + @type {String} + */ + this.id = internalModel.id; - this._changedAttributes = record.changedAttributes(); - } + /** + A hash of adapter options + @property adapterOptions + @type {Object} + */ + this.adapterOptions = options.adapterOptions; + this.include = options.include; - Snapshot.prototype = { - constructor: Snapshot, + /** + The type of the underlying record for this snapshot, as a DS.Model. + @property type + @type {DS.Model} + */ + // TODO @runspired we should deprecate this in favor of modelClass but only once + // we've cleaned up the internals enough that a public change to follow suite is + // uncontroversial. + this.type = internalModel.modelClass; - /** - The id of the snapshot's underlying record - Example - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postSnapshot.id; // => '1' - ``` - @property id - @type {String} - */ - id: null, + /** + The name of the type of the underlying record for this snapshot, as a string. + @property modelName + @type {String} + */ + this.modelName = internalModel.modelName; - /** - The underlying record for this snapshot. Can be used to access methods and - properties defined on the record. - Example - ```javascript - var json = snapshot.record.toJSON(); - ``` - @property record - @type {DS.Model} - */ - record: null, + this._changedAttributes = record.changedAttributes(); + } /** - The type of the underlying record for this snapshot, as a DS.Model. - @property type - @type {DS.Model} - */ - type: null, + Returns the value of an attribute. + Example + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postSnapshot.attr('author'); // => 'Tomster' + postSnapshot.attr('title'); // => 'Ember.js rocks' + ``` + Note: Values are loaded eagerly and cached when the snapshot is created. + @method attr + @param {String} keyName + @return {Object} The attribute value or undefined + */ - /** - The name of the type of the underlying record for this snapshot, as a string. - @property modelName - @type {String} - */ - modelName: null, + _createClass(Snapshot, [{ + key: "attr", + value: function attr(keyName) { + if (keyName in this._attributes) { + return this._attributes[keyName]; + } + throw new _ember.default.Error("Model '" + _ember.default.inspect(this.record) + "' has no attribute named '" + keyName + "' defined."); + } - /** - Returns the value of an attribute. - Example - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postSnapshot.attr('author'); // => 'Tomster' - postSnapshot.attr('title'); // => 'Ember.js rocks' - ``` - Note: Values are loaded eagerly and cached when the snapshot is created. - @method attr - @param {String} keyName - @return {Object} The attribute value or undefined - */ - attr: function (keyName) { - if (keyName in this._attributes) { - return this._attributes[keyName]; + /** + Returns all attributes and their corresponding values. + Example + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postSnapshot.attributes(); // => { author: 'Tomster', title: 'Ember.js rocks' } + ``` + @method attributes + @return {Object} All attributes of the current snapshot + */ + }, { + key: "attributes", + value: function attributes() { + return _ember.default.copy(this._attributes); } - throw new _ember.default.Error("Model '" + _ember.default.inspect(this.record) + "' has no attribute named '" + keyName + "' defined."); - }, - /** - Returns all attributes and their corresponding values. - Example - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postSnapshot.attributes(); // => { author: 'Tomster', title: 'Ember.js rocks' } - ``` - @method attributes - @return {Object} All attributes of the current snapshot - */ - attributes: function () { - return _ember.default.copy(this._attributes); - }, + /** + Returns all changed attributes and their old and new values. + Example + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postModel.set('title', 'Ember.js rocks!'); + postSnapshot.changedAttributes(); // => { title: ['Ember.js rocks', 'Ember.js rocks!'] } + ``` + @method changedAttributes + @return {Object} All changed attributes of the current snapshot + */ + }, { + key: "changedAttributes", + value: function changedAttributes() { + var changedAttributes = new _emberDataPrivateSystemEmptyObject.default(); + var changedAttributeKeys = Object.keys(this._changedAttributes); - /** - Returns all changed attributes and their old and new values. - Example - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postModel.set('title', 'Ember.js rocks!'); - postSnapshot.changedAttributes(); // => { title: ['Ember.js rocks', 'Ember.js rocks!'] } - ``` - @method changedAttributes - @return {Object} All changed attributes of the current snapshot - */ - changedAttributes: function () { - var changedAttributes = new _emberDataPrivateSystemEmptyObject.default(); - var changedAttributeKeys = Object.keys(this._changedAttributes); + for (var i = 0, _length = changedAttributeKeys.length; i < _length; i++) { + var key = changedAttributeKeys[i]; + changedAttributes[key] = _ember.default.copy(this._changedAttributes[key]); + } - for (var i = 0, _length = changedAttributeKeys.length; i < _length; i++) { - var key = changedAttributeKeys[i]; - changedAttributes[key] = _ember.default.copy(this._changedAttributes[key]); + return changedAttributes; } - return changedAttributes; - }, + /** + Returns the current value of a belongsTo relationship. + `belongsTo` takes an optional hash of options as a second parameter, + currently supported options are: + - `id`: set to `true` if you only want the ID of the related record to be + returned. + Example + ```javascript + // store.push('post', { id: 1, title: 'Hello World' }); + // store.createRecord('comment', { body: 'Lorem ipsum', post: post }); + commentSnapshot.belongsTo('post'); // => DS.Snapshot + commentSnapshot.belongsTo('post', { id: true }); // => '1' + // store.push('comment', { id: 1, body: 'Lorem ipsum' }); + commentSnapshot.belongsTo('post'); // => undefined + ``` + Calling `belongsTo` will return a new Snapshot as long as there's any known + data for the relationship available, such as an ID. If the relationship is + known but unset, `belongsTo` will return `null`. If the contents of the + relationship is unknown `belongsTo` will return `undefined`. + Note: Relationships are loaded lazily and cached upon first access. + @method belongsTo + @param {String} keyName + @param {Object} [options] + @return {(DS.Snapshot|String|null|undefined)} A snapshot or ID of a known + relationship or null if the relationship is known but unset. undefined + will be returned if the contents of the relationship is unknown. + */ + }, { + key: "belongsTo", + value: function belongsTo(keyName, options) { + var id = options && options.id; + var relationship = undefined, + inverseRecord = undefined, + hasData = undefined; + var result = undefined; - /** - Returns the current value of a belongsTo relationship. - `belongsTo` takes an optional hash of options as a second parameter, - currently supported options are: - - `id`: set to `true` if you only want the ID of the related record to be - returned. - Example - ```javascript - // store.push('post', { id: 1, title: 'Hello World' }); - // store.createRecord('comment', { body: 'Lorem ipsum', post: post }); - commentSnapshot.belongsTo('post'); // => DS.Snapshot - commentSnapshot.belongsTo('post', { id: true }); // => '1' - // store.push('comment', { id: 1, body: 'Lorem ipsum' }); - commentSnapshot.belongsTo('post'); // => undefined - ``` - Calling `belongsTo` will return a new Snapshot as long as there's any known - data for the relationship available, such as an ID. If the relationship is - known but unset, `belongsTo` will return `null`. If the contents of the - relationship is unknown `belongsTo` will return `undefined`. - Note: Relationships are loaded lazily and cached upon first access. - @method belongsTo - @param {String} keyName - @param {Object} [options] - @return {(DS.Snapshot|String|null|undefined)} A snapshot or ID of a known - relationship or null if the relationship is known but unset. undefined - will be returned if the contents of the relationship is unknown. - */ - belongsTo: function (keyName, options) { - var id = options && options.id; - var relationship, inverseRecord, hasData; - var result; + if (id && keyName in this._belongsToIds) { + return this._belongsToIds[keyName]; + } - if (id && keyName in this._belongsToIds) { - return this._belongsToIds[keyName]; - } + if (!id && keyName in this._belongsToRelationships) { + return this._belongsToRelationships[keyName]; + } - if (!id && keyName in this._belongsToRelationships) { - return this._belongsToRelationships[keyName]; - } + relationship = this._internalModel._relationships.get(keyName); + if (!(relationship && relationship.relationshipMeta.kind === 'belongsTo')) { + throw new _ember.default.Error("Model '" + _ember.default.inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined."); + } - relationship = this._internalModel._relationships.get(keyName); - if (!(relationship && relationship.relationshipMeta.kind === 'belongsTo')) { - throw new _ember.default.Error("Model '" + _ember.default.inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined."); - } + hasData = get(relationship, 'hasData'); + inverseRecord = get(relationship, 'inverseRecord'); - hasData = get(relationship, 'hasData'); - inverseRecord = get(relationship, 'inverseRecord'); - - if (hasData) { - if (inverseRecord && !inverseRecord.isDeleted()) { - if (id) { - result = get(inverseRecord, 'id'); + if (hasData) { + if (inverseRecord && !inverseRecord.isDeleted()) { + if (id) { + result = get(inverseRecord, 'id'); + } else { + result = inverseRecord.createSnapshot(); + } } else { - result = inverseRecord.createSnapshot(); + result = null; } + } + + if (id) { + this._belongsToIds[keyName] = result; } else { - result = null; + this._belongsToRelationships[keyName] = result; } - } - if (id) { - this._belongsToIds[keyName] = result; - } else { - this._belongsToRelationships[keyName] = result; + return result; } - return result; - }, + /** + Returns the current value of a hasMany relationship. + `hasMany` takes an optional hash of options as a second parameter, + currently supported options are: + - `ids`: set to `true` if you only want the IDs of the related records to be + returned. + Example + ```javascript + // store.push('post', { id: 1, title: 'Hello World', comments: [2, 3] }); + postSnapshot.hasMany('comments'); // => [DS.Snapshot, DS.Snapshot] + postSnapshot.hasMany('comments', { ids: true }); // => ['2', '3'] + // store.push('post', { id: 1, title: 'Hello World' }); + postSnapshot.hasMany('comments'); // => undefined + ``` + Note: Relationships are loaded lazily and cached upon first access. + @method hasMany + @param {String} keyName + @param {Object} [options] + @return {(Array|undefined)} An array of snapshots or IDs of a known + relationship or an empty array if the relationship is known but unset. + undefined will be returned if the contents of the relationship is unknown. + */ + }, { + key: "hasMany", + value: function hasMany(keyName, options) { + var ids = options && options.ids; + var relationship = undefined, + members = undefined, + hasData = undefined; + var results = undefined; - /** - Returns the current value of a hasMany relationship. - `hasMany` takes an optional hash of options as a second parameter, - currently supported options are: - - `ids`: set to `true` if you only want the IDs of the related records to be - returned. - Example - ```javascript - // store.push('post', { id: 1, title: 'Hello World', comments: [2, 3] }); - postSnapshot.hasMany('comments'); // => [DS.Snapshot, DS.Snapshot] - postSnapshot.hasMany('comments', { ids: true }); // => ['2', '3'] - // store.push('post', { id: 1, title: 'Hello World' }); - postSnapshot.hasMany('comments'); // => undefined - ``` - Note: Relationships are loaded lazily and cached upon first access. - @method hasMany - @param {String} keyName - @param {Object} [options] - @return {(Array|undefined)} An array of snapshots or IDs of a known - relationship or an empty array if the relationship is known but unset. - undefined will be returned if the contents of the relationship is unknown. - */ - hasMany: function (keyName, options) { - var ids = options && options.ids; - var relationship, members, hasData; - var results; + if (ids && keyName in this._hasManyIds) { + return this._hasManyIds[keyName]; + } - if (ids && keyName in this._hasManyIds) { - return this._hasManyIds[keyName]; + if (!ids && keyName in this._hasManyRelationships) { + return this._hasManyRelationships[keyName]; + } + + relationship = this._internalModel._relationships.get(keyName); + if (!(relationship && relationship.relationshipMeta.kind === 'hasMany')) { + throw new _ember.default.Error("Model '" + _ember.default.inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined."); + } + + hasData = get(relationship, 'hasData'); + members = get(relationship, 'members'); + + if (hasData) { + results = []; + members.forEach(function (member) { + if (!member.isDeleted()) { + if (ids) { + results.push(member.id); + } else { + results.push(member.createSnapshot()); + } + } + }); + } + + if (ids) { + this._hasManyIds[keyName] = results; + } else { + this._hasManyRelationships[keyName] = results; + } + + return results; } - if (!ids && keyName in this._hasManyRelationships) { - return this._hasManyRelationships[keyName]; + /** + Iterates through all the attributes of the model, calling the passed + function on each attribute. + Example + ```javascript + snapshot.eachAttribute(function(name, meta) { + // ... + }); + ``` + @method eachAttribute + @param {Function} callback the callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + */ + }, { + key: "eachAttribute", + value: function eachAttribute(callback, binding) { + this.record.eachAttribute(callback, binding); } - relationship = this._internalModel._relationships.get(keyName); - if (!(relationship && relationship.relationshipMeta.kind === 'hasMany')) { - throw new _ember.default.Error("Model '" + _ember.default.inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined."); + /** + Iterates through all the relationships of the model, calling the passed + function on each relationship. + Example + ```javascript + snapshot.eachRelationship(function(name, relationship) { + // ... + }); + ``` + @method eachRelationship + @param {Function} callback the callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + */ + }, { + key: "eachRelationship", + value: function eachRelationship(callback, binding) { + this.record.eachRelationship(callback, binding); } - hasData = get(relationship, 'hasData'); - members = get(relationship, 'members'); - - if (hasData) { - results = []; - members.forEach(function (member) { - if (!member.isDeleted()) { - if (ids) { - results.push(member.id); - } else { - results.push(member.createSnapshot()); - } + /** + Serializes the snapshot using the serializer for the model. + Example + ```app/adapters/application.js + import DS from 'ember-data'; + export default DS.Adapter.extend({ + createRecord(store, type, snapshot) { + var data = snapshot.serialize({ includeId: true }); + var url = `/${type.modelName}`; + return fetch(url, { + method: 'POST', + body: data, + }).then((response) => response.json()) } }); + ``` + @method serialize + @param {Object} options + @return {Object} an object whose values are primitive JSON values only + */ + }, { + key: "serialize", + value: function serialize(options) { + return this.record.store.serializerFor(this.modelName).serialize(this, options); } + }]); - if (ids) { - this._hasManyIds[keyName] = results; - } else { - this._hasManyRelationships[keyName] = results; - } + return Snapshot; + })(); - return results; - }, - - /** - Iterates through all the attributes of the model, calling the passed - function on each attribute. - Example - ```javascript - snapshot.eachAttribute(function(name, meta) { - // ... - }); - ``` - @method eachAttribute - @param {Function} callback the callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - */ - eachAttribute: function (callback, binding) { - this.record.eachAttribute(callback, binding); - }, - - /** - Iterates through all the relationships of the model, calling the passed - function on each relationship. - Example - ```javascript - snapshot.eachRelationship(function(name, relationship) { - // ... - }); - ``` - @method eachRelationship - @param {Function} callback the callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - */ - eachRelationship: function (callback, binding) { - this.record.eachRelationship(callback, binding); - }, - - /** - Serializes the snapshot using the serializer for the model. - Example - ```app/adapters/application.js - import DS from 'ember-data'; - export default DS.Adapter.extend({ - createRecord(store, type, snapshot) { - var data = snapshot.serialize({ includeId: true }); - var url = `/${type.modelName}`; - return fetch(url, { - method: 'POST', - body: data, - }).then((response) => response.json()) - } - }); - ``` - @method serialize - @param {Object} options - @return {Object} an object whose values are primitive JSON values only - */ - serialize: function (options) { - return this.record.store.serializerFor(this.modelName).serialize(this, options); - } - }; + exports.default = Snapshot; }); /** @module ember-data */ -define('ember-data/-private/system/store', ['exports', 'ember', 'ember-data/model', 'ember-data/-private/debug', 'ember-data/-private/system/normalize-model-name', 'ember-data/adapters/errors', 'ember-data/-private/system/identity-map', 'ember-data/-private/system/promise-proxies', 'ember-data/-private/system/store/common', 'ember-data/-private/system/store/serializer-response', 'ember-data/-private/system/store/serializers', 'ember-data/-private/system/store/finders', 'ember-data/-private/utils', 'ember-data/-private/system/coerce-id', 'ember-data/-private/system/record-array-manager', 'ember-data/-private/system/store/container-instance-cache', 'ember-data/-private/system/model/internal-model', 'ember-data/-private/system/empty-object', 'ember-data/-private/features'], function (exports, _ember, _emberDataModel, _emberDataPrivateDebug, _emberDataPrivateSystemNormalizeModelName, _emberDataAdaptersErrors, _emberDataPrivateSystemIdentityMap, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemStoreCommon, _emberDataPrivateSystemStoreSerializerResponse, _emberDataPrivateSystemStoreSerializers, _emberDataPrivateSystemStoreFinders, _emberDataPrivateUtils, _emberDataPrivateSystemCoerceId, _emberDataPrivateSystemRecordArrayManager, _emberDataPrivateSystemStoreContainerInstanceCache, _emberDataPrivateSystemModelInternalModel, _emberDataPrivateSystemEmptyObject, _emberDataPrivateFeatures) { +define('ember-data/-private/system/store', ['exports', 'ember', 'ember-data/-private/debug', 'ember-data/model', 'ember-data/-private/system/normalize-model-name', 'ember-data/adapters/errors', 'ember-data/-private/system/identity-map', 'ember-data/-private/system/promise-proxies', 'ember-data/-private/system/store/common', 'ember-data/-private/system/store/serializer-response', 'ember-data/-private/system/store/serializers', 'ember-data/-private/system/store/finders', 'ember-data/-private/utils', 'ember-data/-private/system/coerce-id', 'ember-data/-private/system/record-array-manager', 'ember-data/-private/system/store/container-instance-cache', 'ember-data/-private/system/model/internal-model', 'ember-data/-private/system/empty-object', 'ember-data/-private/features'], function (exports, _ember, _emberDataPrivateDebug, _emberDataModel, _emberDataPrivateSystemNormalizeModelName, _emberDataAdaptersErrors, _emberDataPrivateSystemIdentityMap, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemStoreCommon, _emberDataPrivateSystemStoreSerializerResponse, _emberDataPrivateSystemStoreSerializers, _emberDataPrivateSystemStoreFinders, _emberDataPrivateUtils, _emberDataPrivateSystemCoerceId, _emberDataPrivateSystemRecordArrayManager, _emberDataPrivateSystemStoreContainerInstanceCache, _emberDataPrivateSystemModelInternalModel, _emberDataPrivateSystemEmptyObject, _emberDataPrivateFeatures) { var badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; exports.badIdFormatAssertion = badIdFormatAssertion; var A = _ember.default.A; var Backburner = _ember.default._Backburner; @@ -9550,30 +9622,31 @@ */ init: function () { this._super.apply(this, arguments); this._backburner = new Backburner(['normalizeRelationships', 'syncRelationships', 'finished']); // internal bookkeeping; not observable - this.recordArrayManager = _emberDataPrivateSystemRecordArrayManager.default.create({ - store: this - }); + this.recordArrayManager = new _emberDataPrivateSystemRecordArrayManager.default({ store: this }); this._identityMap = new _emberDataPrivateSystemIdentityMap.default(); this._pendingSave = []; this._instanceCache = new _emberDataPrivateSystemStoreContainerInstanceCache.default((0, _emberDataPrivateUtils.getOwner)(this), this); - this._modelClassCache = new _emberDataPrivateSystemEmptyObject.default(); + this._modelFactoryCache = new _emberDataPrivateSystemEmptyObject.default(); /* Ember Data uses several specialized micro-queues for organizing and coalescing similar async work. These queues are currently controlled by a flush scheduled into ember-data's custom backburner instance. */ // used for coalescing record save requests this._pendingSave = []; + // used for coalescing relationship updates + this._updatedRelationships = []; // used for coalescing relationship setup needs this._pushedInternalModels = []; - // stores a reference to the flush for relationship setup - this._relationshipFlush = null; + // used for coalescing internal model updates + this._updatedInternalModels = []; + // used to keep track of all the find requests that need to be coalesced this._pendingFetch = MapWithDefault.create({ defaultValue: function () { return []; } }); @@ -9641,44 +9714,44 @@ Create a new record in the current store. The properties passed to this method are set on the newly created record. To create a new instance of a `Post`: ```js store.createRecord('post', { - title: "Rails is omakase" + title: 'Rails is omakase' }); ``` To create a new instance of a `Post` that has a relationship with a `User` record: ```js let user = this.store.peekRecord('user', 1); store.createRecord('post', { - title: "Rails is omakase", + title: 'Rails is omakase', user: user }); ``` @method createRecord @param {String} modelName @param {Object} inputProperties a hash of properties to set on the newly created record. @return {DS.Model} record */ createRecord: function (modelName, inputProperties) { - var trueModelName = this._classKeyFor(modelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); var properties = copy(inputProperties) || new _emberDataPrivateSystemEmptyObject.default(); // If the passed properties do not include a primary key, // give the adapter an opportunity to generate one. Typically, // client-side ID generators will use something like uuid.js // to avoid conflicts. if (isNone(properties.id)) { - properties.id = this._generateId(trueModelName, properties); + properties.id = this._generateId(normalizedModelName, properties); } // Coerce ID to a string properties.id = (0, _emberDataPrivateSystemCoerceId.default)(properties.id); - var internalModel = this.buildInternalModel(trueModelName, properties.id); + var internalModel = this.buildInternalModel(normalizedModelName, properties.id); var record = internalModel.getRecord(); // Move the record out of its initial `empty` state into // the `loaded` state. // TODO @runspired this seems really bad, store should not be changing the state @@ -9722,11 +9795,11 @@ /** For symmetry, a record can be deleted via the store. Example ```javascript let post = store.createRecord('post', { - title: "Rails is omakase" + title: 'Rails is omakase' }); store.deleteRecord(post); ``` @method deleteRecord @param {DS.Model} record @@ -9734,12 +9807,12 @@ deleteRecord: function (record) { record.deleteRecord(); }, /** - For symmetry, a record can be unloaded via the store. Only - non-dirty records can be unloaded. + For symmetry, a record can be unloaded via the store. + This will cause the record to be destroyed and freed up for garbage collection. Example ```javascript store.findRecord('post', 1).then(function(post) { store.unloadRecord(post); }); @@ -9766,13 +9839,13 @@ find: function (modelName, id, options) { // The default `model` hook in Ember.Route calls `find(modelName, id)`, // that's why we have to keep this method around even though `findRecord` is // the public way to get a record by modelName and id. - var trueModelName = this._classKeyFor(modelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); - return this.findRecord(trueModelName, id); + return this.findRecord(normalizedModelName, id); }, /** This method returns a record for a given type and id combination. The `findRecord` method will always resolve its promise with the same @@ -9781,19 +9854,34 @@ resolved with the record. Example ```app/routes/post.js import Ember from 'ember'; export default Ember.Route.extend({ - model: function(params) { + model(params) { return this.store.findRecord('post', params.post_id); } }); ``` If the record is not yet available, the store will ask the adapter's `find` method to find the necessary data. If the record is already present in the store, it depends on the reload behavior _when_ the returned promise resolves. + ### Preloading + You can optionally `preload` specific attributes and relationships that you know of + by passing them via the passed `options`. + For example, if your Ember route looks like `/posts/1/comments/2` and your API route + for the comment also looks like `/posts/1/comments/2` if you want to fetch the comment + without fetching the post you can pass in the post to the `findRecord` call: + ```javascript + store.findRecord('comment', 2, { preload: { post: 1 } }); + ``` + If you have access to the post model you can also pass the model itself: + ```javascript + store.findRecord('post', 1).then(function (myPostModel) { + store.findRecord('comment', 2, { post: myPostModel }); + }); + ``` ### Reloading The reload behavior is configured either via the passed `options` hash or the result of the adapter's `shouldReloadRecord`. If `{ reload: true }` is passed or `adapter.shouldReloadRecord` evaluates to `true`, then the returned promise resolves once the adapter returns @@ -9813,11 +9901,11 @@ // type: 'post', // revision: 2 // } // ] store.findRecord('post', 1, { reload: true }).then(function(post) { - post.get("revision"); // 2 + post.get('revision'); // 2 }); ``` If no reload is indicated via the abovementioned ways, then the promise immediately resolves with the cached version in the store. ### Background Reloading @@ -9860,31 +9948,31 @@ boolean value for `backgroundReload` in the options object for `findRecord`. ```app/routes/post/edit.js import Ember from 'ember'; export default Ember.Route.extend({ - model: function(params) { + model(params) { return this.store.findRecord('post', params.post_id, { backgroundReload: false }); } }); ``` If you pass an object on the `adapterOptions` property of the options argument it will be passed to you adapter via the snapshot ```app/routes/post/edit.js import Ember from 'ember'; export default Ember.Route.extend({ - model: function(params) { + model(params) { return this.store.findRecord('post', params.post_id, { adapterOptions: { subscribe: false } }); } }); ``` ```app/adapters/post.js import MyCustomAdapter from './custom-adapter'; export default MyCustomAdapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { if (snapshot.adapterOptions.subscribe) { // ... } // ... } @@ -9903,12 +9991,12 @@ model, when we retrieve a specific post we can have the server also return that post's comments in the same request: ```app/routes/post.js import Ember from 'ember'; export default Ember.Route.extend({ - model: function(params) { - return this.store.findRecord('post', params.post_id, {include: 'comments'}); + model(params) { + return this.store.findRecord('post', params.post_id, { include: 'comments' }); } }); ``` In this case, the post's comments would then be available in your template as `model.comments`. @@ -9917,12 +10005,12 @@ using a dot-separated sequence of relationship names. So to request both the post's comments and the authors of those comments the request would look like this: ```app/routes/post.js import Ember from 'ember'; export default Ember.Route.extend({ - model: function(params) { - return this.store.findRecord('post', params.post_id, {include: 'comments,comments.author'}); + model(params) { + return this.store.findRecord('post', params.post_id, { include: 'comments,comments.author' }); } }); ``` @since 1.13.0 @method findRecord @@ -9931,33 +10019,32 @@ @param {Object} options @return {Promise} promise */ findRecord: function (modelName, id, options) { - var trueModelName = this._classKeyFor(modelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); - var internalModel = this._internalModelForId(trueModelName, id); + var internalModel = this._internalModelForId(normalizedModelName, id); options = options || {}; - if (!this.hasRecordForId(trueModelName, id)) { + if (!this.hasRecordForId(normalizedModelName, id)) { return this._findByInternalModel(internalModel, options); } var fetchedInternalModel = this._findRecord(internalModel, options); - return promiseRecord(fetchedInternalModel, 'DS: Store#findRecord ' + trueModelName + ' with id: ' + id); + return promiseRecord(fetchedInternalModel, 'DS: Store#findRecord ' + normalizedModelName + ' with id: ' + id); }, _findRecord: function (internalModel, options) { // Refetch if the reload option is passed if (options.reload) { return this._scheduleFetch(internalModel, options); } var snapshot = internalModel.createSnapshot(options); - var modelClass = internalModel.type; - var adapter = this.adapterFor(modelClass.modelName); + var adapter = this.adapterFor(internalModel.modelName); // Refetch the record if the adapter thinks the record is stale if (adapter.shouldReloadRecord(this, snapshot)) { return this._scheduleFetch(internalModel, options); } @@ -9973,20 +10060,20 @@ // Return the cached record return Promise.resolve(internalModel); }, - _findByInternalModel: function (internalModel, options) { - options = options || {}; + _findByInternalModel: function (internalModel) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; if (options.preload) { internalModel.preloadData(options.preload); } var fetchedInternalModel = this._findEmptyInternalModel(internalModel, options); - return promiseRecord(fetchedInternalModel, "DS: Store#findRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id')); + return promiseRecord(fetchedInternalModel, 'DS: Store#findRecord ' + internalModel.modelName + ' with id: ' + internalModel.id); }, _findEmptyInternalModel: function (internalModel, options) { if (internalModel.isEmpty()) { return this._scheduleFetch(internalModel, options); @@ -10008,19 +10095,20 @@ @param {String} modelName @param {Array} ids @return {Promise} promise */ findByIds: function (modelName, ids) { + var promises = new Array(ids.length); - var trueModelName = this._classKeyFor(modelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); for (var i = 0; i < ids.length; i++) { - promises[i] = this.findRecord(trueModelName, ids[i]); + promises[i] = this.findRecord(normalizedModelName, ids[i]); } - return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)(RSVP.all(promises).then(A, null, 'DS: Store#findByIds of ' + trueModelName + ' complete')); + return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)(RSVP.all(promises).then(A, null, 'DS: Store#findByIds of ' + normalizedModelName + ' complete')); }, /** This method is called by `findRecord` if it discovers that a particular type/id pair hasn't been loaded yet to kick off a request to the @@ -10029,15 +10117,14 @@ @private @param {InternalModel} internalModel model @return {Promise} promise */ _fetchRecord: function (internalModel, options) { - var modelClass = internalModel.type; - var id = internalModel.id; - var adapter = this.adapterFor(modelClass.modelName); + var modelName = internalModel.modelName; + var adapter = this.adapterFor(modelName); - return (0, _emberDataPrivateSystemStoreFinders._find)(adapter, this, modelClass, id, internalModel, options); + return (0, _emberDataPrivateSystemStoreFinders._find)(adapter, this, internalModel.type, internalModel.id, internalModel, options); }, _scheduleFetchMany: function (internalModels) { var fetches = new Array(internalModels.length); @@ -10051,23 +10138,28 @@ _scheduleFetch: function (internalModel, options) { if (internalModel._loadingPromise) { return internalModel._loadingPromise; } - var modelClass = internalModel.type; - var resolver = RSVP.defer('Fetching ' + modelClass.modelName + ' with id: ' + internalModel.id); + var id = internalModel.id; + var modelName = internalModel.modelName; + + var resolver = RSVP.defer('Fetching ' + modelName + '\' with id: ' + id); var pendingFetchItem = { internalModel: internalModel, resolver: resolver, options: options }; + var promise = resolver.promise; internalModel.loadingData(promise); - this._pendingFetch.get(modelClass).push(pendingFetchItem); + if (this._pendingFetch.size === 0) { + emberRun.schedule('afterRender', this, this.flushAllPendingFetches); + } - emberRun.scheduleOnce('afterRender', this, this.flushAllPendingFetches); + this._pendingFetch.get(modelName).push(pendingFetchItem); return promise; }, flushAllPendingFetches: function () { @@ -10077,13 +10169,13 @@ this._pendingFetch.forEach(this._flushPendingFetchForType, this); this._pendingFetch.clear(); }, - _flushPendingFetchForType: function (pendingFetchItems, modelClass) { + _flushPendingFetchForType: function (pendingFetchItems, modelName) { var store = this; - var adapter = store.adapterFor(modelClass.modelName); + var adapter = store.adapterFor(modelName); var shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; var totalItems = pendingFetchItems.length; var internalModels = new Array(totalItems); var seeking = new _emberDataPrivateSystemEmptyObject.default(); @@ -10130,14 +10222,15 @@ } } function rejectInternalModels(internalModels, error) { for (var i = 0, l = internalModels.length; i < l; i++) { - var pair = seeking[internalModels[i].id]; + var internalModel = internalModels[i]; + var pair = seeking[internalModel.id]; if (pair) { - pair.resolver.reject(error); + pair.resolver.reject(error || new Error('Expected: \'' + internalModel + '\' to be present in the adapter provided payload, but it was not found.')); } } } if (shouldCoalesce) { @@ -10170,11 +10263,11 @@ groupedInternalModels[j] = internalModel; ids[j] = internalModel.id; } if (totalInGroup > 1) { - (0, _emberDataPrivateSystemStoreFinders._findMany)(adapter, store, modelClass, ids, groupedInternalModels).then(function (foundInternalModels) { + (0, _emberDataPrivateSystemStoreFinders._findMany)(adapter, store, modelName, ids, groupedInternalModels).then(function (foundInternalModels) { handleFoundRecords(foundInternalModels, groupedInternalModels); }).catch(function (error) { rejectInternalModels(groupedInternalModels, error); }); } else if (ids.length === 1) { @@ -10201,40 +10294,40 @@ // check if the user is loaded let isLoaded = userRef.value() !== null; // get the record of the reference (null if not yet available) let user = userRef.value(); // get the identifier of the reference - if (userRef.remoteType() === "id") { + if (userRef.remoteType() === 'id') { let id = userRef.id(); } // load user (via store.find) userRef.load().then(...) // or trigger a reload userRef.reload().then(...) // provide data for reference - userRef.push({ id: 1, username: "@user" }).then(function(user) { - userRef.value() === user; + userRef.push({ id: 1, username: '@user' }).then(function(user) { + userRef.value() === user; }); ``` @method getReference @param {String} modelName @param {String|Integer} id @since 2.5.0 @return {RecordReference} */ getReference: function (modelName, id) { - var trueModelName = this._classKeyFor(modelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); - return this._internalModelForId(trueModelName, id).recordReference; + return this._internalModelForId(normalizedModelName, id).recordReference; }, /** Get a record by a given type and ID without triggering a fetch. This method will synchronously return the record if it is available in the store, otherwise it will return `null`. A record is available if it has been fetched earlier, or pushed manually into the store. - _Note: This is an synchronous method and does not return a promise._ + _Note: This is a synchronous method and does not return a promise._ ```js let post = store.peekRecord('post', 1); post.get('id'); // 1 ``` @since 1.13.0 @@ -10242,14 +10335,14 @@ @param {String} modelName @param {String|Integer} id @return {DS.Model|null} record */ peekRecord: function (modelName, id) { - var trueModelName = this._classKeyFor(modelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); - if (this.hasRecordForId(trueModelName, id)) { - return this._internalModelForId(trueModelName, id).getRecord(); + if (this.hasRecordForId(normalizedModelName, id)) { + return this._internalModelForId(normalizedModelName, id).getRecord(); } else { return null; } }, @@ -10262,14 +10355,15 @@ @private @param {DS.Model} internalModel @return {Promise} promise */ _reloadRecord: function (internalModel) { - var modelName = internalModel.type.modelName; - var adapter = this.adapterFor(modelName); var id = internalModel.id; + var modelName = internalModel.modelName; + var adapter = this.adapterFor(modelName); + return this._scheduleFetch(internalModel); }, /** This method returns true if a record for a given modelName and id is already @@ -10277,23 +10371,24 @@ will result in a request or that it will be a cache hit. Example ```javascript store.hasRecordForId('post', 1); // false store.findRecord('post', 1).then(function() { - store.hasRecordForId('post', 1); // true - }); + store.hasRecordForId('post', 1); // true + }); ``` @method hasRecordForId @param {String} modelName @param {(String|Integer)} id @return {Boolean} */ hasRecordForId: function (modelName, id) { - var trueModelName = this._classKeyFor(modelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); + var trueId = (0, _emberDataPrivateSystemCoerceId.default)(id); - var internalModel = this._recordMapFor(trueModelName).get(trueId); + var internalModel = this._internalModelsFor(normalizedModelName).get(trueId); return !!internalModel && internalModel.isLoaded(); }, /** @@ -10304,16 +10399,17 @@ @param {String} modelName @param {(String|Integer)} id @return {DS.Model} record */ recordForId: function (modelName, id) { + return this._internalModelForId(modelName, id).getRecord(); }, _internalModelForId: function (modelName, id) { var trueId = (0, _emberDataPrivateSystemCoerceId.default)(id); - var internalModel = this._recordMapFor(modelName).get(trueId); + var internalModel = this._internalModelsFor(modelName).get(trueId); if (!internalModel) { internalModel = this.buildInternalModel(modelName, trueId); } @@ -10328,11 +10424,11 @@ */ findMany: function (internalModels) { var finds = new Array(internalModels.length); for (var i = 0; i < internalModels.length; i++) { - finds[i] = this._findByInternalModel(internalModels[i]); + finds[i] = this._findEmptyInternalModel(internalModels[i]); } return Promise.all(finds); }, @@ -10344,38 +10440,39 @@ adapter can make whatever request it wants. The usual use-case is for the server to register a URL as a link, and then use that URL in the future to make a request for the relationship. @method findHasMany @private - @param {DS.Model} owner + @param {InternalModel} internalModel @param {any} link @param {(Relationship)} relationship @return {Promise} promise */ - findHasMany: function (owner, link, relationship) { - var adapter = this.adapterFor(owner.type.modelName); + findHasMany: function (internalModel, link, relationship) { + var adapter = this.adapterFor(internalModel.modelName); - return (0, _emberDataPrivateSystemStoreFinders._findHasMany)(adapter, this, owner, link, relationship); + return (0, _emberDataPrivateSystemStoreFinders._findHasMany)(adapter, this, internalModel, link, relationship); }, /** @method findBelongsTo @private - @param {DS.Model} owner + @param {InternalModel} internalModel @param {any} link @param {Relationship} relationship @return {Promise} promise */ - findBelongsTo: function (owner, link, relationship) { - var adapter = this.adapterFor(owner.type.modelName); + findBelongsTo: function (internalModel, link, relationship) { + var adapter = this.adapterFor(internalModel.modelName); - return (0, _emberDataPrivateSystemStoreFinders._findBelongsTo)(adapter, this, owner, link, relationship); + return (0, _emberDataPrivateSystemStoreFinders._findBelongsTo)(adapter, this, internalModel, link, relationship); }, /** This method delegates a query to the adapter. This is the one place where adapter-level semantics are exposed to the application. + Each time this method is called a new request is made through the adapter. Exposing queries this way seems preferable to creating an abstract query language for all server-side queries, and then require all adapters to implement them. --- If you do something like this: @@ -10408,22 +10505,21 @@ @param {any} query an opaque query to be used by the adapter @return {Promise} promise */ query: function (modelName, query) { - var trueModelName = this._classKeyFor(modelName); - return this._query(trueModelName, query); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); + return this._query(normalizedModelName, query); }, _query: function (modelName, query, array) { - var modelClass = this._modelFor(modelName); array = array || this.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); var adapter = this.adapterFor(modelName); - var pA = (0, _emberDataPrivateSystemPromiseProxies.promiseArray)((0, _emberDataPrivateSystemStoreFinders._query)(adapter, this, modelClass, query, array)); + var pA = (0, _emberDataPrivateSystemPromiseProxies.promiseArray)((0, _emberDataPrivateSystemStoreFinders._query)(adapter, this, modelName, query, array)); return pA; }, /** @@ -10451,14 +10547,14 @@ console.log(`Currently logged in as ${username}`); }); ``` The request is made through the adapters' `queryRecord`: ```app/adapters/user.js - import DS from "ember-data"; + import DS from 'ember-data'; export default DS.Adapter.extend({ queryRecord(modelName, query) { - return Ember.$.getJSON("/api/current_user"); + return Ember.$.getJSON('/api/current_user'); } }); ``` Note: the primary use case for `store.queryRecord` is when a single record is queried and the `id` is not known beforehand. In all other cases @@ -10502,16 +10598,16 @@ @param {String} modelName @param {any} query an opaque query to be used by the adapter @return {Promise} promise which resolves with the found record or `null` */ queryRecord: function (modelName, query) { - var trueModelName = this._classKeyFor(modelName); - var modelClass = this._modelFor(trueModelName); - var adapter = this.adapterFor(trueModelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); - return (0, _emberDataPrivateSystemPromiseProxies.promiseObject)((0, _emberDataPrivateSystemStoreFinders._queryRecord)(adapter, this, modelClass, query).then(function (internalModel) { + var adapter = this.adapterFor(normalizedModelName); + + return (0, _emberDataPrivateSystemPromiseProxies.promiseObject)((0, _emberDataPrivateSystemStoreFinders._queryRecord)(adapter, this, modelName, query).then(function (internalModel) { // the promise returned by store.queryRecord is expected to resolve with // an instance of DS.Model if (internalModel) { return internalModel.getRecord(); } @@ -10526,11 +10622,11 @@ this type present in the store, even if the adapter only returns a subset of them. ```app/routes/authors.js import Ember from 'ember'; export default Ember.Route.extend({ - model: function(params) { + model(params) { return this.store.findAll('author'); } }); ``` _When_ the returned promise resolves depends on the reload behavior, @@ -10553,11 +10649,11 @@ // id: 'second', // type: 'author' // } // ] store.findAll('author', { reload: true }).then(function(authors) { - authors.getEach("id"); // ['first', 'second'] + authors.getEach('id'); // ['first', 'second'] }); ``` If no reload is indicated via the abovementioned ways, then the promise immediately resolves with all the records currently loaded in the store. ### Background Reloading @@ -10600,31 +10696,31 @@ boolean value for `backgroundReload` in the options object for `findAll`. ```app/routes/post/edit.js import Ember from 'ember'; export default Ember.Route.extend({ - model: function() { + model() { return this.store.findAll('post', { backgroundReload: false }); } }); ``` If you pass an object on the `adapterOptions` property of the options argument it will be passed to you adapter via the `snapshotRecordArray` ```app/routes/posts.js import Ember from 'ember'; export default Ember.Route.extend({ - model: function(params) { + model(params) { return this.store.findAll('post', { adapterOptions: { subscribe: false } }); } }); ``` ```app/adapters/post.js import MyCustomAdapter from './custom-adapter'; export default MyCustomAdapter.extend({ - findAll: function(store, type, sinceToken, snapshotRecordArray) { + findAll(store, type, sinceToken, snapshotRecordArray) { if (snapshotRecordArray.adapterOptions.subscribe) { // ... } // ... } @@ -10644,24 +10740,24 @@ model, when we retrieve all of the post records we can have the server also return all of the posts' comments in the same request: ```app/routes/posts.js import Ember from 'ember'; export default Ember.Route.extend({ - model: function() { - return this.store.findAll('post', {include: 'comments'}); + model() { + return this.store.findAll('post', { include: 'comments' }); } }); ``` Multiple relationships can be requested using an `include` parameter consisting of a comma-separated list (without white-space) while nested relationships can be specified using a dot-separated sequence of relationship names. So to request both the posts' comments and the authors of those comments the request would look like this: ```app/routes/posts.js import Ember from 'ember'; export default Ember.Route.extend({ - model: function() { - return this.store.findAll('post', {include: 'comments,comments.author'}); + model() { + return this.store.findAll('post', { include: 'comments,comments.author' }); } }); ``` See [query](#method_query) to only get a subset of records from the server. @since 1.13.0 @@ -10669,50 +10765,48 @@ @param {String} modelName @param {Object} options @return {Promise} promise */ findAll: function (modelName, options) { - var trueModelName = this._classKeyFor(modelName); - var modelClass = this._modelFor(trueModelName); - var fetch = this._fetchAll(modelClass, this.peekAll(trueModelName), options); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); + var fetch = this._fetchAll(normalizedModelName, this.peekAll(normalizedModelName), options); return fetch; }, /** @method _fetchAll @private - @param {DS.Model} modelClass + @param {DS.Model} modelName @param {DS.RecordArray} array @return {Promise} promise */ - _fetchAll: function (modelClass, array, options) { - options = options || {}; + _fetchAll: function (modelName, array) { + var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; - var modelName = modelClass.modelName; var adapter = this.adapterFor(modelName); - var sinceToken = this._recordMapFor(modelName).metadata.since; + var sinceToken = this._internalModelsFor(modelName).metadata.since; if (options.reload) { set(array, 'isUpdating', true); - return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)((0, _emberDataPrivateSystemStoreFinders._findAll)(adapter, this, modelClass, sinceToken, options)); + return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)((0, _emberDataPrivateSystemStoreFinders._findAll)(adapter, this, modelName, sinceToken, options)); } var snapshotArray = array._createSnapshot(options); if (adapter.shouldReloadAll(this, snapshotArray)) { set(array, 'isUpdating', true); - return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)((0, _emberDataPrivateSystemStoreFinders._findAll)(adapter, this, modelClass, sinceToken, options)); + return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)((0, _emberDataPrivateSystemStoreFinders._findAll)(adapter, this, modelName, sinceToken, options)); } if (options.backgroundReload === false) { return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)(Promise.resolve(array)); } if (options.backgroundReload || adapter.shouldBackgroundReloadAll(this, snapshotArray)) { set(array, 'isUpdating', true); - (0, _emberDataPrivateSystemStoreFinders._findAll)(adapter, this, modelClass, sinceToken, options); + (0, _emberDataPrivateSystemStoreFinders._findAll)(adapter, this, modelName, sinceToken, options); } return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)(Promise.resolve(array)); }, @@ -10745,14 +10839,14 @@ @method peekAll @param {String} modelName @return {DS.RecordArray} */ peekAll: function (modelName) { - var trueModelName = this._classKeyFor(modelName); - var liveRecordArray = this.recordArrayManager.liveRecordArrayFor(trueModelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); + var liveRecordArray = this.recordArrayManager.liveRecordArrayFor(normalizedModelName); - this.recordArrayManager.syncLiveRecordArray(liveRecordArray, trueModelName); + this.recordArrayManager.syncLiveRecordArray(liveRecordArray, normalizedModelName); return liveRecordArray; }, /** @@ -10769,12 +10863,12 @@ unloadAll: function (modelName) { if (arguments.length === 0) { this._identityMap.clear(); } else { - var trueModelName = this._classKeyFor(modelName); - this._recordMapFor(trueModelName).clear(); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); + this._internalModelsFor(normalizedModelName).clear(); } }, /** Takes a type and filter function, and returns a live RecordArray that @@ -10827,30 +10921,30 @@ var promise = undefined; var length = arguments.length; var array = undefined; var hasQuery = length === 3; - var trueModelName = this._classKeyFor(modelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); // allow an optional server query if (hasQuery) { - promise = this.query(trueModelName, query); + promise = this.query(normalizedModelName, query); } else if (arguments.length === 2) { filter = query; } if (hasQuery) { - array = this.recordArrayManager.createFilteredRecordArray(trueModelName, filter, query); + array = this.recordArrayManager.createFilteredRecordArray(normalizedModelName, filter, query); } else { - array = this.recordArrayManager.createFilteredRecordArray(trueModelName, filter); + array = this.recordArrayManager.createFilteredRecordArray(normalizedModelName, filter); } promise = promise || Promise.resolve(array); return (0, _emberDataPrivateSystemPromiseProxies.promiseArray)(promise.then(function () { return array; - }, null, 'DS: Store#filter of ' + trueModelName)); + }, null, 'DS: Store#filter of ' + normalizedModelName)); }, /** This method has been deprecated and is an alias for store.hasRecordForId, which should be used instead. @@ -10862,27 +10956,10 @@ */ recordIsLoaded: function (modelName, id) { return this.hasRecordForId(modelName, id); }, - // ............ - // . UPDATING . - // ............ - - /** - If the adapter updates attributes the record will notify - the store to update its membership in any filters. - To avoid thrashing, this method is invoked only once per - run loop per record. - @method _dataWasUpdated - @private - @param {InternalModel} internalModel - */ - _dataWasUpdated: function (internalModel) { - this.recordArrayManager.recordDidChange(internalModel); - }, - // .............. // . PERSISTING . // .............. /** @@ -10919,14 +10996,14 @@ for (var i = 0, j = pending.length; i < j; i++) { var pendingItem = pending[i]; var snapshot = pendingItem.snapshot; var resolver = pendingItem.resolver; var internalModel = snapshot._internalModel; - var adapter = this.adapterFor(internalModel.modelClass.modelName); + var adapter = this.adapterFor(internalModel.modelName); var operation = undefined; - if (get(internalModel, 'currentState.stateName') === 'root.deleted.saved') { + if (internalModel.currentState.stateName === 'root.deleted.saved') { return resolver.resolve(); } else if (internalModel.isNew()) { operation = 'createRecord'; } else if (internalModel.isDeleted()) { operation = 'deleteRecord'; @@ -11000,10 +11077,11 @@ @param {InternalModel} internalModel @param {Object} data */ updateId: function (internalModel, data) { var oldId = internalModel.id; + var modelName = internalModel.modelName; var id = (0, _emberDataPrivateSystemCoerceId.default)(data.id); // ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record) // ID absolutely can't be different than oldID if oldID is not null @@ -11012,35 +11090,23 @@ // however, this is more than likely a developer error. if (oldId !== null && id === null) { return; } - this._recordMapFor(internalModel.modelName).set(id, internalModel); + this._internalModelsFor(internalModel.modelName).set(id, internalModel); internalModel.setId(id); }, /** - Returns the normalized (dasherized) modelName. This method should be used whenever - receiving a modelName in a public method. - @method _classKeyFor - @param {String} modelName - @returns {String} - @private - */ - _classKeyFor: function (modelName) { - return (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); - }, - - /** Returns a map of IDs to client IDs for a given modelName. - @method _recordMapFor + @method _internalModelsFor @private @param {String} modelName @return {Object} recordMap */ - _recordMapFor: function (modelName) { + _internalModelsFor: function (modelName) { return this._identityMap.retrieve(modelName); }, // ................ // . LOADING DATA . @@ -11053,11 +11119,10 @@ @param {Object} data */ _load: function (data) { var internalModel = this._internalModelForId(data.type, data.id); - // TODO @runspired move this out of here internalModel.setupData(data); this.recordArrayManager.recordDidChange(internalModel); return internalModel; @@ -11065,11 +11130,11 @@ /* In case someone defined a relationship to a mixin, for example: ``` let Comment = DS.Model.extend({ - owner: belongsTo('commentable'. { polymorphic: true}) + owner: belongsTo('commentable'. { polymorphic: true }) }); let Commentable = Ember.Mixin.create({ comments: hasMany('comment') }); ``` @@ -11077,12 +11142,11 @@ relationship metadata. Thus, we look up the mixin and create a mock DS.Model, so we can access the relationship CPs of the mixin (`comments`) in this case @private */ - _modelForMixin: function (modelName) { - var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); + _modelForMixin: function (normalizedModelName) { // container.registry = 2.1 // container._registry = 1.11 - 2.0 // container = < 1.11 var owner = (0, _emberDataPrivateUtils.getOwner)(this); var mixin = undefined; @@ -11118,13 +11182,13 @@ @param {String} modelName @return {DS.Model} */ modelFor: function (modelName) { - var trueModelName = this._classKeyFor(modelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); - return this._modelFor(trueModelName); + return this._modelFor(normalizedModelName); }, /* @private */ @@ -11133,11 +11197,11 @@ // for factorFor factory/class split return maybeFactory.class ? maybeFactory.class : maybeFactory; }, _modelFactoryFor: function (modelName) { - var factory = this._modelClassCache[modelName]; + var factory = this._modelFactoryCache[modelName]; if (!factory) { factory = this.modelFactoryFor(modelName); if (!factory) { @@ -11152,27 +11216,28 @@ var klass = (0, _emberDataPrivateUtils.getOwner)(this).factoryFor ? factory.class : factory; // TODO: deprecate this klass.modelName = klass.modelName || modelName; - this._modelClassCache[modelName] = factory; + this._modelFactoryCache[modelName] = factory; } return factory; }, /* @private */ modelFactoryFor: function (modelName) { - var trueModelName = this._classKeyFor(modelName); + + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); var owner = (0, _emberDataPrivateUtils.getOwner)(this); if (owner.factoryFor) { - return owner.factoryFor('model:' + trueModelName); + return owner.factoryFor('model:' + normalizedModelName); } else { - return owner._lookupFactory('model:' + trueModelName); + return owner._lookupFactory('model:' + normalizedModelName); } }, /** Push some data for a given type into the store. @@ -11365,10 +11430,11 @@ return internalModelOrModels; }, _hasModelFor: function (modelName) { var owner = (0, _emberDataPrivateUtils.getOwner)(this); + modelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); if (owner.factoryFor) { return !!owner.factoryFor('model:' + modelName); } else { return !!owner._lookupFactory('model:' + modelName); @@ -11385,29 +11451,30 @@ return internalModel; }, _setupRelationshipsForModel: function (internalModel, data) { - this._pushedInternalModels.push(internalModel, data); - if (this._relationshipFlush === null) { - this._relationshipFlush = this._backburner.schedule('normalizeRelationships', this, this._setupRelationships); + if (this._pushedInternalModels.push(internalModel, data) !== 2) { + return; } + + this._backburner.schedule('normalizeRelationships', this, this._setupRelationships); }, _setupRelationships: function () { var pushed = this._pushedInternalModels; - this._pushedInternalModels = []; - this._relationshipFlush = null; for (var i = 0, l = pushed.length; i < l; i += 2) { // This will convert relationships specified as IDs into DS.Model instances // (possibly unloaded) and also create the data structures used to track // relationships. var internalModel = pushed[i]; var data = pushed[i + 1]; setupRelationships(this, internalModel, data); } + + pushed.length = 0; }, /** Push some raw data into the store. This method can be used both to push in brand new @@ -11457,14 +11524,14 @@ payload = modelName; serializer = defaultSerializer(this); } else { payload = inputPayload; - var trueModelName = this._classKeyFor(modelName); - serializer = this.serializerFor(trueModelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); + serializer = this.serializerFor(normalizedModelName); } - if (false) { + if ((0, _emberDataPrivateFeatures.default)('ds-pushpayload-return')) { return serializer.pushPayload(this, payload); } else { serializer.pushPayload(this, payload); } }, @@ -11484,13 +11551,13 @@ @param {String} modelName The name of the model type for this payload @param {Object} payload @return {Object} The normalized payload */ normalize: function (modelName, payload) { - var trueModelName = this._classKeyFor(modelName); - var serializer = this.serializerFor(trueModelName); - var model = this._modelFor(trueModelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); + var serializer = this.serializerFor(normalizedModelName); + var model = this._modelFor(normalizedModelName); return serializer.normalize(model, payload); }, /** Build a brand new record for a given type, ID, and @@ -11502,11 +11569,11 @@ @param {Object} data @return {InternalModel} internal model */ buildInternalModel: function (modelName, id, data) { - var recordMap = this._recordMapFor(modelName); + var recordMap = this._internalModelsFor(modelName); // lookupFactory should really return an object that creates // instances with the injections applied var internalModel = new _emberDataPrivateSystemModelInternalModel.default(modelName, id, this, data); @@ -11525,20 +11592,18 @@ // ............... /** When a record is destroyed, this un-indexes it and removes it from any record arrays so it can be GCed. - @method _dematerializeRecord + @method _removeFromIdMap @private @param {InternalModel} internalModel */ - _dematerializeRecord: function (internalModel) { - var recordMap = this._recordMapFor(internalModel.modelName); + _removeFromIdMap: function (internalModel) { + var recordMap = this._internalModelsFor(internalModel.modelName); var id = internalModel.id; - internalModel.updateRecordArrays(); - recordMap.remove(internalModel, id); }, // ...................... // . PER-TYPE ADAPTERS @@ -11557,13 +11622,13 @@ @public @param {String} modelName @return DS.Adapter */ adapterFor: function (modelName) { - var trueModelName = this._classKeyFor(modelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); - return this._instanceCache.get('adapter', trueModelName); + return this._instanceCache.get('adapter', normalizedModelName); }, // .............................. // . RECORD CHANGE NOTIFICATION . // .............................. @@ -11584,13 +11649,13 @@ @public @param {String} modelName the record to serialize @return {DS.Serializer} */ serializerFor: function (modelName) { - var trueModelName = this._classKeyFor(modelName); + var normalizedModelName = (0, _emberDataPrivateSystemNormalizeModelName.default)(modelName); - return this._instanceCache.get('serializer', trueModelName); + return this._instanceCache.get('serializer', normalizedModelName); }, lookupAdapter: function (name) { return this.adapterFor(name); }, @@ -11600,18 +11665,56 @@ }, willDestroy: function () { this._super.apply(this, arguments); this._pushedInternalModels = null; - this._backburner.cancel(this._relationshipFlush); - this._relationshipFlush = null; this.recordArrayManager.destroy(); this._instanceCache.destroy(); this.unloadAll(); }, + _updateRelationshipState: function (relationship) { + var _this2 = this; + + if (this._updatedRelationships.push(relationship) !== 1) { + return; + } + + this._backburner.join(function () { + _this2._backburner.schedule('syncRelationships', _this2, _this2._flushUpdatedRelationships); + }); + }, + + _flushUpdatedRelationships: function () { + var updated = this._updatedRelationships; + + for (var i = 0, l = updated.length; i < l; i++) { + updated[i].flushCanonical(); + } + + updated.length = 0; + }, + + _updateInternalModel: function (internalModel) { + if (this._updatedInternalModels.push(internalModel) !== 1) { + return; + } + + emberRun.schedule('actions', this, this._flushUpdatedInternalModels); + }, + + _flushUpdatedInternalModels: function () { + var updated = this._updatedInternalModels; + + for (var i = 0, l = updated.length; i < l; i++) { + updated[i]._triggerDeferredTriggers(); + } + + updated.length = 0; + }, + _pushResourceIdentifier: function (relationship, resourceIdentifier) { if (isNone(resourceIdentifier)) { return; } @@ -11774,12 +11877,10 @@ * */ var ContainerInstanceCache = (function () { function ContainerInstanceCache(owner, store) { - this.isDestroying = false; - this.isDestroyed = false; this._owner = owner; this._store = store; this._namespaces = { adapter: new _emberDataPrivateSystemEmptyObject.default(), serializer: new _emberDataPrivateSystemEmptyObject.default() @@ -11855,14 +11956,15 @@ } } }, { key: 'destroy', value: function destroy() { - this.isDestroying = true; this.destroyCache(this._namespaces.adapter); this.destroyCache(this._namespaces.serializer); - this.isDestroyed = true; + this._namespaces = null; + this._store = null; + this._owner = null; } }, { key: 'toString', value: function toString() { return 'ContainerInstanceCache'; @@ -11881,11 +11983,10 @@ exports._findHasMany = _findHasMany; exports._findBelongsTo = _findBelongsTo; exports._findAll = _findAll; exports._query = _query; exports._queryRecord = _queryRecord; - var Promise = _ember.default.RSVP.Promise; function payloadIsNotBlank(adapterPayload) { if (Array.isArray(adapterPayload)) { return true; @@ -11894,13 +11995,15 @@ } } function _find(adapter, store, modelClass, id, internalModel, options) { var snapshot = internalModel.createSnapshot(options); + var modelName = internalModel.modelName; + var promise = adapter.findRecord(store, modelClass, id, snapshot); - var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, internalModel.type.modelName); - var label = "DS: Handle Adapter#findRecord of " + modelClass + " with id: " + id; + var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, modelName); + var label = "DS: Handle Adapter#findRecord of '" + modelName + "' with id: '" + id + "'"; promise = Promise.resolve(promise, label); promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, store)); return promise.then(function (adapterPayload) { @@ -11912,18 +12015,19 @@ if (internalModel.isEmpty()) { internalModel.unloadRecord(); } throw error; - }, "DS: Extract payload of '" + modelClass + "'"); + }, "DS: Extract payload of '" + modelName + "'"); } - function _findMany(adapter, store, modelClass, ids, internalModels) { + function _findMany(adapter, store, modelName, ids, internalModels) { var snapshots = _ember.default.A(internalModels).invoke('createSnapshot'); + var modelClass = store.modelFor(modelName); // `adapter.findMany` gets the modelClass still var promise = adapter.findMany(store, modelClass, ids, snapshots); - var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, modelClass.modelName); - var label = "DS: Handle Adapter#findMany of " + modelClass; + var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, modelName); + var label = "DS: Handle Adapter#findMany of '" + modelName + "'"; if (promise === undefined) { throw new Error('adapter.findMany returned undefined, this was very likely a mistake'); } @@ -11931,19 +12035,19 @@ promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, store)); return promise.then(function (adapterPayload) { var payload = (0, _emberDataPrivateSystemStoreSerializerResponse.normalizeResponseHelper)(serializer, store, modelClass, adapterPayload, null, 'findMany'); return store._push(payload); - }, null, "DS: Extract payload of " + modelClass); + }, null, "DS: Extract payload of " + modelName); } function _findHasMany(adapter, store, internalModel, link, relationship) { var snapshot = internalModel.createSnapshot(); var modelClass = store.modelFor(relationship.type); var promise = adapter.findHasMany(store, snapshot, link, relationship); var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, relationship.type); - var label = "DS: Handle Adapter#findHasMany of " + internalModel + " : " + relationship.type; + var label = "DS: Handle Adapter#findHasMany of '" + internalModel.modelName + "' : '" + relationship.type + "'"; promise = Promise.resolve(promise, label); promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, store)); promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, internalModel)); @@ -11951,19 +12055,19 @@ var payload = (0, _emberDataPrivateSystemStoreSerializerResponse.normalizeResponseHelper)(serializer, store, modelClass, adapterPayload, null, 'findHasMany'); var internalModelArray = store._push(payload); internalModelArray.meta = payload.meta; return internalModelArray; - }, null, "DS: Extract payload of " + internalModel + " : hasMany " + relationship.type); + }, null, "DS: Extract payload of '" + internalModel.modelName + "' : hasMany '" + relationship.type + "'"); } function _findBelongsTo(adapter, store, internalModel, link, relationship) { var snapshot = internalModel.createSnapshot(); var modelClass = store.modelFor(relationship.type); var promise = adapter.findBelongsTo(store, snapshot, link, relationship); var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, relationship.type); - var label = "DS: Handle Adapter#findBelongsTo of " + internalModel + " : " + relationship.type; + var label = "DS: Handle Adapter#findBelongsTo of " + internalModel.modelName + " : " + relationship.type; promise = Promise.resolve(promise, label); promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, store)); promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, internalModel)); @@ -11973,15 +12077,15 @@ if (!payload.data) { return null; } return store._push(payload); - }, null, "DS: Extract payload of " + internalModel + " : " + relationship.type); + }, null, "DS: Extract payload of " + internalModel.modelName + " : " + relationship.type); } - function _findAll(adapter, store, modelClass, sinceToken, options) { - var modelName = modelClass.modelName; + function _findAll(adapter, store, modelName, sinceToken, options) { + var modelClass = store.modelFor(modelName); // adapter.findAll depends on the class var recordArray = store.peekAll(modelName); var snapshotArray = recordArray._createSnapshot(options); var promise = adapter.findAll(store, modelClass, sinceToken, snapshotArray); var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, modelName); var label = "DS: Handle Adapter#findAll of " + modelClass; @@ -11994,20 +12098,20 @@ store._push(payload); store.didUpdateAll(modelName); return store.peekAll(modelName); - }, null, "DS: Extract payload of findAll " + modelClass); + }, null, 'DS: Extract payload of findAll ${modelName}'); } - function _query(adapter, store, modelClass, query, recordArray) { - var modelName = modelClass.modelName; + function _query(adapter, store, modelName, query, recordArray) { + var modelClass = store.modelFor(modelName); // adapter.query needs the class var promise = adapter.query(store, modelClass, query, recordArray); var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, modelName); - var label = 'DS: Handle Adapter#query of ' + modelClass; + var label = "DS: Handle Adapter#query of " + modelClass; promise = Promise.resolve(promise, label); promise = (0, _emberDataPrivateSystemStoreCommon._guard)(promise, (0, _emberDataPrivateSystemStoreCommon._bind)(_emberDataPrivateSystemStoreCommon._objectIsAlive, store)); return promise.then(function (adapterPayload) { @@ -12016,15 +12120,15 @@ var internalModels = store._push(payload); recordArray._setInternalModels(internalModels, payload); return recordArray; - }, null, 'DS: Extract payload of query ' + modelName); + }, null, "DS: Extract payload of query " + modelName); } - function _queryRecord(adapter, store, modelClass, query) { - var modelName = modelClass.modelName; + function _queryRecord(adapter, store, modelName, query) { + var modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class var promise = adapter.queryRecord(store, modelClass, query); var serializer = (0, _emberDataPrivateSystemStoreSerializers.serializerForAdapter)(store, adapter, modelName); var label = "DS: Handle Adapter#queryRecord of " + modelName; promise = Promise.resolve(promise, label); @@ -12120,15 +12224,15 @@ } }); define("ember-data/-private/system/store/serializers", ["exports"], function (exports) { exports.serializerForAdapter = serializerForAdapter; - function serializerForAdapter(store, adapter, type) { + function serializerForAdapter(store, adapter, modelName) { var serializer = adapter.serializer; if (serializer === undefined) { - serializer = store.serializerFor(type); + serializer = store.serializerFor(modelName); } if (serializer === null || serializer === undefined) { serializer = { extract: function (store, type, payload) { @@ -12293,11 +12397,11 @@ @extends DS.Transform @namespace DS */ exports.default = _emberDataTransform.default.extend({ deserialize: function (serialized) { - var transformed; + var transformed = undefined; if (empty(serialized)) { return null; } else { transformed = Number(serialized); @@ -12305,11 +12409,11 @@ return isNumber(transformed) ? transformed : null; } }, serialize: function (deserialized) { - var transformed; + var transformed = undefined; if (empty(deserialized)) { return null; } else { transformed = Number(deserialized); @@ -12372,11 +12476,11 @@ ember-container-inject-owner is a new feature in Ember 2.3 that finally provides a public API for looking items up. This function serves as a super simple polyfill to avoid triggering deprecations. */ function getOwner(context) { - var owner; + var owner = undefined; if (_ember.default.getOwner) { owner = _ember.default.getOwner(context); } else if (context.container) { owner = context.container; @@ -12518,14 +12622,15 @@ should query your persistence layer for a record with the given ID. The `findRecord` method should return a promise that will resolve to a JavaScript object that will be normalized by the serializer. Here is an example `findRecord` implementation: ```app/adapters/application.js + import Ember from 'ember'; import DS from 'ember-data'; export default DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { - return new Ember.RSVP.Promise(function(resolve, reject) { + findRecord(store, type, id, snapshot) { + return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.getJSON(`/${type.modelName}/${id}`).then(function(data) { resolve(data); }, function(jqXHR) { reject(jqXHR); }); @@ -12544,15 +12649,16 @@ /** The `findAll()` method is used to retrieve all records for a given type. Example ```app/adapters/application.js + import Ember from 'ember'; import DS from 'ember-data'; export default DS.Adapter.extend({ - findAll: function(store, type, sinceToken) { - var query = { since: sinceToken }; - return new Ember.RSVP.Promise(function(resolve, reject) { + findAll(store, type, sinceToken) { + let query = { since: sinceToken }; + return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { resolve(data); }, function(jqXHR) { reject(jqXHR); }); @@ -12571,13 +12677,14 @@ /** This method is called when you call `query` on the store. Example ```app/adapters/application.js + import Ember from 'ember'; import DS from 'ember-data'; export default DS.Adapter.extend({ - query: function(store, type, query) { + query(store, type, query) { return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { resolve(data); }, function(jqXHR) { reject(jqXHR); @@ -12602,14 +12709,14 @@ data. Once found, you can asynchronously call the store's `push()` method to push the record into the store. Here is an example `queryRecord` implementation: Example ```app/adapters/application.js - import DS from 'ember-data'; import Ember from 'ember'; + import DS from 'ember-data'; export default DS.Adapter.extend(DS.BuildURLMixin, { - queryRecord: function(store, type, query) { + queryRecord(store, type, query) { return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { resolve(data); }, function(jqXHR) { reject(jqXHR); @@ -12639,11 +12746,11 @@ the first parameter and the newly created record as the second parameter: ```javascript import DS from 'ember-data'; import { v4 } from 'uuid'; export default DS.Adapter.extend({ - generateIdForRecord: function(store, inputProperties) { + generateIdForRecord(store, inputProperties) { return v4(); } }); ``` @method generateIdForRecord @@ -12659,13 +12766,13 @@ Proxies to the serializer's `serialize` method. Example ```app/adapters/application.js import DS from 'ember-data'; export default DS.Adapter.extend({ - createRecord: function(store, type, snapshot) { - var data = this.serialize(snapshot, { includeId: true }); - var url = `/${type.modelName}`; + createRecord(store, type, snapshot) { + let data = this.serialize(snapshot, { includeId: true }); + let url = `/${type.modelName}`; // ... } }); ``` @method serialize @@ -12681,14 +12788,15 @@ Implement this method in a subclass to handle the creation of new records. Serializes the record and sends it to the server. Example ```app/adapters/application.js + import Ember from 'ember'; import DS from 'ember-data'; export default DS.Adapter.extend({ - createRecord: function(store, type, snapshot) { - var data = this.serialize(snapshot, { includeId: true }); + createRecord(store, type, snapshot) { + let data = this.serialize(snapshot, { includeId: true }); return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.ajax({ type: 'POST', url: `/${type.modelName}`, dataType: 'json', @@ -12722,15 +12830,16 @@ the updateRecord promise can also resolve with `undefined` and the Ember Data store will assume all of the updates were successfully applied on the backend. Example ```app/adapters/application.js + import Ember from 'ember'; import DS from 'ember-data'; export default DS.Adapter.extend({ - updateRecord: function(store, type, snapshot) { - var data = this.serialize(snapshot, { includeId: true }); - var id = snapshot.id; + updateRecord(store, type, snapshot) { + let data = this.serialize(snapshot, { includeId: true }); + let id = snapshot.id; return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.ajax({ type: 'PUT', url: `/${type.modelName}/${id}`, dataType: 'json', @@ -12757,15 +12866,16 @@ Implement this method in a subclass to handle the deletion of a record. Sends a delete request for the record to the server. Example ```app/adapters/application.js + import Ember from 'ember'; import DS from 'ember-data'; export default DS.Adapter.extend({ - deleteRecord: function(store, type, snapshot) { - var data = this.serialize(snapshot, { includeId: true }); - var id = snapshot.id; + deleteRecord(store, type, snapshot) { + let data = this.serialize(snapshot, { includeId: true }); + let id = snapshot.id; return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.ajax({ type: 'DELETE', url: `/${type.modelName}/${id}`, dataType: 'json', @@ -12801,10 +12911,11 @@ /** The store will call `findMany` instead of multiple `findRecord` requests to find multiple records at once if coalesceFindRequests is true. ```app/adapters/application.js + import Ember from 'ember'; import DS from 'ember-data'; export default DS.Adapter.extend({ findMany(store, type, ids, snapshots) { return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.ajax({ @@ -12857,13 +12968,14 @@ For example, if you are building an events ticketing system, in which users can only reserve tickets for 20 minutes at a time, and want to ensure that in each route you have data that is no more than 20 minutes old you could write: ```javascript - shouldReloadRecord: function(store, ticketSnapshot) { - var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt'), 'minutes'); - if (timeDiff > 20) { + shouldReloadRecord(store, ticketSnapshot) { + let lastAccessedAt = ticketSnapshot.attr('lastAccessedAt'); + let timeDiff = moment().diff(lastAccessedAt, 'minutes'); + if (timeDiff > 20) { return true; } else { return false; } } @@ -12898,15 +13010,16 @@ For example, if you are building an events ticketing system, in which users can only reserve tickets for 20 minutes at a time, and want to ensure that in each route you have data that is no more than 20 minutes old you could write: ```javascript - shouldReloadAll: function(store, snapshotArray) { - var snapshots = snapshotArray.snapshots(); - return snapshots.any(function(ticketSnapshot) { - var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt'), 'minutes'); - if (timeDiff > 20) { + shouldReloadAll(store, snapshotArray) { + let snapshots = snapshotArray.snapshots(); + return snapshots.any((ticketSnapshot) => { + let lastAccessedAt = ticketSnapshot.attr('lastAccessedAt'); + let timeDiff = moment().diff(lastAccessedAt, 'minutes'); + if (timeDiff > 20) { return true; } else { return false; } }); @@ -12943,13 +13056,13 @@ the adapter. For example, if you do not want to fetch complex data over a mobile connection, or if the network is down, you can implement `shouldBackgroundReloadRecord` as follows: ```javascript - shouldBackgroundReloadRecord: function(store, snapshot) { - var connection = window.navigator.connection; - if (connection === 'cellular' || connection === 'none') { + shouldBackgroundReloadRecord(store, snapshot) { + let connection = window.navigator.connection; + if (connection === 'cellular' || connection === 'none') { return false; } else { return true; } } @@ -12976,13 +13089,13 @@ from the adapter. For example, if you do not want to fetch complex data over a mobile connection, or if the network is down, you can implement `shouldBackgroundReloadAll` as follows: ```javascript - shouldBackgroundReloadAll: function(store, snapshotArray) { - var connection = window.navigator.connection; - if (connection === 'cellular' || connection === 'none') { + shouldBackgroundReloadAll(store, snapshotArray) { + let connection = window.navigator.connection; + if (connection === 'cellular' || connection === 'none') { return false; } else { return true; } } @@ -13093,11 +13206,11 @@ detail: message }]; } var extendedErrorsEnabled = false; - if (false) { + if (true) { extendedErrorsEnabled = true; } function extendFn(ErrorClass) { return function () { @@ -13159,11 +13272,11 @@ ```app/adapters/post.js import Ember from 'ember'; import DS from 'ember-data'; export default DS.RESTAdapter.extend({ - updateRecord: function() { + updateRecord() { // Fictional adapter that always rejects return Ember.RSVP.reject(new DS.InvalidError([ { detail: 'Must be unique', source: { pointer: '/data/attributes/title' } @@ -13355,13 +13468,13 @@ import DS from 'ember-data'; const { errorsHashToArray } = DS; let errors = { - base: "Invalid attributes on saving this record", - name: "Must be present", - age: ["Must be present", "Must be a number"] + base: 'Invalid attributes on saving this record', + name: 'Must be present', + age: ['Must be present', 'Must be a number'] }; let errorsArray = errorsHashToArray(errors); // [ // { @@ -13430,23 +13543,23 @@ const { errorsArrayToHash } = DS; let errorsArray = [ { - title: "Invalid Attribute", - detail: "Must be present", - source: { pointer: "/data/attributes/name" } + title: 'Invalid Attribute', + detail: 'Must be present', + source: { pointer: '/data/attributes/name' } }, { - title: "Invalid Attribute", - detail: "Must be present", - source: { pointer: "/data/attributes/age" } + title: 'Invalid Attribute', + detail: 'Must be present', + source: { pointer: '/data/attributes/age' } }, { - title: "Invalid Attribute", - detail: "Must be a number", - source: { pointer: "/data/attributes/age" } + title: 'Invalid Attribute', + detail: 'Must be a number', + source: { pointer: '/data/attributes/age' } } ]; let errors = errorsArrayToHash(errorsArray); // { @@ -13700,11 +13813,11 @@ @type {boolean} */ coalesceFindRequests: false, findMany: function (store, type, ids, snapshots) { - if (false && !this._hasCustomizedAjax()) { + if ((0, _emberDataPrivateFeatures.default)('ds-improved-ajax') && !this._hasCustomizedAjax()) { return this._super.apply(this, arguments); } else { var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); return this.ajax(url, 'GET', { data: { filter: { id: ids.join(',') } } }); } @@ -13715,20 +13828,19 @@ return _ember.default.String.pluralize(dasherized); }, // TODO: Remove this once we have a better way to override HTTP verbs. updateRecord: function (store, type, snapshot) { - if (false && !this._hasCustomizedAjax()) { + if ((0, _emberDataPrivateFeatures.default)('ds-improved-ajax') && !this._hasCustomizedAjax()) { return this._super.apply(this, arguments); } else { var data = {}; var serializer = store.serializerFor(type.modelName); serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); - var id = snapshot.id; - var url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); + var url = this.buildURL(type.modelName, snapshot.id, snapshot, 'updateRecord'); return this.ajax(url, 'PATCH', { data: data }); } }, @@ -13743,11 +13855,11 @@ return false; } }); - if (false) { + if ((0, _emberDataPrivateFeatures.default)('ds-improved-ajax')) { JSONAPIAdapter.reopen({ methodForRequest: function (params) { if (params.requestType === 'updateRecord') { @@ -13910,12 +14022,12 @@ ```js { "people": { "id": 5, - "firstName": "Barack", - "lastName": "Obama", + "firstName": "Zaphod", + "lastName": "Beeblebrox", "occupation": "President" } } ``` @@ -14020,12 +14132,12 @@ ```app/adapters/application.js import DS from 'ember-data'; export default DS.RESTAdapter.extend({ headers: { - "API_KEY": "secret key", - "ANOTHER_HEADER": "Some header value" + 'API_KEY': 'secret key', + 'ANOTHER_HEADER': 'Some header value' } }); ``` `headers` can also be used as a computed property to support dynamic @@ -14036,12 +14148,12 @@ import DS from 'ember-data'; export default DS.RESTAdapter.extend({ headers: Ember.computed('session.authToken', function() { return { - "API_KEY": this.get("session.authToken"), - "ANOTHER_HEADER": "Some header value" + 'API_KEY': this.get('session.authToken'), + 'ANOTHER_HEADER': 'Some header value' }; }) }); ``` @@ -14056,12 +14168,12 @@ import DS from 'ember-data'; export default DS.RESTAdapter.extend({ headers: Ember.computed(function() { return { - "API_KEY": Ember.get(document.cookie.match(/apiKey\=([^;]*)/), "1"), - "ANOTHER_HEADER": "Some header value" + 'API_KEY': Ember.get(document.cookie.match(/apiKey\=([^;]*)/), '1'), + 'ANOTHER_HEADER': 'Some header value' }; }).volatile() }); ``` @@ -14077,11 +14189,11 @@ /** By default, the RESTAdapter will send the query params sorted alphabetically to the server. For example: ```js - store.query('posts', { sort: 'price', category: 'pets' }); + store.query('posts', { sort: 'price', category: 'pets' }); ``` will generate a requests like this `/posts?category=pets&sort=price`, even if the parameters were specified in a different order. That way the generated URL will be deterministic and that simplifies caching mechanisms in the backend. @@ -14089,17 +14201,17 @@ In case you want to sort the query parameters with a different criteria, set `sortQueryParams` to your custom sort function. ```app/adapters/application.js import DS from 'ember-data'; export default DS.RESTAdapter.extend({ - sortQueryParams: function(params) { - var sortedKeys = Object.keys(params).sort().reverse(); - var len = sortedKeys.length, newParams = {}; - for (var i = 0; i < len; i++) { + sortQueryParams(params) { + let sortedKeys = Object.keys(params).sort().reverse(); + let len = sortedKeys.length, newParams = {}; + for (let i = 0; i < len; i++) { newParams[sortedKeys[i]] = params[sortedKeys[i]]; } - return newParams; + return newParams; } }); ``` @method sortQueryParams @param {Object} obj @@ -14193,12 +14305,12 @@ customization](/api/data/classes/DS.RESTAdapter.html#toc_headers-customization). ```app/adapters/application.js import DS from 'ember-data'; export default DS.RESTAdapter.extend({ headers: { - "API_KEY": "secret key", - "ANOTHER_HEADER": "Some header value" + 'API_KEY': 'secret key', + 'ANOTHER_HEADER': 'Some header value' } }); ``` @property headers @type {Object} @@ -14217,11 +14329,11 @@ @param {String} id @param {DS.Snapshot} snapshot @return {Promise} promise */ findRecord: function (store, type, id, snapshot) { - if (false && !this._hasCustomizedAjax()) { + if ((0, _emberDataPrivateFeatures.default)('ds-improved-ajax') && !this._hasCustomizedAjax()) { var request = this._requestFor({ store: store, type: type, id: id, snapshot: snapshot, requestType: 'findRecord' }); @@ -14247,11 +14359,11 @@ @return {Promise} promise */ findAll: function (store, type, sinceToken, snapshotRecordArray) { var query = this.buildQuery(snapshotRecordArray); - if (false && !this._hasCustomizedAjax()) { + if ((0, _emberDataPrivateFeatures.default)('ds-improved-ajax') && !this._hasCustomizedAjax()) { var request = this._requestFor({ store: store, type: type, sinceToken: sinceToken, query: query, snapshots: snapshotRecordArray, requestType: 'findAll' }); @@ -14281,11 +14393,11 @@ @param {DS.Model} type @param {Object} query @return {Promise} promise */ query: function (store, type, query) { - if (false && !this._hasCustomizedAjax()) { + if ((0, _emberDataPrivateFeatures.default)('ds-improved-ajax') && !this._hasCustomizedAjax()) { var request = this._requestFor({ store: store, type: type, query: query, requestType: 'query' }); @@ -14315,11 +14427,11 @@ @param {DS.Model} type @param {Object} query @return {Promise} promise */ queryRecord: function (store, type, query) { - if (false && !this._hasCustomizedAjax()) { + if ((0, _emberDataPrivateFeatures.default)('ds-improved-ajax') && !this._hasCustomizedAjax()) { var request = this._requestFor({ store: store, type: type, query: query, requestType: 'queryRecord' }); @@ -14360,11 +14472,11 @@ @param {Array} ids @param {Array} snapshots @return {Promise} promise */ findMany: function (store, type, ids, snapshots) { - if (false && !this._hasCustomizedAjax()) { + if ((0, _emberDataPrivateFeatures.default)('ds-improved-ajax') && !this._hasCustomizedAjax()) { var request = this._requestFor({ store: store, type: type, ids: ids, snapshots: snapshots, requestType: 'findMany' }); @@ -14401,11 +14513,11 @@ @param {Object} relationship meta object describing the relationship @param {String} url @return {Promise} promise */ findHasMany: function (store, snapshot, url, relationship) { - if (false && !this._hasCustomizedAjax()) { + if ((0, _emberDataPrivateFeatures.default)('ds-improved-ajax') && !this._hasCustomizedAjax()) { var request = this._requestFor({ store: store, snapshot: snapshot, url: url, relationship: relationship, requestType: 'findHasMany' }); @@ -14445,11 +14557,11 @@ @param {DS.Snapshot} snapshot @param {String} url @return {Promise} promise */ findBelongsTo: function (store, snapshot, url, relationship) { - if (false && !this._hasCustomizedAjax()) { + if ((0, _emberDataPrivateFeatures.default)('ds-improved-ajax') && !this._hasCustomizedAjax()) { var request = this._requestFor({ store: store, snapshot: snapshot, url: url, relationship: relationship, requestType: 'findBelongsTo' }); @@ -14475,11 +14587,11 @@ @param {DS.Model} type @param {DS.Snapshot} snapshot @return {Promise} promise */ createRecord: function (store, type, snapshot) { - if (false && !this._hasCustomizedAjax()) { + if ((0, _emberDataPrivateFeatures.default)('ds-improved-ajax') && !this._hasCustomizedAjax()) { var request = this._requestFor({ store: store, type: type, snapshot: snapshot, requestType: 'createRecord' }); @@ -14507,11 +14619,11 @@ @param {DS.Model} type @param {DS.Snapshot} snapshot @return {Promise} promise */ updateRecord: function (store, type, snapshot) { - if (false && !this._hasCustomizedAjax()) { + if ((0, _emberDataPrivateFeatures.default)('ds-improved-ajax') && !this._hasCustomizedAjax()) { var request = this._requestFor({ store: store, type: type, snapshot: snapshot, requestType: 'updateRecord' }); @@ -14537,11 +14649,11 @@ @param {DS.Model} type @param {DS.Snapshot} snapshot @return {Promise} promise */ deleteRecord: function (store, type, snapshot) { - if (false && !this._hasCustomizedAjax()) { + if ((0, _emberDataPrivateFeatures.default)('ds-improved-ajax') && !this._hasCustomizedAjax()) { var request = this._requestFor({ store: store, type: type, snapshot: snapshot, requestType: 'deleteRecord' }); @@ -14606,12 +14718,12 @@ var baseUrl = adapter._stripIDFromURL(store, snapshot); groups.get(baseUrl).push(snapshot); }); function splitGroupToFitInUrl(group, maxURLLength, paramNameLength) { - var baseUrl = adapter._stripIDFromURL(store, group[0]); var idsSize = 0; + var baseUrl = adapter._stripIDFromURL(store, group[0]); var splitGroups = [[]]; group.forEach(function (snapshot) { var additionalLength = encodeURIComponent(snapshot.id).length + paramNameLength; if (baseUrl.length + idsSize + additionalLength >= maxURLLength) { @@ -14673,11 +14785,11 @@ } var errors = this.normalizeErrorResponse(status, headers, payload); var detailedMessage = this.generatedDetailedMessage(status, headers, payload, requestData); - if (false) { + if (true) { switch (status) { case 401: return new _emberDataAdaptersErrors.UnauthorizedError(errors, detailedMessage); case 403: return new _emberDataAdaptersErrors.ForbiddenError(errors, detailedMessage); @@ -14861,11 +14973,11 @@ @param {Object} payload @param {Object} requestData @return {String} detailed error message */ generatedDetailedMessage: function (status, headers, payload, requestData) { - var shortenedPayload; + var shortenedPayload = undefined; var payloadContentType = headers["Content-Type"] || "Empty Content-Type"; if (payloadContentType === "text/html" && payload.length > 250) { shortenedPayload = "[Omitted Lengthy HTML]"; } else { @@ -14904,11 +15016,11 @@ return false; } }); - if (false) { + if ((0, _emberDataPrivateFeatures.default)('ds-improved-ajax')) { RESTAdapter.reopen({ /** * Get the data (body or query params) for a request. @@ -15263,50 +15375,56 @@ ```app/models/user.js import DS from 'ember-data'; export default DS.Model.extend({ - username: attr('string'), - email: attr('string'), - settings: attr({defaultValue: function() { - return {}; - }}) + username: DS.attr('string'), + email: DS.attr('string'), + settings: DS.attr({ + defaultValue() { + return {}; + } + }) }); ``` The `options` hash is passed as second argument to a transforms' `serialize` and `deserialize` method. This allows to configure a transformation and adapt the corresponding value, based on the config: ```app/models/post.js + import DS from 'ember-data'; + export default DS.Model.extend({ text: DS.attr('text', { uppercase: true }) }); ``` ```app/transforms/text.js + import DS from 'ember-data'; + export default DS.Transform.extend({ - serialize: function(value, options) { + serialize(value, options) { if (options.uppercase) { return value.toUpperCase(); } return value; }, - deserialize: function(value) { + deserialize(value) { return value; } }) ``` @namespace @method attr @for DS - @param {String} type the attribute type + @param {String|Object} type the attribute type @param {Object} options a hash of options @return {Attribute} */ function attr(type, options) { @@ -15333,11 +15451,11 @@ } }, set: function (key, value) { var internalModel = this._internalModel; var oldValue = getValue(internalModel, key); - var originalValue; + var originalValue = undefined; if (value !== oldValue) { // Add the new value to the changed attributes hash; it will get deleted by // the 'didSetProperty' handler if it is no different from the original value internalModel._attributes[key] = value; @@ -15359,11 +15477,11 @@ return value; } }).meta(meta); } }); -define("ember-data", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/features", "ember-data/-private/global", "ember-data/-private/core", "ember-data/-private/system/normalize-model-name", "ember-data/-private/system/model/internal-model", "ember-data/-private/system/promise-proxies", "ember-data/-private/system/store", "ember-data/-private/system/model", "ember-data/model", "ember-data/-private/system/snapshot", "ember-data/adapter", "ember-data/serializer", "ember-data/-private/system/debug", "ember-data/adapters/errors", "ember-data/-private/system/record-arrays", "ember-data/-private/system/many-array", "ember-data/-private/system/record-array-manager", "ember-data/-private/adapters", "ember-data/-private/adapters/build-url-mixin", "ember-data/-private/serializers", "ember-inflector", "ember-data/serializers/embedded-records-mixin", "ember-data/-private/transforms", "ember-data/relationships", "ember-data/setup-container", "ember-data/-private/instance-initializers/initialize-store-service", "ember-data/-private/system/relationships/state/relationship"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateFeatures, _emberDataPrivateGlobal, _emberDataPrivateCore, _emberDataPrivateSystemNormalizeModelName, _emberDataPrivateSystemModelInternalModel, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemStore, _emberDataPrivateSystemModel, _emberDataModel, _emberDataPrivateSystemSnapshot, _emberDataAdapter, _emberDataSerializer, _emberDataPrivateSystemDebug, _emberDataAdaptersErrors, _emberDataPrivateSystemRecordArrays, _emberDataPrivateSystemManyArray, _emberDataPrivateSystemRecordArrayManager, _emberDataPrivateAdapters, _emberDataPrivateAdaptersBuildUrlMixin, _emberDataPrivateSerializers, _emberInflector, _emberDataSerializersEmbeddedRecordsMixin, _emberDataPrivateTransforms, _emberDataRelationships, _emberDataSetupContainer, _emberDataPrivateInstanceInitializersInitializeStoreService, _emberDataPrivateSystemRelationshipsStateRelationship) { +define("ember-data", ["exports", "ember", "ember-data/-private/debug", "ember-data/-private/features", "ember-data/-private/global", "ember-data/-private/core", "ember-data/-private/system/normalize-model-name", "ember-data/-private/system/model/internal-model", "ember-data/-private/system/promise-proxies", "ember-data/-private/system/store", "ember-data/-private/system/model", "ember-data/model", "ember-data/-private/system/snapshot", "ember-data/adapter", "ember-data/serializer", "ember-data/adapters/errors", "ember-data/-private/system/record-arrays", "ember-data/-private/system/many-array", "ember-data/-private/system/record-array-manager", "ember-data/-private/adapters", "ember-data/-private/adapters/build-url-mixin", "ember-data/-private/serializers", "ember-inflector", "ember-data/serializers/embedded-records-mixin", "ember-data/-private/transforms", "ember-data/relationships", "ember-data/setup-container", "ember-data/-private/instance-initializers/initialize-store-service", "ember-data/-private/system/relationships/state/relationship"], function (exports, _ember, _emberDataPrivateDebug, _emberDataPrivateFeatures, _emberDataPrivateGlobal, _emberDataPrivateCore, _emberDataPrivateSystemNormalizeModelName, _emberDataPrivateSystemModelInternalModel, _emberDataPrivateSystemPromiseProxies, _emberDataPrivateSystemStore, _emberDataPrivateSystemModel, _emberDataModel, _emberDataPrivateSystemSnapshot, _emberDataAdapter, _emberDataSerializer, _emberDataAdaptersErrors, _emberDataPrivateSystemRecordArrays, _emberDataPrivateSystemManyArray, _emberDataPrivateSystemRecordArrayManager, _emberDataPrivateAdapters, _emberDataPrivateAdaptersBuildUrlMixin, _emberDataPrivateSerializers, _emberInflector, _emberDataSerializersEmbeddedRecordsMixin, _emberDataPrivateTransforms, _emberDataRelationships, _emberDataSetupContainer, _emberDataPrivateInstanceInitializersInitializeStoreService, _emberDataPrivateSystemRelationshipsStateRelationship) { /** Ember Data @module ember-data @main ember-data @@ -15392,11 +15510,11 @@ _emberDataPrivateCore.default.AdapterError = _emberDataAdaptersErrors.AdapterError; _emberDataPrivateCore.default.InvalidError = _emberDataAdaptersErrors.InvalidError; _emberDataPrivateCore.default.TimeoutError = _emberDataAdaptersErrors.TimeoutError; _emberDataPrivateCore.default.AbortError = _emberDataAdaptersErrors.AbortError; - if (false) { + if (true) { _emberDataPrivateCore.default.UnauthorizedError = _emberDataAdaptersErrors.UnauthorizedError; _emberDataPrivateCore.default.ForbiddenError = _emberDataAdaptersErrors.ForbiddenError; _emberDataPrivateCore.default.NotFoundError = _emberDataAdaptersErrors.NotFoundError; _emberDataPrivateCore.default.ConflictError = _emberDataAdaptersErrors.ConflictError; _emberDataPrivateCore.default.ServerError = _emberDataAdaptersErrors.ServerError; @@ -15405,11 +15523,11 @@ _emberDataPrivateCore.default.errorsHashToArray = _emberDataAdaptersErrors.errorsHashToArray; _emberDataPrivateCore.default.errorsArrayToHash = _emberDataAdaptersErrors.errorsArrayToHash; _emberDataPrivateCore.default.Serializer = _emberDataSerializer.default; - _emberDataPrivateCore.default.DebugAdapter = _emberDataPrivateSystemDebug.default; + _emberDataPrivateCore.default.DebugAdapter = _emberDataPrivateDebug.default; _emberDataPrivateCore.default.RecordArray = _emberDataPrivateSystemRecordArrays.RecordArray; _emberDataPrivateCore.default.FilteredRecordArray = _emberDataPrivateSystemRecordArrays.FilteredRecordArray; _emberDataPrivateCore.default.AdapterPopulatedRecordArray = _emberDataPrivateSystemRecordArrays.AdapterPopulatedRecordArray; _emberDataPrivateCore.default.ManyArray = _emberDataPrivateSystemManyArray.default; @@ -15471,11 +15589,11 @@ name: 'data-adapter', before: 'store', initialize: function () {} }; }); -define('ember-data/initializers/ember-data', ['exports', 'ember-data/setup-container', 'ember-data/-private/core'], function (exports, _emberDataSetupContainer, _emberDataPrivateCore) { +define('ember-data/initializers/ember-data', ['exports', 'ember-data/setup-container', 'ember-data/index'], function (exports, _emberDataSetupContainer, _emberDataIndex) { /* This code initializes Ember-Data onto an Ember application. @@ -15602,11 +15720,11 @@ all records. It can be used to look up serializers for other model types that may be nested inside the payload response. Example: ```js Serializer.extend({ - extractRelationship: function(relationshipModelName, relationshipHash) { + extractRelationship(relationshipModelName, relationshipHash) { var modelClass = this.store.modelFor(relationshipModelName); var relationshipSerializer = this.store.serializerFor(relationshipModelName); return relationshipSerializer.normalize(modelClass, relationshipHash); } }); @@ -15727,10 +15845,12 @@ `DS.EmbeddedRecordsMixin` supports serializing embedded records. To set up embedded records, include the mixin when extending a serializer, then define and configure embedded (model) relationships. + Note that embedded records will serialize with the serializer for their model instead of the serializer in which they are defined. + Below is an example of a per-type serializer (`post` type). ```app/serializers/post.js import DS from 'ember-data'; @@ -16133,23 +16253,23 @@ @param {DS.Snapshot} embeddedSnapshot @param {Object} relationship @param {Object} json */ removeEmbeddedForeignKey: function (snapshot, embeddedSnapshot, relationship, json) { - if (relationship.kind === 'hasMany') { - return; - } else if (relationship.kind === 'belongsTo') { + if (relationship.kind === 'belongsTo') { var parentRecord = snapshot.type.inverseFor(relationship.key, this.store); if (parentRecord) { - var name = parentRecord.name; + var _name = parentRecord.name; var embeddedSerializer = this.store.serializerFor(embeddedSnapshot.modelName); - var parentKey = embeddedSerializer.keyForRelationship(name, parentRecord.kind, 'deserialize'); + var parentKey = embeddedSerializer.keyForRelationship(_name, parentRecord.kind, 'deserialize'); if (parentKey) { delete json[parentKey]; } } - } + } /*else if (relationship.kind === 'hasMany') { + return; + }*/ }, // checks config for attrs option to embedded (always) - serialize and deserialize hasEmbeddedAlwaysOption: function (attr) { var option = this.attrsOption(attr); @@ -16295,11 +16415,11 @@ return serializer.normalize(modelClass, relationshipHash, null); }, isEmbeddedRecordsMixin: true }); }); -define('ember-data/serializers/json-api', ['exports', 'ember', 'ember-data/-private/debug', 'ember-data/serializers/json', 'ember-data/-private/system/normalize-model-name', 'ember-inflector', 'ember-data/-private/features'], function (exports, _ember, _emberDataPrivateDebug, _emberDataSerializersJson, _emberDataPrivateSystemNormalizeModelName, _emberInflector, _emberDataPrivateFeatures) { +define('ember-data/serializers/json-api', ['exports', 'ember', 'ember-inflector', 'ember-data/-private/debug', 'ember-data/serializers/json', 'ember-data/-private/system/normalize-model-name', 'ember-data/-private/features'], function (exports, _ember, _emberInflector, _emberDataPrivateDebug, _emberDataSerializersJson, _emberDataPrivateSystemNormalizeModelName, _emberDataPrivateFeatures) { var dasherize = _ember.default.String.dasherize; /** Ember Data 2.0 Serializer: @@ -16312,34 +16432,32 @@ `JSONAPISerializer` supports the http://jsonapi.org/ spec and is the serializer recommended by Ember Data. This serializer normalizes a JSON API payload that looks like: - ```js + ```app/models/player.js + import DS from 'ember-data'; - // models/player.js - import DS from "ember-data"; + export default DS.Model.extend({ + name: DS.attr('string'), + skill: DS.attr('string'), + gamesPlayed: DS.attr('number'), + club: DS.belongsTo('club') + }); + ``` - export default DS.Model.extend({ - name: DS.attr(), - skill: DS.attr(), - gamesPlayed: DS.attr(), - club: DS.belongsTo('club') - }); + ```app/models/club.js + import DS from 'ember-data'; - // models/club.js - import DS from "ember-data"; - - export default DS.Model.extend({ - name: DS.attr(), - location: DS.attr(), - players: DS.hasMany('player') - }); + export default DS.Model.extend({ + name: DS.attr('string'), + location: DS.attr('string'), + players: DS.hasMany('player') + }); ``` ```js - { "data": [ { "attributes": { "name": "Benfica", @@ -16392,11 +16510,10 @@ below shows how this could be done using `normalizeArrayResponse` and `extractRelationship`. ```app/serializers/application.js export default JSONAPISerializer.extend({ - normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) { let normalizedDocument = this._super(...arguments); // Customize document meta normalizedDocument.meta = camelCaseKeys(normalizedDocument.meta); @@ -16410,11 +16527,10 @@ // Customize relationship meta normalizedRelationship.meta = camelCaseKeys(normalizedRelationship.meta); return normalizedRelationship; } - }); ``` @since 1.13.0 @class JSONAPISerializer @@ -16463,23 +16579,22 @@ @param {Object} relationshipDataHash @return {Object} @private */ _normalizeRelationshipDataHelper: function (relationshipDataHash) { - if (false) { + if ((0, _emberDataPrivateFeatures.default)("ds-payload-type-hooks")) { var modelName = this.modelNameFromPayloadType(relationshipDataHash.type); var deprecatedModelNameLookup = this.modelNameFromPayloadKey(relationshipDataHash.type); if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { modelName = deprecatedModelNameLookup; } relationshipDataHash.type = modelName; } else { - var type = this.modelNameFromPayloadKey(relationshipDataHash.type); - relationshipDataHash.type = type; + relationshipDataHash.type = this.modelNameFromPayloadKey(relationshipDataHash.type); } return relationshipDataHash; }, @@ -16492,11 +16607,11 @@ _normalizeResourceHelper: function (resourceHash) { var modelName = undefined, usedLookup = undefined; - if (false) { + if ((0, _emberDataPrivateFeatures.default)("ds-payload-type-hooks")) { modelName = this.modelNameFromPayloadType(resourceHash.type); var deprecatedModelNameLookup = this.modelNameFromPayloadKey(resourceHash.type); usedLookup = 'modelNameFromPayloadType'; @@ -16529,11 +16644,11 @@ @param {DS.Store} store @param {Object} payload */ pushPayload: function (store, payload) { var normalizedPayload = this._normalizeDocumentHelper(payload); - if (false) { + if ((0, _emberDataPrivateFeatures.default)('ds-pushpayload-return')) { return store.push(normalizedPayload); } else { store.push(normalizedPayload); } }, @@ -16622,11 +16737,11 @@ @param {Object} resourceHash @return {String} @private */ _extractType: function (modelClass, resourceHash) { - if (false) { + if ((0, _emberDataPrivateFeatures.default)("ds-payload-type-hooks")) { var modelName = this.modelNameFromPayloadType(resourceHash.type); var deprecatedModelNameLookup = this.modelNameFromPayloadKey(resourceHash.type); if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { @@ -16696,11 +16811,11 @@ This behaviour can be easily customized by extending this method. Example ```app/serializers/application.js import DS from 'ember-data'; export default DS.JSONAPISerializer.extend({ - keyForAttribute: function(attr, method) { + keyForAttribute(attr, method) { return Ember.String.dasherize(attr).toUpperCase(); } }); ``` @method keyForAttribute @@ -16721,11 +16836,11 @@ This behaviour can be easily customized by extending this method. Example ```app/serializers/post.js import DS from 'ember-data'; export default DS.JSONAPISerializer.extend({ - keyForRelationship: function(key, relationship, method) { + keyForRelationship(key, relationship, method) { return Ember.String.underscore(key); } }); ``` @method keyForRelationship @@ -16740,11 +16855,11 @@ serialize: function (snapshot, options) { var data = this._super.apply(this, arguments); var payloadType = undefined; - if (false) { + if ((0, _emberDataPrivateFeatures.default)("ds-payload-type-hooks")) { payloadType = this.payloadTypeFromModelName(snapshot.modelName); var deprecatedPayloadTypeLookup = this.payloadKeyFromModelName(snapshot.modelName); if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { @@ -16796,11 +16911,11 @@ var data = null; if (belongsTo) { var payloadType = undefined; - if (false) { + if ((0, _emberDataPrivateFeatures.default)("ds-payload-type-hooks")) { payloadType = this.payloadTypeFromModelName(belongsTo.modelName); var deprecatedPayloadTypeLookup = this.payloadKeyFromModelName(belongsTo.modelName); if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { @@ -16844,11 +16959,11 @@ for (var i = 0; i < hasMany.length; i++) { var item = hasMany[i]; var payloadType = undefined; - if (false) { + if ((0, _emberDataPrivateFeatures.default)("ds-payload-type-hooks")) { payloadType = this.payloadTypeFromModelName(item.modelName); var deprecatedPayloadTypeLookup = this.payloadKeyFromModelName(item.modelName); if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { @@ -16868,11 +16983,11 @@ } } } }); - if (false) { + if ((0, _emberDataPrivateFeatures.default)("ds-payload-type-hooks")) { JSONAPISerializer.reopen({ /** `modelNameFromPayloadType` can be used to change the mapping for a DS model @@ -16889,11 +17004,11 @@ } ``` By overwriting `modelNameFromPayloadType` you can specify that the `post` model should be used: ```app/serializers/application.js - import DS from "ember-data"; + import DS from 'ember-data'; export default DS.JSONAPISerializer.extend({ modelNameFromPayloadType(payloadType) { return payloadType.replace('api::v1::', ''); } }); @@ -16929,14 +17044,14 @@ } ``` By overwriting `payloadTypeFromModelName` you can specify that the namespaces model name for the `post` should be used: ```app/serializers/application.js - import DS from "ember-data"; + import DS from 'ember-data'; export default JSONAPISerializer.extend({ payloadTypeFromModelName(modelName) { - return "api::v1::" + modelName; + return 'api::v1::' + modelName; } }); ``` By default the payload type is the pluralized model name. Usually, Ember Data can use the correct inflection to do this for you. Most of the time, @@ -17447,19 +17562,19 @@ or other general-purpose normalizations. Example ```app/serializers/application.js import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - normalize: function(typeClass, hash) { + normalize(typeClass, hash) { var fields = Ember.get(typeClass, 'fields'); - fields.forEach(function(field) { + fields.forEach(function(field) { var payloadField = Ember.String.underscore(field); if (field === payloadField) { return; } hash[field] = hash[payloadField]; delete hash[payloadField]; }); - return this._super.apply(this, arguments); + return this._super.apply(this, arguments); } }); ``` @method normalize @param {DS.Model} typeClass @@ -17510,11 +17625,11 @@ @return {Object} */ extractAttributes: function (modelClass, resourceHash) { var _this2 = this; - var attributeKey; + var attributeKey = undefined; var attributes = {}; modelClass.eachAttribute(function (key) { attributeKey = _this2.keyForAttribute(key, 'deserialize'); if (resourceHash[attributeKey] !== undefined) { @@ -17548,11 +17663,11 @@ } var modelClass = this.store.modelFor(relationshipModelName); if (relationshipHash.type && !(0, _emberDataPrivateUtils.modelHasAttributeOrRelationshipNamedType)(modelClass)) { - if (false) { + if ((0, _emberDataPrivateFeatures.default)("ds-payload-type-hooks")) { var modelName = this.modelNameFromPayloadType(relationshipHash.type); var deprecatedModelNameLookup = this.modelNameFromPayloadKey(relationshipHash.type); if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { @@ -17660,11 +17775,11 @@ @private */ normalizeRelationships: function (typeClass, hash) { var _this4 = this; - var payloadKey; + var payloadKey = undefined; if (this.keyForRelationship) { typeClass.eachRelationship(function (key, relationship) { payloadKey = _this4.keyForRelationship(key, relationship.kind, 'deserialize'); if (key === payloadKey) { @@ -17684,14 +17799,15 @@ @method normalizeUsingDeclaredMapping @private */ normalizeUsingDeclaredMapping: function (modelClass, hash) { var attrs = get(this, 'attrs'); - var normalizedKey, payloadKey, key; + var normalizedKey = undefined; + var payloadKey = undefined; if (attrs) { - for (key in attrs) { + for (var key in attrs) { normalizedKey = payloadKey = this._getMappedKey(key, modelClass); if (hash[payloadKey] === undefined) { continue; } @@ -17721,11 +17837,11 @@ @return {String} key */ _getMappedKey: function (key, modelClass) { var attrs = get(this, 'attrs'); - var mappedKey; + var mappedKey = undefined; if (attrs && attrs[key]) { mappedKey = attrs[key]; //We need to account for both the { title: 'post_title' } and //{ title: { key: 'post_title' }} forms if (mappedKey.key) { @@ -17841,16 +17957,16 @@ In that case, you can implement `serialize` yourself and return a JSON hash of your choosing. ```app/serializers/post.js import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - serialize: function(snapshot, options) { + serialize(snapshot, options) { var json = { POST_TTL: snapshot.attr('title'), POST_BDY: snapshot.attr('body'), POST_CMS: snapshot.hasMany('comments', { ids: true }) - } + }; if (options.includeId) { json.POST_ID_ = snapshot.id; } return json; } @@ -17861,15 +17977,15 @@ application, you'll probably want to use `eachAttribute` and `eachRelationship` on the record. ```app/serializers/application.js import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - serialize: function(snapshot, options) { + serialize(snapshot, options) { var json = {}; snapshot.eachAttribute(function(name) { json[serverAttributeName(name)] = snapshot.attr(name); - }) + }); snapshot.eachRelationship(function(name, relationship) { if (relationship.kind === 'hasMany') { json[serverHasManyName(name)] = snapshot.hasMany(name, { ids: true }); } }); @@ -17899,12 +18015,12 @@ you can call super first and make the tweaks on the returned JSON. ```app/serializers/post.js import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - serialize: function(snapshot, options) { - var json = this._super.apply(this, arguments); + serialize(snapshot, options) { + var json = this._super(...arguments); json.subject = json.title; delete json.title; return json; } }); @@ -17918,11 +18034,11 @@ var _this5 = this; var json = {}; if (options && options.includeId) { - if (true) { + if ((0, _emberDataPrivateFeatures.default)('ds-serialize-id')) { this.serializeId(snapshot, json, get(this, 'primaryKey')); } else { var id = snapshot.id; if (id) { json[get(this, 'primaryKey')] = id; @@ -17954,11 +18070,11 @@ The hash property should be modified by reference. For example, your server may expect underscored root objects. ```app/serializers/application.js import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - serializeIntoHash: function(data, type, snapshot, options) { + serializeIntoHash(data, type, snapshot, options) { var root = Ember.String.decamelize(type.modelName); data[root] = this.serialize(snapshot, options); } }); ``` @@ -17979,11 +18095,11 @@ serialized as properties on an `attributes` object you could write: ```app/serializers/application.js import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - serializeAttribute: function(snapshot, json, key, attributes) { + serializeAttribute(snapshot, json, key, attributes) { json.attributes = json.attributes || {}; this._super(snapshot, json.attributes, key, attributes); } }); ``` @@ -17992,13 +18108,13 @@ @param {Object} json @param {String} key @param {Object} attribute */ serializeAttribute: function (snapshot, json, key, attribute) { - var type = attribute.type; if (this._canSerialize(key)) { + var type = attribute.type; var value = snapshot.attr(key); if (type) { var transform = this.transformFor(type); value = transform.serialize(value, attribute.options); } @@ -18020,13 +18136,13 @@ properties are serialized. Example ```app/serializers/post.js import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - serializeBelongsTo: function(snapshot, json, relationship) { + serializeBelongsTo(snapshot, json, relationship) { var key = relationship.key; - var belongsTo = snapshot.belongsTo(key); + var belongsTo = snapshot.belongsTo(key); key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo", "serialize") : key; json[key] = Ember.isNone(belongsTo) ? belongsTo : belongsTo.record.toJSON(); } }); ``` @@ -18066,16 +18182,16 @@ properties are serialized. Example ```app/serializers/post.js import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - serializeHasMany: function(snapshot, json, relationship) { + serializeHasMany(snapshot, json, relationship) { var key = relationship.key; if (key === 'comments') { return; } else { - this._super.apply(this, arguments); + this._super(...arguments); } } }); ``` @method serializeHasMany @@ -18113,18 +18229,18 @@ `DS.belongsTo` function. Example ```app/serializers/comment.js import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - serializePolymorphicType: function(snapshot, json, relationship) { - var key = relationship.key, - belongsTo = snapshot.belongsTo(key); - key = this.keyForAttribute ? this.keyForAttribute(key, "serialize") : key; + serializePolymorphicType(snapshot, json, relationship) { + var key = relationship.key; + var belongsTo = snapshot.belongsTo(key); + key = this.keyForAttribute ? this.keyForAttribute(key, 'serialize') : key; if (Ember.isNone(belongsTo)) { - json[key + "_type"] = null; + json[key + '_type'] = null; } else { - json[key + "_type"] = belongsTo.modelName; + json[key + '_type'] = belongsTo.modelName; } } }); ``` @method serializePolymorphicType @@ -18140,11 +18256,11 @@ be located on the `meta` property of the payload object. Example ```app/serializers/post.js import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - extractMeta: function(store, typeClass, payload) { + extractMeta(store, typeClass, payload) { if (payload && payload.hasOwnProperty('_pagination')) { let meta = payload._pagination; delete payload._pagination; return meta; } @@ -18219,11 +18335,11 @@ Example of alternative implementation, overriding the default behavior to deal with a different format of errors: ```app/serializers/post.js import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - extractErrors: function(store, typeClass, payload, id) { + extractErrors(store, typeClass, payload, id) { if (payload && typeof payload === 'object' && payload._problems) { payload = payload._problems; this.normalizeErrors(typeClass, payload); } return payload; @@ -18270,11 +18386,11 @@ attribute name in your model to a key in your JSON. Example ```app/serializers/application.js import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - keyForAttribute: function(attr, method) { + keyForAttribute(attr, method) { return Ember.String.underscore(attr).toUpperCase(); } }); ``` @method keyForAttribute @@ -18292,11 +18408,11 @@ `JSONSerializer` does not provide an implementation of this method. Example ```app/serializers/post.js import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - keyForRelationship: function(key, relationship, method) { + keyForRelationship(key, relationship, method) { return 'rel_' + Ember.String.underscore(key); } }); ``` @method keyForRelationship @@ -18335,11 +18451,11 @@ return transform; } }); - if (false) { + if ((0, _emberDataPrivateFeatures.default)("ds-payload-type-hooks")) { JSONSerializer.reopen({ /** @method modelNameFromPayloadType @@ -18356,11 +18472,11 @@ } }); } - if (true) { + if ((0, _emberDataPrivateFeatures.default)("ds-serialize-id")) { JSONSerializer.reopen({ /** serializeId can be used to customize how id is serialized @@ -18391,11 +18507,11 @@ }); } exports.default = JSONSerializer; }); -define("ember-data/serializers/rest", ["exports", "ember", "ember-data/-private/debug", "ember-data/serializers/json", "ember-data/-private/system/normalize-model-name", "ember-inflector", "ember-data/-private/system/coerce-id", "ember-data/-private/utils", "ember-data/-private/features"], function (exports, _ember, _emberDataPrivateDebug, _emberDataSerializersJson, _emberDataPrivateSystemNormalizeModelName, _emberInflector, _emberDataPrivateSystemCoerceId, _emberDataPrivateUtils, _emberDataPrivateFeatures) { +define("ember-data/serializers/rest", ["exports", "ember", "ember-inflector", "ember-data/-private/debug", "ember-data/serializers/json", "ember-data/-private/system/normalize-model-name", "ember-data/-private/system/coerce-id", "ember-data/-private/utils", "ember-data/-private/features"], function (exports, _ember, _emberInflector, _emberDataPrivateDebug, _emberDataSerializersJson, _emberDataPrivateSystemNormalizeModelName, _emberDataPrivateSystemCoerceId, _emberDataPrivateUtils, _emberDataPrivateFeatures) { function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } var camelize = _ember.default.String.camelize; /** @@ -18423,11 +18539,11 @@ ```app/serializers/application.js import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - keyForAttribute: function(attr, method) { + keyForAttribute(attr, method) { return Ember.String.underscore(attr).toUpperCase(); } }); ``` @@ -18448,11 +18564,11 @@ returned key is `${key}Type`. Example ```app/serializers/post.js import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - keyForPolymorphicType: function(key, relationship) { + keyForPolymorphicType(key, relationship) { var relationshipKey = this.keyForRelationship(key); return 'type-' + relationshipKey; } }); ``` @@ -18546,11 +18662,11 @@ var documentHash = { data: [], included: [] }; - var modelClass = store._modelFor(modelName); + var modelClass = store.modelFor(modelName); var serializer = store.serializerFor(modelName); _ember.default.makeArray(arrayHash).forEach(function (hash) { var _normalizePolymorphicRecord = _this._normalizePolymorphicRecord(store, hash, prop, modelClass, serializer); @@ -18575,11 +18691,11 @@ var primaryHasTypeAttribute = (0, _emberDataPrivateUtils.modelHasAttributeOrRelationshipNamedType)(primaryModelClass); if (!primaryHasTypeAttribute && hash.type) { // Support polymorphic records in async relationships var modelName = undefined; - if (false) { + if ((0, _emberDataPrivateFeatures.default)("ds-payload-type-hooks")) { modelName = this.modelNameFromPayloadType(hash.type); var deprecatedModelNameLookup = this.modelNameFromPayloadKey(hash.type); if (modelName !== deprecatedModelNameLookup && !this._hasCustomModelNameFromPayloadType() && this._hasCustomModelNameFromPayloadKey()) { @@ -18608,10 +18724,12 @@ @param {Boolean} isSingle @return {Object} JSON-API Document @private */ _normalizeResponse: function (store, primaryModelClass, payload, id, requestType, isSingle) { + var _this2 = this; + var documentHash = { data: null, included: [] }; @@ -18620,11 +18738,11 @@ documentHash.meta = meta; } var keys = Object.keys(payload); - for (var i = 0, _length = keys.length; i < _length; i++) { + var _loop = function (i, _length) { var prop = keys[i]; var modelName = prop; var forcedSecondary = false; /* @@ -18647,20 +18765,20 @@ if (prop.charAt(0) === '_') { forcedSecondary = true; modelName = prop.substr(1); } - var typeName = this.modelNameFromPayloadKey(modelName); + var typeName = _this2.modelNameFromPayloadKey(modelName); if (!store.modelFactoryFor(typeName)) { - continue; + return "continue"; } - var isPrimary = !forcedSecondary && this.isPrimaryType(store, typeName, primaryModelClass); + var isPrimary = !forcedSecondary && _this2.isPrimaryType(store, typeName, primaryModelClass); var value = payload[prop]; if (value === null) { - continue; + return "continue"; } /* Support primary data as an object instead of an array. Example @@ -18669,25 +18787,25 @@ user: { id: 1, title: 'Tom', manager: 3 } } ``` */ if (isPrimary && _ember.default.typeOf(value) !== 'array') { - var _normalizePolymorphicRecord2 = this._normalizePolymorphicRecord(store, value, prop, primaryModelClass, this); + var _normalizePolymorphicRecord2 = _this2._normalizePolymorphicRecord(store, value, prop, primaryModelClass, _this2); var _data = _normalizePolymorphicRecord2.data; var _included = _normalizePolymorphicRecord2.included; documentHash.data = _data; if (_included) { var _documentHash$included2; (_documentHash$included2 = documentHash.included).push.apply(_documentHash$included2, _toConsumableArray(_included)); } - continue; + return "continue"; } - var _normalizeArray = this._normalizeArray(store, typeName, value, prop); + var _normalizeArray = _this2._normalizeArray(store, typeName, value, prop); var data = _normalizeArray.data; var included = _normalizeArray.included; if (included) { @@ -18724,18 +18842,23 @@ (_documentHash$included4 = documentHash.included).push.apply(_documentHash$included4, _toConsumableArray(data)); } } } + }; + + for (var i = 0, _length = keys.length; i < _length; i++) { + var _ret = _loop(i, _length); + + if (_ret === "continue") continue; } return documentHash; }, isPrimaryType: function (store, typeName, primaryTypeClass) { - var typeClass = store.modelFor(typeName); - return typeClass.modelName === primaryTypeClass.modelName; + return store.modelFor(typeName) === primaryTypeClass; }, /** This method allows you to push a payload containing top-level collections of records organized per type. @@ -18763,19 +18886,21 @@ @method pushPayload @param {DS.Store} store @param {Object} payload */ pushPayload: function (store, payload) { + var _this3 = this; + var documentHash = { data: [], included: [] }; - for (var prop in payload) { - var modelName = this.modelNameFromPayloadKey(prop); + var _loop2 = function (prop) { + var modelName = _this3.modelNameFromPayloadKey(prop); if (!store.modelFactoryFor(modelName)) { - continue; + return "continue"; } var type = store.modelFor(modelName); var typeSerializer = store.serializerFor(type.modelName); _ember.default.makeArray(payload[prop]).forEach(function (hash) { @@ -18789,13 +18914,19 @@ var _documentHash$included5; (_documentHash$included5 = documentHash.included).push.apply(_documentHash$included5, _toConsumableArray(included)); } }); + }; + + for (var prop in payload) { + var _ret2 = _loop2(prop); + + if (_ret2 === "continue") continue; } - if (false) { + if ((0, _emberDataPrivateFeatures.default)('ds-pushpayload-return')) { return store.push(documentHash); } else { store.push(documentHash); } }, @@ -18826,11 +18957,11 @@ Since we want to remove this namespace, we can define a serializer for the application that will remove "blog/" from the payload key whenver it's encountered by Ember Data: ```app/serializers/application.js import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - modelNameFromPayloadKey: function(payloadKey) { + modelNameFromPayloadKey(payloadKey) { if (payloadKey === 'blog/post') { return this._super(payloadKey.replace('blog/', '')); } else { return this._super(payloadKey); } @@ -18893,16 +19024,16 @@ In that case, you can implement `serialize` yourself and return a JSON hash of your choosing. ```app/serializers/post.js import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - serialize: function(snapshot, options) { + serialize(snapshot, options) { var json = { POST_TTL: snapshot.attr('title'), POST_BDY: snapshot.attr('body'), POST_CMS: snapshot.hasMany('comments', { ids: true }) - } + }; if (options.includeId) { json.POST_ID_ = snapshot.id; } return json; } @@ -18913,15 +19044,15 @@ application, you'll probably want to use `eachAttribute` and `eachRelationship` on the record. ```app/serializers/application.js import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - serialize: function(snapshot, options) { + serialize(snapshot, options) { var json = {}; snapshot.eachAttribute(function(name) { json[serverAttributeName(name)] = snapshot.attr(name); - }) + }); snapshot.eachRelationship(function(name, relationship) { if (relationship.kind === 'hasMany') { json[serverHasManyName(name)] = snapshot.hasMany(name, { ids: true }); } }); @@ -18951,11 +19082,11 @@ you can call super first and make the tweaks on the returned JSON. ```app/serializers/post.js import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - serialize: function(snapshot, options) { + serialize(snapshot, options) { var json = this._super(snapshot, options); json.subject = json.title; delete json.title; return json; } @@ -18977,11 +19108,11 @@ version of the name. For example, your server may expect underscored root objects. ```app/serializers/application.js import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - serializeIntoHash: function(data, type, record, options) { + serializeIntoHash(data, type, record, options) { var root = Ember.String.decamelize(type.modelName); data[root] = this.serialize(record, options); } }); ``` @@ -19012,11 +19143,11 @@ ``` For example, your server may expect dasherized root objects: ```app/serializers/application.js import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - payloadKeyFromModelName: function(modelName) { + payloadKeyFromModelName(modelName) { return Ember.String.dasherize(modelName); } }); ``` Given a `TacoParty` model, calling `save` on it would produce an outgoing @@ -19046,12 +19177,12 @@ @param {Object} json @param {Object} relationship */ serializePolymorphicType: function (snapshot, json, relationship) { var key = relationship.key; - var belongsTo = snapshot.belongsTo(key); var typeKey = this.keyForPolymorphicType(key, relationship.type, 'serialize'); + var belongsTo = snapshot.belongsTo(key); // old way of getting the key for the polymorphic type key = this.keyForAttribute ? this.keyForAttribute(key, "serialize") : key; key = key + "Type"; @@ -19066,11 +19197,11 @@ } if (_ember.default.isNone(belongsTo)) { json[typeKey] = null; } else { - if (false) { + if ((0, _emberDataPrivateFeatures.default)("ds-payload-type-hooks")) { json[typeKey] = this.payloadTypeFromModelName(belongsTo.modelName); } else { json[typeKey] = camelize(belongsTo.modelName); } } @@ -19110,11 +19241,11 @@ var isPolymorphic = relationshipMeta.options.polymorphic; var typeProperty = this.keyForPolymorphicType(key, relationshipType, 'deserialize'); if (isPolymorphic && resourceHash[typeProperty] !== undefined && typeof relationshipHash !== 'object') { - if (false) { + if ((0, _emberDataPrivateFeatures.default)("ds-payload-type-hooks")) { var payloadType = resourceHash[typeProperty]; var type = this.modelNameFromPayloadType(payloadType); var deprecatedTypeLookup = this.modelNameFromPayloadKey(payloadType); @@ -19139,11 +19270,11 @@ return this._super.apply(this, arguments); } }); - if (false) { + if ((0, _emberDataPrivateFeatures.default)("ds-payload-type-hooks")) { RESTSerializer.reopen({ /** `modelNameFromPayloadType` can be used to change the mapping for a DS model @@ -19161,11 +19292,11 @@ } ``` By overwriting `modelNameFromPayloadType` you can specify that the `administrator` model should be used: ```app/serializers/application.js - import DS from "ember-data"; + import DS from 'ember-data'; export default DS.RESTSerializer.extend({ modelNameFromPayloadType(payloadType) { return payloadType.replace('api::v1::', ''); } }); @@ -19203,14 +19334,14 @@ } ``` By overwriting `payloadTypeFromModelName` you can specify that the namespaces model name for the `administrator` should be used: ```app/serializers/application.js - import DS from "ember-data"; + import DS from 'ember-data'; export default DS.RESTSerializer.extend({ payloadTypeFromModelName(modelName) { - return "api::v1::" + modelName; + return 'api::v1::' + modelName; } }); ``` By default the payload type is the camelized model name. Usually, Ember Data can use the correct inflection to do this for you. Most of the time, @@ -19218,11 +19349,11 @@ Also take a look at [modelNameFromPayloadType](#method_modelNameFromPayloadType) to customize how the model name from should be mapped from the payload. @method payloadTypeFromModelName @public - @param {String} modelname modelName from the record + @param {String} modelName modelName from the record @return {String} payloadType */ payloadTypeFromModelName: function (modelName) { return camelize(modelName); }, @@ -19278,14 +19409,15 @@ ```app/transforms/temperature.js import DS from 'ember-data'; // Converts centigrade in the JSON to fahrenheit in the app export default DS.Transform.extend({ - deserialize: function(serialized, options) { + deserialize(serialized, options) { return (serialized * 1.8) + 32; }, - serialize: function(deserialized, options) { + + serialize(deserialized, options) { return (deserialized - 32) / 1.8; } }); ``` @@ -19304,15 +19436,15 @@ }); ``` ```app/transforms/markdown.js export default DS.Transform.extend({ - serialize: function (deserialized, options) { + serialize(deserialized, options) { return deserialized.raw; }, - deserialize: function (serialized, options) { + deserialize(serialized, options) { var markdownOptions = options.markdown || {}; return marked(serialized, markdownOptions); } }); @@ -19336,11 +19468,11 @@ /** When given a deserialized value from a record attribute this method must return the serialized value. Example ```javascript - serialize: function(deserialized, options) { + serialize(deserialized, options) { return Ember.isEmpty(deserialized) ? null : Number(deserialized); } ``` @method serialize @param deserialized The deserialized value @@ -19352,11 +19484,11 @@ /** When given a serialize value from a JSON object this method must return the deserialized value for the record attribute. Example ```javascript - deserialize: function(serialized, options) { + deserialize(serialized, options) { return empty(serialized) ? null : Number(serialized); } ``` @method deserialize @param serialized The serialized value @@ -19365,11 +19497,11 @@ */ deserialize: null }); }); define("ember-data/version", ["exports"], function (exports) { - exports.default = "2.12.2"; + exports.default = "2.13.0-beta.1"; }); define("ember-inflector", ["exports", "ember", "ember-inflector/lib/system", "ember-inflector/lib/ext/string"], function (exports, _ember, _emberInflectorLibSystem, _emberInflectorLibExtString) { _emberInflectorLibSystem.Inflector.defaultRules = _emberInflectorLibSystem.defaultRules; _ember.default.Inflector = _emberInflectorLibSystem.Inflector; @@ -19826,51 +19958,384 @@ return _ember.default.HTMLBars.makeBoundHelper(helperFunction); } return _ember.default.Handlebars.makeBoundHelper(helperFunction); } }); -define('ember-load-initializers', ['exports', 'ember'], function (exports, _ember) { - exports.default = function (app, prefix) { - var regex = new RegExp('^' + prefix + '\/((?:instance-)?initializers)\/'); - var getKeys = Object.keys || _ember.default.keys; +define('ember-load-initializers', ['exports'], function (exports) { + function resolveInitializer(moduleName) { + var module = require(moduleName, null, null, true); + if (!module) { + throw new Error(moduleName + ' must export an initializer.'); + } + var initializer = module['default']; + if (!initializer.name) { + initializer.name = moduleName.slice(moduleName.lastIndexOf('/') + 1); + } + return initializer; + } - getKeys(requirejs._eak_seen).map(function (moduleName) { - return { - moduleName: moduleName, - matches: regex.exec(moduleName) - }; - }).filter(function (dep) { - return dep.matches && dep.matches.length === 2; - }).forEach(function (dep) { - var moduleName = dep.moduleName; + function registerInitializers(app, moduleNames) { + for (var i = 0; i < moduleNames.length; i++) { + app.initializer(resolveInitializer(moduleNames[i])); + } + } - var module = require(moduleName, null, null, true); - if (!module) { - throw new Error(moduleName + ' must export an initializer.'); - } + function registerInstanceInitializers(app, moduleNames) { + for (var i = 0; i < moduleNames.length; i++) { + app.instanceInitializer(resolveInitializer(moduleNames[i])); + } + } - var initializerType = _ember.default.String.camelize(dep.matches[1].substring(0, dep.matches[1].length - 1)); - var initializer = module['default']; - if (!initializer.name) { - var initializerName = moduleName.match(/[^\/]+\/?$/)[0]; - initializer.name = initializerName; + exports.default = function (app, prefix) { + var initializerPrefix = prefix + '/initializers/'; + var instanceInitializerPrefix = prefix + '/instance-initializers/'; + var initializers = []; + var instanceInitializers = []; + // this is 2 pass because generally the first pass is the problem + // and is reduced, and resolveInitializer has potential to deopt + var moduleNames = Object.keys(requirejs._eak_seen); + for (var i = 0; i < moduleNames.length; i++) { + var moduleName = moduleNames[i]; + if (moduleName.lastIndexOf(initializerPrefix, 0) === 0) { + initializers.push(moduleName); + } else if (moduleName.lastIndexOf(instanceInitializerPrefix, 0) === 0) { + instanceInitializers.push(moduleName); } - - if (app[initializerType]) { - app[initializerType](initializer); - } - }); + } + registerInitializers(app, initializers); + registerInstanceInitializers(app, instanceInitializers); }; }); define('ember', [], function() { return { default: Ember }; }); +/*! + * @overview Ember Data + * @copyright Copyright 2011-2017 Tilde Inc. and contributors. + * Portions Copyright 2011 LivingSocial Inc. + * @license Licensed under MIT license (see license.js) + * @version 2.13.0-beta.1 + */ +var loader, define, requireModule, require, requirejs; + +(function (global) { + 'use strict'; + + var heimdall = global.heimdall; + + function dict() { + var obj = Object.create(null); + obj['__'] = undefined; + delete obj['__']; + return obj; + } + + // Save off the original values of these globals, so we can restore them if someone asks us to + var oldGlobals = { + loader: loader, + define: define, + requireModule: requireModule, + require: require, + requirejs: requirejs + }; + + requirejs = require = requireModule = function (name) { + var pending = []; + var mod = findModule(name, '(require)', pending); + + for (var i = pending.length - 1; i >= 0; i--) { + pending[i].exports(); + } + + return mod.module.exports; + }; + + loader = { + noConflict: function (aliases) { + var oldName, newName; + + for (oldName in aliases) { + if (aliases.hasOwnProperty(oldName)) { + if (oldGlobals.hasOwnProperty(oldName)) { + newName = aliases[oldName]; + + global[newName] = global[oldName]; + global[oldName] = oldGlobals[oldName]; + } + } + } + } + }; + + var _isArray; + if (!Array.isArray) { + _isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; + } else { + _isArray = Array.isArray; + } + + var registry = dict(); + var seen = dict(); + + var uuid = 0; + + function unsupportedModule(length) { + throw new Error('an unsupported module was defined, expected `define(name, deps, module)` instead got: `' + length + '` arguments to define`'); + } + + var defaultDeps = ['require', 'exports', 'module']; + + function Module(name, deps, callback, alias) { + this.id = uuid++; + this.name = name; + this.deps = !deps.length && callback.length ? defaultDeps : deps; + this.module = { exports: {} }; + this.callback = callback; + this.hasExportsAsDep = false; + this.isAlias = alias; + this.reified = new Array(deps.length); + + /* + Each module normally passes through these states, in order: + new : initial state + pending : this module is scheduled to be executed + reifying : this module's dependencies are being executed + reified : this module's dependencies finished executing successfully + errored : this module's dependencies failed to execute + finalized : this module executed successfully + */ + this.state = 'new'; + } + + Module.prototype.makeDefaultExport = function () { + var exports = this.module.exports; + if (exports !== null && (typeof exports === 'object' || typeof exports === 'function') && exports['default'] === undefined && Object.isExtensible(exports)) { + exports['default'] = exports; + } + }; + + Module.prototype.exports = function () { + // if finalized, there is no work to do. If reifying, there is a + // circular dependency so we must return our (partial) exports. + if (this.state === 'finalized' || this.state === 'reifying') { + return this.module.exports; + } + + if (loader.wrapModules) { + this.callback = loader.wrapModules(this.name, this.callback); + } + + this.reify(); + + var result = this.callback.apply(this, this.reified); + this.state = 'finalized'; + + if (!(this.hasExportsAsDep && result === undefined)) { + this.module.exports = result; + } + this.makeDefaultExport(); + return this.module.exports; + }; + + Module.prototype.unsee = function () { + this.state = 'new'; + this.module = { exports: {} }; + }; + + Module.prototype.reify = function () { + if (this.state === 'reified') { + return; + } + this.state = 'reifying'; + try { + this.reified = this._reify(); + this.state = 'reified'; + } finally { + if (this.state === 'reifying') { + this.state = 'errored'; + } + } + }; + + Module.prototype._reify = function () { + var reified = this.reified.slice(); + for (var i = 0; i < reified.length; i++) { + var mod = reified[i]; + reified[i] = mod.exports ? mod.exports : mod.module.exports(); + } + return reified; + }; + + Module.prototype.findDeps = function (pending) { + if (this.state !== 'new') { + return; + } + + this.state = 'pending'; + + var deps = this.deps; + + for (var i = 0; i < deps.length; i++) { + var dep = deps[i]; + var entry = this.reified[i] = { exports: undefined, module: undefined }; + if (dep === 'exports') { + this.hasExportsAsDep = true; + entry.exports = this.module.exports; + } else if (dep === 'require') { + entry.exports = this.makeRequire(); + } else if (dep === 'module') { + entry.exports = this.module; + } else { + entry.module = findModule(resolve(dep, this.name), this.name, pending); + } + } + }; + + Module.prototype.makeRequire = function () { + var name = this.name; + var r = function (dep) { + return require(resolve(dep, name)); + }; + r['default'] = r; + r.has = function (dep) { + return has(resolve(dep, name)); + }; + return r; + }; + + define = function (name, deps, callback) { + var module = registry[name]; + + // If a module for this name has already been defined and is in any state + // other than `new` (meaning it has been or is currently being required), + // then we return early to avoid redefinition. + if (module && module.state !== 'new') { + return; + } + + if (arguments.length < 2) { + unsupportedModule(arguments.length); + } + + if (!_isArray(deps)) { + callback = deps; + deps = []; + } + + if (callback instanceof Alias) { + registry[name] = new Module(callback.name, deps, callback, true); + } else { + registry[name] = new Module(name, deps, callback, false); + } + }; + + // we don't support all of AMD + // define.amd = {}; + + function Alias(path) { + this.name = path; + } + + define.alias = function (path) { + return new Alias(path); + }; + + function missingModule(name, referrer) { + throw new Error('Could not find module `' + name + '` imported from `' + referrer + '`'); + } + + function findModule(name, referrer, pending) { + var mod = registry[name] || registry[name + '/index']; + + while (mod && mod.isAlias) { + mod = registry[mod.name]; + } + + if (!mod) { + missingModule(name, referrer); + } + + if (pending && mod.state !== 'pending' && mod.state !== 'finalized') { + mod.findDeps(pending); + pending.push(mod); + } + return mod; + } + + function resolve(child, name) { + if (child.charAt(0) !== '.') { + return child; + } + + var parts = child.split('/'); + var nameParts = name.split('/'); + var parentBase = nameParts.slice(0, -1); + + for (var i = 0, l = parts.length; i < l; i++) { + var part = parts[i]; + + if (part === '..') { + if (parentBase.length === 0) { + throw new Error('Cannot access parent module of root'); + } + parentBase.pop(); + } else if (part === '.') { + continue; + } else { + parentBase.push(part); + } + } + + return parentBase.join('/'); + } + + function has(name) { + return !!(registry[name] || registry[name + '/index']); + } + + requirejs.entries = requirejs._eak_seen = registry; + requirejs.has = has; + requirejs.unsee = function (moduleName) { + findModule(moduleName, '(unsee)', false).unsee(); + }; + + requirejs.clear = function () { + requirejs.entries = requirejs._eak_seen = registry = dict(); + seen = dict(); + }; + + // This code primes the JS engine for good performance by warming the + // JIT compiler for these functions. + define('foo', function () {}); + define('foo/bar', [], function () {}); + define('foo/asdf', ['module', 'exports', 'require'], function (module, exports, require) { + if (require.has('foo/bar')) { + require('foo/bar'); + } + }); + define('foo/baz', [], define.alias('foo')); + define('foo/quz', define.alias('foo')); + define('foo/bar', ['foo', './quz', './baz', './asdf', './bar', '../foo'], function () {}); + define('foo/main', ['foo/bar'], function () {}); + + require('foo/main'); + require.unsee('foo/bar'); + + requirejs.clear(); + + if (typeof exports === 'object' && typeof module === 'object' && module.exports) { + module.exports = { require: require, define: define }; + } +})(this); + require("ember-data"); require("ember-load-initializers")["default"](Ember.Application, "ember-data"); ;(function() { var global = require('ember-data/-private/global').default; var DS = require('ember-data').default; @@ -19878,11 +20343,11 @@ get: function() { return DS; } }); })(); -}).call(this); +})(); ;(function() { function processEmberDataShims() { var shims = { 'ember-data': { default: DS }, 'ember-data/model': { default: DS.Model }, @@ -19917,5 +20382,7 @@ if (typeof define !== 'undefined' && define && define.petal) { processEmberDataShims(); } })(); + +//# sourceMappingURL=ember-data.prod.map