ember-data-source 1.0.0.beta.3 → 1.0.0.beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/dist/ember-data-spade.js +49 -0
- data/dist/ember-data-tests.js +75 -0
- data/dist/ember-data.js +2114 -629
- data/dist/ember-data.min.js +15 -14
- data/dist/ember-data.prod.js +2115 -630
- data/lib/ember/data/version.rb +1 -1
- metadata +7 -4
data/dist/ember-data.min.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
/*!
|
|
2
|
+
* @overview Ember Data
|
|
3
|
+
* @copyright Copyright 2011-2013 Tilde Inc. and contributors.
|
|
4
|
+
* Portions Copyright 2011 LivingSocial Inc.
|
|
5
|
+
* @license Licensed under MIT license (see license.js)
|
|
6
|
+
*/
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
// Version: 1.0.0-beta.4
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
!function(){var e,t;!function(){var r={},n={};e=function(e,t,n){r[e]={deps:t,callback:n}},t=function(e){if(n[e])return n[e];n[e]={};var i,a,o,s,c;if(i=r[e],!i)throw new Error("Module '"+e+"' not found.");a=i.deps,o=i.callback,s=[];for(var u=0,d=a.length;d>u;u++)"exports"===a[u]?s.push(c={}):s.push(t(a[u]));var l=o.apply(this,s);return n[e]=c||l}}(),function(){"undefined"==typeof DS&&(DS=Ember.Namespace.create({VERSION:"1.0.0-beta.2"}),"undefined"!=typeof window&&(window.DS=DS),Ember.libraries&&Ember.libraries.registerCoreLibrary("Ember Data",DS.VERSION))}(),function(){function e(e){return function(){return this[e].apply(this,arguments)}}var t=Ember.get,r=(Ember.set,Ember.isNone);DS.JSONSerializer=Ember.Object.extend({primaryKey:"id",applyTransforms:function(e,t){return e.eachTransformedAttribute(function(e,r){var n=this.transformFor(r);t[e]=n.deserialize(t[e])},this),t},normalize:function(e,t){return t?(this.applyTransforms(e,t),t):t},serialize:function(e,r){var n={};if(r&&r.includeId){var i=t(e,"id");i&&(n[t(this,"primaryKey")]=t(e,"id"))}return e.eachAttribute(function(t,r){this.serializeAttribute(e,n,t,r)},this),e.eachRelationship(function(t,r){"belongsTo"===r.kind?this.serializeBelongsTo(e,n,r):"hasMany"===r.kind&&this.serializeHasMany(e,n,r)},this),n},serializeAttribute:function(e,r,n,i){var a=t(this,"attrs"),o=t(e,n),s=i.type;if(s){var c=this.transformFor(s);o=c.serialize(o)}n=a&&a[n]||(this.keyForAttribute?this.keyForAttribute(n):n),r[n]=o},serializeBelongsTo:function(e,n,i){var a=i.key,o=t(e,a);a=this.keyForRelationship?this.keyForRelationship(a,"belongsTo"):a,n[a]=r(o)?o:t(o,"id"),i.options.polymorphic&&this.serializePolymorphicType(e,n,i)},serializeHasMany:function(e,r,n){var i=n.key,a=DS.RelationshipChange.determineRelationshipType(e.constructor,n);("manyToNone"===a||"manyToMany"===a)&&(r[i]=t(e,i).mapBy("id"))},serializePolymorphicType:Ember.K,extract:function(e,t,r,n,i){this.extractMeta(e,t,r);var a="extract"+i.charAt(0).toUpperCase()+i.substr(1);return this[a](e,t,r,n,i)},extractFindAll:e("extractArray"),extractFindQuery:e("extractArray"),extractFindMany:e("extractArray"),extractFindHasMany:e("extractArray"),extractCreateRecord:e("extractSave"),extractUpdateRecord:e("extractSave"),extractDeleteRecord:e("extractSave"),extractFind:e("extractSingle"),extractFindBelongsTo:e("extractSingle"),extractSave:e("extractSingle"),extractSingle:function(e,t,r){return this.normalize(t,r)},extractArray:function(e,t,r){return this.normalize(t,r)},extractMeta:function(e,t,r){r&&r.meta&&(e.metaForType(t,r.meta),delete r.meta)},transformFor:function(e){var t=this.container.lookup("transform:"+e);return t}})}(),function(){var e=Ember.get,t=Ember.String.capitalize,r=Ember.String.underscore,n=window.DS;n.DebugAdapter=Ember.DataAdapter.extend({getFilters:function(){return[{name:"isNew",desc:"New"},{name:"isModified",desc:"Modified"},{name:"isClean",desc:"Clean"}]},detect:function(e){return e!==n.Model&&n.Model.detect(e)},columnsForType:function(n){var i=[{name:"id",desc:"Id"}],a=0,o=this;return e(n,"attributes").forEach(function(e){if(a++>o.attributeLimit)return!1;var n=t(r(e).replace("_"," "));i.push({name:e,desc:n})}),i},getRecords:function(e){return this.get("store").all(e)},getRecordColumnValues:function(t){var r=this,n=0,i={id:e(t,"id")};return t.eachAttribute(function(a){if(n++>r.attributeLimit)return!1;var o=e(t,a);i[a]=o}),i},getRecordKeywords:function(t){var r=[],n=Ember.A(["id"]);return t.eachAttribute(function(e){n.push(e)}),n.forEach(function(n){r.push(e(t,n))}),r},getRecordFilterValues:function(e){return{isNew:e.get("isNew"),isModified:e.get("isDirty")&&!e.get("isNew"),isClean:!e.get("isDirty")}},getRecordColor:function(e){var t="black";return e.get("isNew")?t="green":e.get("isDirty")&&(t="blue"),t},observeRecord:function(e,t){var r=Ember.A(),n=this,i=Ember.A(["id","isNew","isDirty"]);e.eachAttribute(function(e){i.push(e)}),i.forEach(function(i){var a=function(){t(n.wrapRecord(e))};Ember.addObserver(e,i,a),r.push(function(){Ember.removeObserver(e,i,a)})});var a=function(){r.forEach(function(e){e()})};return a}})}(),function(){DS.Transform=Ember.Object.extend({serialize:Ember.required(),deserialize:Ember.required()})}(),function(){DS.BooleanTransform=DS.Transform.extend({deserialize:function(e){var t=typeof e;return"boolean"===t?e:"string"===t?null!==e.match(/^true$|^t$|^1$/i):"number"===t?1===e:!1},serialize:function(e){return Boolean(e)}})}(),function(){DS.DateTransform=DS.Transform.extend({deserialize:function(e){var t=typeof e;return"string"===t?new Date(Ember.Date.parse(e)):"number"===t?new Date(e):null===e||void 0===e?e:null},serialize:function(e){if(e instanceof Date){var t=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],r=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],n=function(e){return 10>e?"0"+e:""+e},i=e.getUTCFullYear(),a=e.getUTCMonth(),o=e.getUTCDate(),s=e.getUTCDay(),c=e.getUTCHours(),u=e.getUTCMinutes(),d=e.getUTCSeconds(),l=t[s],h=n(o),f=r[a];return l+", "+h+" "+f+" "+i+" "+n(c)+":"+n(u)+":"+n(d)+" GMT"}return null}})}(),function(){var e=Ember.isEmpty;DS.NumberTransform=DS.Transform.extend({deserialize:function(t){return e(t)?null:Number(t)},serialize:function(t){return e(t)?null:Number(t)}})}(),function(){var e=Ember.isNone;DS.StringTransform=DS.Transform.extend({deserialize:function(t){return e(t)?null:String(t)},serialize:function(t){return e(t)?null:String(t)}})}(),function(){Ember.set,Ember.onLoad("Ember.Application",function(e){e.initializer({name:"store",initialize:function(e,t){t.register("store:main",t.Store||DS.Store),t.register("serializer:_default",DS.JSONSerializer),t.register("serializer:_rest",DS.RESTSerializer),t.register("adapter:_rest",DS.RESTAdapter),e.lookup("store:main")}}),e.initializer({name:"transforms",initialize:function(e,t){t.register("transform:boolean",DS.BooleanTransform),t.register("transform:date",DS.DateTransform),t.register("transform:number",DS.NumberTransform),t.register("transform:string",DS.StringTransform)}}),e.initializer({name:"dataAdapter",initialize:function(e,t){t.register("dataAdapter:main",DS.DebugAdapter)}}),e.initializer({name:"injectStore",initialize:function(e,t){t.inject("controller","store","store:main"),t.inject("route","store","store:main"),t.inject("serializer","store","store:main"),t.inject("dataAdapter","store","store:main")}})})}(),function(){Ember.Date=Ember.Date||{};var e=Date.parse,t=[1,4,5,6,7,10,11];Ember.Date.parse=function(r){var n,i,a=0;if(i=/^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(r)){for(var o,s=0;o=t[s];++s)i[o]=+i[o]||0;i[2]=(+i[2]||1)-1,i[3]=+i[3]||1,"Z"!==i[8]&&void 0!==i[9]&&(a=60*i[10]+i[11],"+"===i[9]&&(a=0-a)),n=Date.UTC(i[1],i[2],i[3],i[4],i[5]+a,i[6],i[7])}else n=e?e(r):0/0;return n},(Ember.EXTEND_PROTOTYPES===!0||Ember.EXTEND_PROTOTYPES.Date)&&(Date.parse=Ember.Date.parse)}(),function(){var e=Ember.get;Ember.set,DS.RecordArray=Ember.ArrayProxy.extend(Ember.Evented,{type:null,content:null,isLoaded:!1,isUpdating:!1,store:null,objectAtContent:function(t){var r=e(this,"content");return r.objectAt(t)},update:function(){if(!e(this,"isUpdating")){var t=e(this,"store"),r=e(this,"type");t.fetchAll(r,this)}},addRecord:function(t){e(this,"content").addObject(t)},removeRecord:function(t){e(this,"content").removeObject(t)},save:function(){var e=Ember.RSVP.all(this.invoke("save")).then(function(e){return Ember.A(e)});return DS.PromiseArray.create({promise:e})}})}(),function(){var e=Ember.get;DS.FilteredRecordArray=DS.RecordArray.extend({filterFunction:null,isLoaded:!0,replace:function(){var t=e(this,"type").toString();throw new Error("The result of a client-side filter (on "+t+") is immutable.")},updateFilter:Ember.observer(function(){var t=e(this,"manager");t.updateFilter(this,e(this,"type"),e(this,"filterFunction"))},"filterFunction")})}(),function(){var e=Ember.get;Ember.set,DS.AdapterPopulatedRecordArray=DS.RecordArray.extend({query:null,replace:function(){var t=e(this,"type").toString();throw new Error("The result of a server query (on "+t+") is immutable.")},load:function(t){var r=e(this,"store"),n=e(this,"type"),i=r.pushMany(n,t),a=r.metadataFor(n);this.setProperties({content:Ember.A(i),isLoaded:!0,meta:a}),Ember.run.once(this,"trigger","didLoad")}})}(),function(){var e=Ember.get,t=Ember.set,r=Ember.EnumerableUtils.map;DS.ManyArray=DS.RecordArray.extend({init:function(){this._super.apply(this,arguments),this._changesToSync=Ember.OrderedSet.create()},owner:null,isPolymorphic:!1,isLoaded:!1,loadingRecordsCount:function(e){this.loadingRecordsCount=e},loadedRecord:function(){this.loadingRecordsCount--,0===this.loadingRecordsCount&&(t(this,"isLoaded",!0),this.trigger("didLoad"))},fetch:function(){var t=e(this,"content"),r=e(this,"store"),n=e(this,"owner"),i=Ember.RSVP.defer(),a=t.filterProperty("isEmpty",!0);r.fetchMany(a,n,i)},replaceContent:function(e,t,n){n=r(n,function(e){return e},this),this._super(e,t,n)},arrangedContentDidChange:function(){Ember.run.once(this,"fetch")},arrayContentWillChange:function(t,r){var n=e(this,"owner"),i=e(this,"name");if(!n._suspendedRelationships)for(var a=t;t+r>a;a++){var o=e(this,"content").objectAt(a),s=DS.RelationshipChange.createChange(n,o,e(this,"store"),{parentType:n.constructor,changeType:"remove",kind:"hasMany",key:i});this._changesToSync.add(s)}return this._super.apply(this,arguments)},arrayContentDidChange:function(t,r,n){this._super.apply(this,arguments);var i=e(this,"owner"),a=e(this,"name"),o=e(this,"store");if(!i._suspendedRelationships){for(var s=t;t+n>s;s++){var c=e(this,"content").objectAt(s),u=DS.RelationshipChange.createChange(i,c,o,{parentType:i.constructor,changeType:"add",kind:"hasMany",key:a});u.hasManyName=a,this._changesToSync.add(u)}this._changesToSync.forEach(function(e){e.sync()}),this._changesToSync.clear()}},createRecord:function(t){var r,n=e(this,"owner"),i=e(n,"store"),a=e(this,"type");return r=i.createRecord.call(i,a,t),this.pushObject(r),r}})}(),function(){function e(e){var t=Ember.meta(e,!0),r="DS.Mappable",n=t[r];return n||(t[r]={}),t.hasOwnProperty(r)||(t[r]=Ember.create(t[r])),t[r]}Ember.get;var t=Ember.ArrayPolyfills.forEach,r=function(e){return e},n=function(e){return e},i=function(e,t){return t};DS._Mappable=Ember.Mixin.create({createInstanceMapFor:function(t){var r=e(this);if(r.values=r.values||{},r.values[t])return r.values[t];for(var n=r.values[t]=new Ember.Map,i=this.constructor;i&&i!==DS.Store;)this._copyMap(t,i,n),i=i.superclass;return r.values[t]=n,n},_copyMap:function(a,o,s){function c(e,t){var a=(o.transformMapKey||n)(e,t),c=(o.transformMapValue||i)(e,t),u=s.get(a),d=c;u&&(d=(this.constructor.resolveMapConflict||r)(u,d)),s.set(a,d)}var u=e(o),d=u[a];d&&t.call(d,c,this)}}),DS._Mappable.generateMapFunctionFor=function(t,r){return function(n,i){var a=e(this),o=a[t]||Ember.MapWithDefault.create({defaultValue:function(){return{}}});r.call(this,n,i,o),a[t]=o}}}(),function(){function e(e,r,a,o){return r.eachRelationship(function(r,s){if(a.links&&a.links[r])return o&&s.options.async&&(o._relationships[r]=null),void 0;var c=s.kind,u=a[r];null!=u&&("belongsTo"===c?t(e,a,r,s,u):"hasMany"===c&&(n(e,a,r,s,u),i(o,r,u)))}),a}function t(e,t,n,i,a){if(!(v(a)||a instanceof DS.Model)){var o;"number"==typeof a||"string"==typeof a?(o=r(i,n,t),t[n]=e.recordForId(o,a)):"object"==typeof a&&(t[n]=e.recordForId(a.type,a.id))}}function r(e,t,r){return e.options.polymorphic?r[t+"Type"]:e.type}function n(e,r,n,i,a){for(var o=0,s=a.length;s>o;o++)t(e,a,o,i,a[o])}function i(e,t,r){e&&r.pushObjects(e.get(t).filterBy("isNew"))}function a(e){return DS.PromiseObject.create({promise:e})}function o(e){return DS.PromiseArray.create({promise:e})}function s(e,t,r){return e.lookup("serializer:"+t)||e.lookup("serializer:application")||e.lookup("serializer:"+r)||e.lookup("serializer:_default")}function c(e,t){var r=e.serializer,n=e.defaultSerializer,i=e.container;return i&&void 0===r&&(r=s(i,t.typeKey,n)),(null===r||void 0===r)&&(r={extract:function(e,t,r){return r}}),r}function u(e,t,r,n,i){var a=e.find(t,r,n),o=c(e,r);return D(a).then(function(e){return e=o.extract(t,r,e,n,"find"),t.push(r,e)},function(e){var i=t.getById(r,n);throw i.notFound(),e}).then(i.resolve,i.reject)}function d(e,t,r,n,i,a){var o=e.findMany(t,r,n,i),s=c(e,r);return D(o).then(function(e){e=s.extract(t,r,e,null,"findMany"),t.pushMany(r,e)}).then(a.resolve,a.reject)}function l(e,t,r,n,i,a){var o=e.findHasMany(t,r,n,i),s=c(e,i.type);return D(o).then(function(e){e=s.extract(t,i.type,e,null,"findHasMany");var n=t.pushMany(i.type,e);r.updateHasMany(i.key,n)}).then(a.resolve,a.reject)}function h(e,t,r,n,i,a){var o=e.findBelongsTo(t,r,n,i),s=c(e,i.type);return D(o).then(function(e){e=s.extract(t,i.type,e,null,"findBelongsTo");var r=t.push(i.type,e);return r.updateBelongsTo(i.key,r),r}).then(a.resolve,a.reject)}function f(e,t,r,n,i){var a=e.findAll(t,r,n),o=c(e,r);return D(a).then(function(e){return e=o.extract(t,r,e,null,"findAll"),t.pushMany(r,e),t.didUpdateAll(r),t.all(r)}).then(i.resolve,i.reject)}function p(e,t,r,n,i,a){var o=e.findQuery(t,r,n,i),s=c(e,r);return D(o).then(function(e){return e=s.extract(t,r,e,null,"findAll"),i.load(e),i}).then(a.resolve,a.reject)}function m(e,t,r,n,i){var a=n.constructor,o=e[r](t,a,n),s=c(e,a);return o.then(function(e){return e&&(e=s.extract(t,a,e,y(n,"id"),r)),t.didSaveRecord(n,e),n},function(e){throw e instanceof DS.InvalidError?t.recordWasInvalid(n,e.errors):t.recordWasError(n,e),e}).then(i.resolve,i.reject)}var y=Ember.get,g=Ember.set,b=Ember.run.once,v=Ember.isNone,R=Ember.EnumerableUtils.forEach,E=Ember.EnumerableUtils.indexOf,S=Ember.EnumerableUtils.map,D=Ember.RSVP.resolve,T=function(e){return null==e?null:e+""};DS.Store=Ember.Object.extend(DS._Mappable,{init:function(){this.typeMaps={},this.recordArrayManager=DS.RecordArrayManager.create({store:this}),this._relationshipChanges={},this._pendingSave=[]},adapter:"_rest",serialize:function(e,t){return this.serializerFor(e.constructor.typeKey).serialize(e,t)},defaultAdapter:Ember.computed(function(){var e=y(this,"adapter");return"string"==typeof e&&(e=this.container.lookup("adapter:"+e)||this.container.lookup("adapter:application")||this.container.lookup("adapter:_rest")),DS.Adapter.detect(e)&&(e=e.create({container:this.container})),e}).property("adapter"),createRecord:function(e,t){e=this.modelFor(e),t=t||{},v(t.id)&&(t.id=this._generateId(e)),t.id=T(t.id);var r=this.buildRecord(e,t.id);return r.loadedData(),r.setProperties(t),r},_generateId:function(e){var t=this.adapterFor(e);return t&&t.generateIdForRecord?t.generateIdForRecord(this):null},deleteRecord:function(e){e.deleteRecord()},unloadRecord:function(e){e.unloadRecord()},find:function(e,t){return void 0===t?this.findAll(e):"object"===Ember.typeOf(t)?this.findQuery(e,t):this.findById(e,T(t))},findById:function(e,t){e=this.modelFor(e);var r=this.recordForId(e,t),n=this.fetchRecord(r)||D(r);return a(n)},findByIds:function(e,t){var r=this;return o(Ember.RSVP.all(S(t,function(t){return r.findById(e,t)})).then(function(e){return Ember.A(e)}))},fetchRecord:function(e){if(v(e))return null;if(e._loadingPromise)return e._loadingPromise;if(!y(e,"isEmpty"))return null;var t=e.constructor,r=y(e,"id"),n=Ember.RSVP.defer();e.loadingData(n.promise);var i=this.adapterFor(t);return u(i,this,t,r,n),n.promise},getById:function(e,t){return e=this.modelFor(e),this.hasRecordForId(e,t)?this.recordForId(e,t):null},reloadRecord:function(e,t){var r=e.constructor,n=this.adapterFor(r),i=y(e,"id");return u(n,this,r,i,t)},fetchMany:function(e,t,r){if(e.length){var n=Ember.MapWithDefault.create({defaultValue:function(){return Ember.A()}});R(e,function(e){n.get(e.constructor).push(e)}),R(n,function(e,n){var i=n.mapProperty("id"),a=this.adapterFor(e);d(a,this,e,i,t,r)},this)}},hasRecordForId:function(e,t){return t=T(t),!!this.typeMapFor(e).idToRecord[t]},recordForId:function(e,t){e=this.modelFor(e),t=T(t);var r=this.typeMapFor(e).idToRecord[t];return r||(r=this.buildRecord(e,t)),r},findMany:function(e,t,r,n){r=this.modelFor(r),t=Ember.A(t);var i=t.filterProperty("isEmpty",!0),a=this.recordArrayManager.createManyArray(r,t);return R(i,function(e){e.loadingData()}),a.loadingRecordsCount=i.length,i.length?(R(i,function(e){this.recordArrayManager.registerWaitingRecordArray(e,a)},this),this.fetchMany(i,e,n)):(n&&n.resolve(),a.set("isLoaded",!0),Ember.run.once(a,"trigger","didLoad")),a},findHasMany:function(e,t,r,n){var i=this.adapterFor(e.constructor),a=this.recordArrayManager.createManyArray(r.type,Ember.A([]));return l(i,this,e,t,r,n),a},findBelongsTo:function(e,t,r,n){var i=this.adapterFor(e.constructor);h(i,this,e,t,r,n)},findQuery:function(e,t){e=this.modelFor(e);var r=DS.AdapterPopulatedRecordArray.create({type:e,query:t,content:Ember.A(),store:this}),n=this.adapterFor(e),i=Ember.RSVP.defer();return p(n,this,e,t,r,i),o(i.promise)},findAll:function(e){return e=this.modelFor(e),this.fetchAll(e,this.all(e))},fetchAll:function(e,t){var r=this.adapterFor(e),n=this.typeMapFor(e).metadata.since,i=Ember.RSVP.defer();return g(t,"isUpdating",!0),f(r,this,e,n,i),o(i.promise)},didUpdateAll:function(e){var t=this.typeMapFor(e).findAllCache;g(t,"isUpdating",!1)},all:function(e){e=this.modelFor(e);var t=this.typeMapFor(e),r=t.findAllCache;if(r)return r;var n=DS.RecordArray.create({type:e,content:Ember.A(),store:this,isLoaded:!0});return this.recordArrayManager.registerFilteredRecordArray(n,e),t.findAllCache=n,n},unloadAll:function(e){e=this.modelFor(e);for(var t,r=this.typeMapFor(e),n=r.records;t=n.pop();)t.unloadRecord()},filter:function(e,t,r){var n;3===arguments.length?n=this.findQuery(e,t):2===arguments.length&&(r=t),e=this.modelFor(e);var i=DS.FilteredRecordArray.create({type:e,content:Ember.A(),store:this,manager:this.recordArrayManager,filterFunction:r});return this.recordArrayManager.registerFilteredRecordArray(i,e,r),n?n.then(function(){return i}):i},recordIsLoaded:function(e,t){return this.hasRecordForId(e,t)?!y(this.recordForId(e,t),"isEmpty"):!1},metadataFor:function(e){return e=this.modelFor(e),this.typeMapFor(e).metadata},dataWasUpdated:function(e,t){y(t,"isDeleted")||y(t,"isLoaded")&&this.recordArrayManager.recordDidChange(t)},scheduleSave:function(e,t){e.adapterWillCommit(),this._pendingSave.push([e,t]),b(this,"flushPendingSave")},flushPendingSave:function(){var e=this._pendingSave.slice();this._pendingSave=[],R(e,function(e){var t,r=e[0],n=e[1],i=this.adapterFor(r.constructor);t=y(r,"isNew")?"createRecord":y(r,"isDeleted")?"deleteRecord":"updateRecord",m(i,this,t,r,n)},this)},didSaveRecord:function(t,r){r&&(r=e(this,t.constructor,r,t),this.updateId(t,r)),t.adapterDidCommit(r)},recordWasInvalid:function(e,t){e.adapterDidInvalidate(t)},recordWasError:function(e){e.adapterDidError()},updateId:function(e,t){var r=(y(e,"id"),T(t.id));this.typeMapFor(e.constructor).idToRecord[r]=e,g(e,"id",r)},typeMapFor:function(e){var t,r=y(this,"typeMaps"),n=Ember.guidFor(e);return(t=r[n])?t:(t={idToRecord:{},records:[],metadata:{}},r[n]=t,t)},_load:function(e,t,r){var n=T(t.id),i=this.recordForId(e,n);return i.setupData(t,r),this.recordArrayManager.recordDidChange(i),i},modelFor:function(e){var t;return"string"==typeof e?(t=this.container.lookupFactory("model:"+e),t.typeKey=e):t=e,t.store=this,t},push:function(t,r,n){return t=this.modelFor(t),r=e(this,t,r),this._load(t,r,n),this.recordForId(t,r.id)},pushPayload:function(e,t){var r=this.serializerFor(e);r.pushPayload(this,t)},update:function(e,t){return this.push(e,t,!0)},pushMany:function(e,t){return S(t,function(t){return this.push(e,t)},this)},metaForType:function(e,t){e=this.modelFor(e),Ember.merge(this.typeMapFor(e).metadata,t)},buildRecord:function(e,t,r){var n=this.typeMapFor(e),i=n.idToRecord,a=e._create({id:t,store:this,container:this.container});return r&&a.setupData(r),t&&(i[t]=a),n.records.push(a),a},dematerializeRecord:function(e){var t=e.constructor,r=this.typeMapFor(t),n=y(e,"id");e.updateRecordArrays(),n&&delete r.idToRecord[n];var i=E(r.records,e);r.records.splice(i,1)},addRelationshipChangeFor:function(e,t,r,n,i){var a=e.clientId,o=r?r:r,s=t+n,c=this._relationshipChanges;a in c||(c[a]={}),o in c[a]||(c[a][o]={}),s in c[a][o]||(c[a][o][s]={}),c[a][o][s][i.changeType]=i},removeRelationshipChangeFor:function(e,t,r,n,i){var a=e.clientId,o=r?r.clientId:r,s=this._relationshipChanges,c=t+n;a in s&&o in s[a]&&c in s[a][o]&&delete s[a][o][c][i]},relationshipChangePairsFor:function(e){var t=[];if(!e)return t;var r=this._relationshipChanges[e.clientId];for(var n in r)if(r.hasOwnProperty(n))for(var i in r[n])r[n].hasOwnProperty(i)&&t.push(r[n][i]);return t},adapterFor:function(e){var t,r=this.container;return r&&(t=r.lookup("adapter:"+e.typeKey)||r.lookup("adapter:application")),t||y(this,"defaultAdapter")},serializerFor:function(e){e=this.modelFor(e);var t=this.adapterFor(e);return s(this.container,e.typeKey,t&&t.defaultSerializer)}}),DS.PromiseArray=Ember.ArrayProxy.extend(Ember.PromiseProxyMixin),DS.PromiseObject=Ember.ObjectProxy.extend(Ember.PromiseProxyMixin)}(),function(){function e(t){var r,n={};for(var i in t)r=t[i],n[i]=r&&"object"==typeof r?e(r):r;return n}function t(e,t){for(var r in t)e[r]=t[r];return e}function r(r){var n=e(c);return t(n,r)}function n(e,r,i){e=t(r?Ember.create(r):{},e),e.parentState=r,e.stateName=i;for(var a in e)e.hasOwnProperty(a)&&"parentState"!==a&&"stateName"!==a&&"object"==typeof e[a]&&(e[a]=n(e[a],e,i+"."+a));return e}var i=Ember.get,a=Ember.set,o=function(e){var t,r,n,i=Ember.keys(e);for(t=0,r=i.length;r>t;t++)if(n=i[t],e.hasOwnProperty(n)&&e[n])return!0;return!1},s=function(e,t){t.value===t.originalValue?(delete e._attributes[t.name],e.send("propertyWasReset",t.name)):t.value!==t.oldValue&&e.send("becomeDirty"),e.updateRecordArraysLater()},c={initialState:"uncommitted",isDirty:!0,uncommitted:{didSetProperty:s,propertyWasReset:function(e){var t=!1;for(var r in e._attributes){t=!0;break}t||e.send("rolledBack")},pushedData:Ember.K,becomeDirty:Ember.K,willCommit:function(e){e.transitionTo("inFlight")},reloadRecord:function(e,t){i(e,"store").reloadRecord(e,t)},rolledBack:function(e){e.transitionTo("loaded.saved")},becameInvalid:function(e){e.transitionTo("invalid")},rollback:function(e){e.rollback()}},inFlight:{isSaving:!0,didSetProperty:s,becomeDirty:Ember.K,pushedData:Ember.K,willCommit:Ember.K,didCommit:function(e){var t=i(this,"dirtyType");e.transitionTo("saved"),e.send("invokeLifecycleCallbacks",t)},becameInvalid:function(e,t){a(e,"errors",t),e.transitionTo("invalid"),e.send("invokeLifecycleCallbacks")},becameError:function(e){e.transitionTo("uncommitted"),e.triggerLater("becameError",e)}},invalid:{isValid:!1,deleteRecord:function(e){e.transitionTo("deleted.uncommitted"),e.clearRelationships()},didSetProperty:function(e,t){var r=i(e,"errors"),n=t.name;a(r,n,null),o(r)||e.send("becameValid"),s(e,t)},becomeDirty:Ember.K,rollback:function(e){e.send("becameValid"),e.send("rollback")},becameValid:function(e){e.transitionTo("uncommitted")},invokeLifecycleCallbacks:function(e){e.triggerLater("becameInvalid",e)}}},u=r({dirtyType:"created",isNew:!0});u.uncommitted.rolledBack=function(e){e.transitionTo("deleted.saved")};var d=r({dirtyType:"updated"});u.uncommitted.deleteRecord=function(e){e.clearRelationships(),e.transitionTo("deleted.saved")},u.uncommitted.rollback=function(e){c.uncommitted.rollback.apply(this,arguments),e.transitionTo("deleted.saved")},d.uncommitted.deleteRecord=function(e){e.transitionTo("deleted.uncommitted"),e.clearRelationships()};var l={isEmpty:!1,isLoading:!1,isLoaded:!1,isDirty:!1,isSaving:!1,isDeleted:!1,isNew:!1,isValid:!0,rolledBack:Ember.K,propertyWasReset:Ember.K,empty:{isEmpty:!0,loadingData:function(e,t){e._loadingPromise=t,e.transitionTo("loading")},loadedData:function(e){e.transitionTo("loaded.created.uncommitted"),e.suspendRelationshipObservers(function(){e.notifyPropertyChange("data")})},pushedData:function(e){e.transitionTo("loaded.saved"),e.triggerLater("didLoad")}},loading:{isLoading:!0,exit:function(e){e._loadingPromise=null},pushedData:function(e){e.transitionTo("loaded.saved"),e.triggerLater("didLoad"),a(e,"isError",!1)},becameError:function(e){e.triggerLater("becameError",e)},notFound:function(e){e.transitionTo("empty")}},loaded:{initialState:"saved",isLoaded:!0,saved:{setup:function(e){var t=e._attributes,r=!1;for(var n in t)if(t.hasOwnProperty(n)){r=!0;break}r&&e.adapterDidDirty()},didSetProperty:s,pushedData:Ember.K,becomeDirty:function(e){e.transitionTo("updated.uncommitted")},willCommit:function(e){e.transitionTo("updated.inFlight")},reloadRecord:function(e,t){i(e,"store").reloadRecord(e,t)},deleteRecord:function(e){e.transitionTo("deleted.uncommitted"),e.clearRelationships()},unloadRecord:function(e){e.clearRelationships(),e.transitionTo("deleted.saved")},didCommit:function(e){e.send("invokeLifecycleCallbacks",i(e,"lastDirtyType"))}},created:u,updated:d},deleted:{initialState:"uncommitted",dirtyType:"deleted",isDeleted:!0,isLoaded:!0,isDirty:!0,setup:function(e){var t=i(e,"store");t.recordArrayManager.remove(e)},uncommitted:{willCommit:function(e){e.transitionTo("inFlight")},rollback:function(e){e.rollback()},becomeDirty:Ember.K,deleteRecord:Ember.K,rolledBack:function(e){e.transitionTo("loaded.saved")}},inFlight:{isSaving:!0,willCommit:Ember.K,didCommit:function(e){e.transitionTo("saved"),e.send("invokeLifecycleCallbacks")},becameError:function(e){e.transitionTo("uncommitted"),e.triggerLater("becameError",e)}},saved:{isDirty:!1,setup:function(e){var t=i(e,"store");t.dematerializeRecord(e)},invokeLifecycleCallbacks:function(e){e.triggerLater("didDelete",e),e.triggerLater("didCommit",e)}}},invokeLifecycleCallbacks:function(e,t){"created"===t?e.triggerLater("didCreate",e):e.triggerLater("didUpdate",e),e.triggerLater("didCommit",e)}};l=n(l,null,"root"),DS.RootState=l}(),function(){var e=Ember.get,t=Ember.set,r=Ember.merge,n=Ember.run.once,i=Ember.computed(function(t){return e(e(this,"currentState"),t)}).property("currentState").readOnly();DS.Model=Ember.Object.extend(Ember.Evented,{isEmpty:i,isLoading:i,isLoaded:i,isDirty:i,isSaving:i,isDeleted:i,isNew:i,isValid:i,dirtyType:i,isError:!1,isReloading:!1,clientId:null,id:null,transaction:null,currentState:null,errors:null,serialize:function(t){var r=e(this,"store");return r.serialize(this,t)},toJSON:function(e){var t=DS.JSONSerializer.create({container:this.container});return t.serialize(this,e)},didLoad:Ember.K,didReload:Ember.K,didUpdate:Ember.K,didCreate:Ember.K,didDelete:Ember.K,becameInvalid:Ember.K,becameError:Ember.K,data:Ember.computed(function(){return this._data=this._data||{},this._data}).property(),_data:null,init:function(){t(this,"currentState",DS.RootState.empty),this._super(),this._setup()},_setup:function(){this._changesToSync={},this._deferredTriggers=[],this._data={},this._attributes={},this._inFlightAttributes={},this._relationships={}},send:function(t,r){var n=e(this,"currentState");return n[t]||this._unhandledEvent(n,t,r),n[t](this,r)},transitionTo:function(r){var n=r.split(".",1),i=e(this,"currentState"),a=i;do a.exit&&a.exit(this),a=a.parentState;while(!a.hasOwnProperty(n));var o,s,c=r.split("."),u=[],d=[];for(o=0,s=c.length;s>o;o++)a=a[c[o]],a.enter&&d.push(a),a.setup&&u.push(a);for(o=0,s=d.length;s>o;o++)d[o].enter(this);for(t(this,"currentState",a),o=0,s=u.length;s>o;o++)u[o].setup(this);this.updateRecordArraysLater()},_unhandledEvent:function(e,t,r){var n="Attempted to handle event `"+t+"` ";throw n+="on "+String(this)+" while in state ",n+=e.stateName+". ",void 0!==r&&(n+="Called with "+Ember.inspect(r)+"."),new Ember.Error(n)},withTransaction:function(t){var r=e(this,"transaction");r&&t(r)},loadingData:function(e){this.send("loadingData",e)},loadedData:function(){this.send("loadedData")},notFound:function(){this.send("notFound")},pushedData:function(){this.send("pushedData")},deleteRecord:function(){this.send("deleteRecord")},destroyRecord:function(){return this.deleteRecord(),this.save()},unloadRecord:function(){this.send("unloadRecord")},clearRelationships:function(){this.eachRelationship(function(e,r){if("belongsTo"===r.kind)t(this,e,null);else if("hasMany"===r.kind){var n=this._relationships[r.name];n&&n.clear()}},this)},updateRecordArrays:function(){var t=e(this,"store");t&&t.dataWasUpdated(this.constructor,this)},changedAttributes:function(){var t,r=e(this,"_data"),n=e(this,"_attributes"),i={};for(t in n)i[t]=[r[t],n[t]];return i},adapterWillCommit:function(){this.send("willCommit")},adapterDidCommit:function(e){t(this,"isError",!1),e?this._data=e:Ember.mixin(this._data,this._inFlightAttributes),this._inFlightAttributes={},this.send("didCommit"),this.updateRecordArraysLater(),e&&this.suspendRelationshipObservers(function(){this.notifyPropertyChange("data")})},adapterDidDirty:function(){this.send("becomeDirty"),this.updateRecordArraysLater()},dataDidChange:Ember.observer(function(){this.reloadHasManys()},"data"),reloadHasManys:function(){var t=e(this.constructor,"relationshipsByName");this.updateRecordArraysLater(),t.forEach(function(e,t){this._data.links&&this._data.links[e]||"hasMany"===t.kind&&this.hasManyDidChange(t.key)},this)},hasManyDidChange:function(e){var r=this._relationships[e];if(r){var n=this._data[e]||[];t(r,"content",Ember.A(n)),t(r,"isLoaded",!0),r.trigger("didLoad")}},updateRecordArraysLater:function(){Ember.run.once(this,this.updateRecordArrays)},setupData:function(e,t){t?Ember.merge(this._data,e):this._data=e;var r=this._relationships;this.eachRelationship(function(t,n){e.links&&e.links[t]||n.options.async&&(r[t]=null)}),e&&this.pushedData(),this.suspendRelationshipObservers(function(){this.notifyPropertyChange("data")})},materializeId:function(e){t(this,"id",e)},materializeAttributes:function(e){r(this._data,e)},materializeAttribute:function(e,t){this._data[e]=t},updateHasMany:function(e,t){this._data[e]=t,this.hasManyDidChange(e)},updateBelongsTo:function(e,t){this._data[e]=t},rollback:function(){this._attributes={},e(this,"isError")&&(this._inFlightAttributes={},t(this,"isError",!1)),this.send("rolledBack"),this.suspendRelationshipObservers(function(){this.notifyPropertyChange("data")})},toStringExtension:function(){return e(this,"id")},suspendRelationshipObservers:function(t,r){var n=e(this.constructor,"relationshipNames").belongsTo,i=this;try{this._suspendedRelationships=!0,Ember._suspendObservers(i,n,null,"belongsToDidChange",function(){Ember._suspendBeforeObservers(i,n,null,"belongsToWillChange",function(){t.call(r||i)})})}finally{this._suspendedRelationships=!1}},save:function(){var e=Ember.RSVP.defer();return this.get("store").scheduleSave(this,e),this._inFlightAttributes=this._attributes,this._attributes={},DS.PromiseObject.create({promise:e.promise})},reload:function(){t(this,"isReloading",!0);var e=Ember.RSVP.defer(),r=this;return e.promise=e.promise.then(function(){return r.set("isReloading",!1),r.set("isError",!1),r},function(e){throw r.set("isError",!0),e}),this.send("reloadRecord",e),DS.PromiseObject.create({promise:e.promise})},adapterDidUpdateAttribute:function(e,t){void 0!==t?(this._data[e]=t,this.notifyPropertyChange(e)):this._data[e]=this._inFlightAttributes[e],this.updateRecordArraysLater()},adapterDidInvalidate:function(e){this.send("becameInvalid",e)},adapterDidError:function(){this.send("becameError"),t(this,"isError",!0)},trigger:function(e){Ember.tryInvoke(this,e,[].slice.call(arguments,1)),this._super.apply(this,arguments)},triggerLater:function(){this._deferredTriggers.push(arguments),n(this,"_triggerDeferredTriggers")},_triggerDeferredTriggers:function(){for(var e=0,t=this._deferredTriggers.length;t>e;e++)this.trigger.apply(this,this._deferredTriggers[e]);this._deferredTriggers=[]}}),DS.Model.reopenClass({_create:DS.Model.create,create:function(){throw new Ember.Error("You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.")}})}(),function(){function e(e,t){return"function"==typeof t.defaultValue?t.defaultValue():t.defaultValue}function t(e,t){return e._attributes.hasOwnProperty(t)||e._inFlightAttributes.hasOwnProperty(t)||e._data.hasOwnProperty(t)}function r(e,t){return e._attributes.hasOwnProperty(t)?e._attributes[t]:e._inFlightAttributes.hasOwnProperty(t)?e._inFlightAttributes[t]:e._data[t]}var n=Ember.get;DS.Model.reopenClass({attributes:Ember.computed(function(){var e=Ember.Map.create();return this.eachComputedProperty(function(t,r){r.isAttribute&&(r.name=t,e.set(t,r))}),e}),transformedAttributes:Ember.computed(function(){var e=Ember.Map.create();return this.eachAttribute(function(t,r){r.type&&e.set(t,r.type)}),e}),eachAttribute:function(e,t){n(this,"attributes").forEach(function(r,n){e.call(t,r,n)},t)},eachTransformedAttribute:function(e,t){n(this,"transformedAttributes").forEach(function(r,n){e.call(t,r,n)
|
|
17
|
-
})}}),DS.Model.reopen({eachAttribute:function(e,t){this.constructor.eachAttribute(e,t)}}),DS.attr=function(n,i){i=i||{};var a={type:n,isAttribute:!0,options:i};return Ember.computed(function(n,a){if(arguments.length>1){var o=this._attributes[n]||this._inFlightAttributes[n]||this._data[n];return this.send("didSetProperty",{name:n,oldValue:o,originalValue:this._data[n],value:a}),this._attributes[n]=a,a}return t(this,n)?r(this,n):e(this,i,n)}).property("data").meta(a)}}(),function(){var e=DS.AttributeChange=function(e){this.record=e.record,this.store=e.store,this.name=e.name,this.value=e.value,this.oldValue=e.oldValue};e.createChange=function(t){return new e(t)},e.prototype={sync:function(){this.value!==this.oldValue&&(this.record.send("becomeDirty"),this.record.updateRecordArraysLater()),this.destroy()},destroy:function(){delete this.record._changesToSync[this.name]}}}(),function(){function e(e){return"object"==typeof e&&(!e.then||"function"!=typeof e.then)}var t=Ember.get,r=Ember.set,n=Ember.EnumerableUtils.forEach;DS.RelationshipChange=function(e){this.parentRecord=e.parentRecord,this.childRecord=e.childRecord,this.firstRecord=e.firstRecord,this.firstRecordKind=e.firstRecordKind,this.firstRecordName=e.firstRecordName,this.secondRecord=e.secondRecord,this.secondRecordKind=e.secondRecordKind,this.secondRecordName=e.secondRecordName,this.changeType=e.changeType,this.store=e.store,this.committed={}},DS.RelationshipChangeAdd=function(e){DS.RelationshipChange.call(this,e)},DS.RelationshipChangeRemove=function(e){DS.RelationshipChange.call(this,e)},DS.RelationshipChange.create=function(e){return new DS.RelationshipChange(e)},DS.RelationshipChangeAdd.create=function(e){return new DS.RelationshipChangeAdd(e)},DS.RelationshipChangeRemove.create=function(e){return new DS.RelationshipChangeRemove(e)},DS.OneToManyChange={},DS.OneToNoneChange={},DS.ManyToNoneChange={},DS.OneToOneChange={},DS.ManyToManyChange={},DS.RelationshipChange._createChange=function(e){return"add"===e.changeType?DS.RelationshipChangeAdd.create(e):"remove"===e.changeType?DS.RelationshipChangeRemove.create(e):void 0},DS.RelationshipChange.determineRelationshipType=function(e,t){var r,n,i=t.key,a=t.kind,o=e.inverseFor(i);return o&&(r=o.name,n=o.kind),o?"belongsTo"===n?"belongsTo"===a?"oneToOne":"manyToOne":"belongsTo"===a?"oneToMany":"manyToMany":"belongsTo"===a?"oneToNone":"manyToNone"},DS.RelationshipChange.createChange=function(e,t,r,n){var i,a=e.constructor;return i=DS.RelationshipChange.determineRelationshipType(a,n),"oneToMany"===i?DS.OneToManyChange.createChange(e,t,r,n):"manyToOne"===i?DS.OneToManyChange.createChange(t,e,r,n):"oneToNone"===i?DS.OneToNoneChange.createChange(e,t,r,n):"manyToNone"===i?DS.ManyToNoneChange.createChange(e,t,r,n):"oneToOne"===i?DS.OneToOneChange.createChange(e,t,r,n):"manyToMany"===i?DS.ManyToManyChange.createChange(e,t,r,n):void 0},DS.OneToNoneChange.createChange=function(e,t,r,n){var i=n.key,a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,store:r,changeType:n.changeType,firstRecordName:i,firstRecordKind:"belongsTo"});return r.addRelationshipChangeFor(e,i,t,null,a),a},DS.ManyToNoneChange.createChange=function(e,t,r,n){var i=n.key,a=DS.RelationshipChange._createChange({parentRecord:e,childRecord:t,secondRecord:e,store:r,changeType:n.changeType,secondRecordName:n.key,secondRecordKind:"hasMany"});return r.addRelationshipChangeFor(e,i,t,null,a),a},DS.ManyToManyChange.createChange=function(e,t,r,n){var i=n.key,a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,secondRecord:t,firstRecordKind:"hasMany",secondRecordKind:"hasMany",store:r,changeType:n.changeType,firstRecordName:i});return r.addRelationshipChangeFor(e,i,t,null,a),a},DS.OneToOneChange.createChange=function(e,t,r,n){var i;n.parentType?i=n.parentType.inverseFor(n.key).name:n.key&&(i=n.key);var a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,secondRecord:t,firstRecordKind:"belongsTo",secondRecordKind:"belongsTo",store:r,changeType:n.changeType,firstRecordName:i});return r.addRelationshipChangeFor(e,i,t,null,a),a},DS.OneToOneChange.maintainInvariant=function(e,r,n,i){if("add"===e.changeType&&r.recordIsMaterialized(n)){var a=t(n,i);if(a){var o=DS.OneToOneChange.createChange(n,a,r,{parentType:e.parentType,hasManyName:e.hasManyName,changeType:"remove",key:e.key});r.addRelationshipChangeFor(n,i,e.parentRecord,null,o),o.sync()}}},DS.OneToManyChange.createChange=function(e,t,r,n){var i;n.parentType?(i=n.parentType.inverseFor(n.key).name,DS.OneToManyChange.maintainInvariant(n,r,e,i)):n.key&&(i=n.key);var a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,secondRecord:t,firstRecordKind:"belongsTo",secondRecordKind:"hasMany",store:r,changeType:n.changeType,firstRecordName:i});return r.addRelationshipChangeFor(e,i,t,a.getSecondRecordName(),a),a},DS.OneToManyChange.maintainInvariant=function(e,r,n,i){if("add"===e.changeType&&n){var a=t(n,i);if(a){var o=DS.OneToManyChange.createChange(n,a,r,{parentType:e.parentType,hasManyName:e.hasManyName,changeType:"remove",key:e.key});r.addRelationshipChangeFor(n,i,e.parentRecord,o.getSecondRecordName(),o),o.sync()}}},DS.RelationshipChange.prototype={getSecondRecordName:function(){var e,t=this.secondRecordName;if(!t){if(e=this.secondRecord,!e)return;var r=this.firstRecord.constructor,n=r.inverseFor(this.firstRecordName);this.secondRecordName=n.name}return this.secondRecordName},getFirstRecordName:function(){var e=this.firstRecordName;return e},destroy:function(){var e=this.childRecord,t=this.getFirstRecordName(),r=this.getSecondRecordName(),n=this.store;n.removeRelationshipChangeFor(e,t,this.parentRecord,r,this.changeType)},getSecondRecord:function(){return this.secondRecord},getFirstRecord:function(){return this.firstRecord},coalesce:function(){var e=this.store.relationshipChangePairsFor(this.firstRecord);n(e,function(e){var t=e.add,r=e.remove;t&&r&&(t.destroy(),r.destroy())})}},DS.RelationshipChangeAdd.prototype=Ember.create(DS.RelationshipChange.create({})),DS.RelationshipChangeRemove.prototype=Ember.create(DS.RelationshipChange.create({})),DS.RelationshipChangeAdd.prototype.changeType="add",DS.RelationshipChangeAdd.prototype.sync=function(){var n=this.getSecondRecordName(),i=this.getFirstRecordName(),a=this.getFirstRecord(),o=this.getSecondRecord();o instanceof DS.Model&&a instanceof DS.Model&&("belongsTo"===this.secondRecordKind?o.suspendRelationshipObservers(function(){r(o,n,a)}):"hasMany"===this.secondRecordKind&&o.suspendRelationshipObservers(function(){var r=t(o,n);e(r)&&r.addObject(a)})),a instanceof DS.Model&&o instanceof DS.Model&&t(a,i)!==o&&("belongsTo"===this.firstRecordKind?a.suspendRelationshipObservers(function(){r(a,i,o)}):"hasMany"===this.firstRecordKind&&a.suspendRelationshipObservers(function(){var r=t(a,i);e(r)&&r.addObject(o)})),this.coalesce()},DS.RelationshipChangeRemove.prototype.changeType="remove",DS.RelationshipChangeRemove.prototype.sync=function(){var n=this.getSecondRecordName(),i=this.getFirstRecordName(),a=this.getFirstRecord(),o=this.getSecondRecord();o instanceof DS.Model&&a instanceof DS.Model&&("belongsTo"===this.secondRecordKind?o.suspendRelationshipObservers(function(){r(o,n,null)}):"hasMany"===this.secondRecordKind&&o.suspendRelationshipObservers(function(){var r=t(o,n);e(r)&&r.removeObject(a)})),a instanceof DS.Model&&t(a,i)&&("belongsTo"===this.firstRecordKind?a.suspendRelationshipObservers(function(){r(a,i,null)}):"hasMany"===this.firstRecordKind&&a.suspendRelationshipObservers(function(){var r=t(a,i);e(r)&&r.removeObject(o)})),this.coalesce()}}(),function(){function e(e,n,i){return Ember.computed(function(e,n){var a=t(this,"data"),o=t(this,"store");if(2===arguments.length)return void 0===n?null:DS.PromiseObject.create({promise:Ember.RSVP.resolve(n)});var s=a.links&&a.links[e],c=a[e];if(r(c)){if(s){var u=Ember.RSVP.defer();return o.findBelongsTo(this,s,i,u),DS.PromiseObject.create({promise:u.promise})}return null}var d=o.fetchRecord(c)||Ember.RSVP.resolve(c);return DS.PromiseObject.create({promise:d})}).property("data").meta(i)}var t=Ember.get,r=(Ember.set,Ember.isNone);DS.belongsTo=function(n,i){"object"==typeof n&&(i=n,n=void 0),i=i||{};var a={type:n,isRelationship:!0,options:i,kind:"belongsTo"};return i.async?e(n,i,a):Ember.computed(function(e,i){var a,o,s=t(this,"data"),c=t(this,"store");return o="string"==typeof n?c.modelFor(n):n,2===arguments.length?void 0===i?null:i:(a=s[e],r(a)?null:(c.fetchRecord(a),a))}).property("data").meta(a)},DS.Model.reopen({belongsToWillChange:Ember.beforeObserver(function(e,r){if(t(e,"isLoaded")){var n=t(e,r);if(n){var i=t(e,"store"),a=DS.RelationshipChange.createChange(e,n,i,{key:r,kind:"belongsTo",changeType:"remove"});a.sync(),this._changesToSync[r]=a}}}),belongsToDidChange:Ember.immediateObserver(function(e,r){if(t(e,"isLoaded")){var n=t(e,r);if(n){var i=t(e,"store"),a=DS.RelationshipChange.createChange(e,n,i,{key:r,kind:"belongsTo",changeType:"add"});a.sync()}}delete this._changesToSync[r]})})}(),function(){function e(e,r,n){return Ember.computed(function(e){if(this._relationships[e])return this._relationships[e];var i=Ember.RSVP.defer(),a=t(this,e,r,function(t,r){var a=r.links&&r.links[e];return a?t.findHasMany(this,a,n,i):t.findMany(this,r[e],n.type,i)}),o=i.promise.then(function(){return a});return DS.PromiseArray.create({promise:o})}).property("data").meta(n)}function t(e,t,r,a){var o=e._relationships;if(o[t])return o[t];var s=n(e,"data"),c=n(e,"store"),u=o[t]=a.call(e,c,s);return i(u,{owner:e,name:t,isPolymorphic:r.polymorphic})}function r(r,n){n=n||{};var i={type:r,isRelationship:!0,options:n,kind:"hasMany"};return n.async?e(r,n,i):Ember.computed(function(e){return t(this,e,n,function(t,r){return r[e],t.findMany(this,r[e],i.type)})}).property("data").meta(i)}var n=Ember.get,i=(Ember.set,Ember.setProperties);DS.hasMany=function(e,t){return"object"==typeof e&&(t=e,e=void 0),r(e,t)}}(),function(){var e=Ember.get;Ember.set,DS.Model.reopen({didDefineProperty:function(e,t,r){if(r instanceof Ember.Descriptor){var n=r.meta();n.isRelationship&&"belongsTo"===n.kind&&(Ember.addObserver(e,t,null,"belongsToDidChange"),Ember.addBeforeObserver(e,t,null,"belongsToWillChange")),n.parentType=e.constructor}}}),DS.Model.reopenClass({typeForRelationship:function(t){var r=e(this,"relationshipsByName").get(t);return r&&r.type},inverseFor:function(t){function r(t,n,i){i=i||[];var a=e(n,"relationships");if(a){var o=a.get(t);return o&&i.push.apply(i,a.get(t)),t.superclass&&r(t.superclass,n,i),i}}var n=this.typeForRelationship(t);if(!n)return null;var i=this.metaForProperty(t).options;if(null===i.inverse)return null;var a,o;if(i.inverse)a=i.inverse,o=Ember.get(n,"relationshipsByName").get(a).kind;else{var s=r(this,n);if(0===s.length)return null;a=s[0].name,o=s[0].kind}return{type:n,name:a,kind:o}},relationships:Ember.computed(function(){var e=new Ember.MapWithDefault({defaultValue:function(){return[]}});return this.eachComputedProperty(function(t,r){if(r.isRelationship){"string"==typeof r.type&&(r.type=this.store.modelFor(r.type));var n=e.get(r.type);n.push({name:t,kind:r.kind})}}),e}),relationshipNames:Ember.computed(function(){var e={hasMany:[],belongsTo:[]};return this.eachComputedProperty(function(t,r){r.isRelationship&&e[r.kind].push(t)}),e}),relatedTypes:Ember.computed(function(){var t,r=Ember.A();return this.eachComputedProperty(function(n,i){i.isRelationship&&(t=i.type,"string"==typeof t&&(t=e(this,t,!1)||this.store.modelFor(t)),r.contains(t)||r.push(t))}),r}),relationshipsByName:Ember.computed(function(){var e,t=Ember.Map.create();return this.eachComputedProperty(function(r,n){n.isRelationship&&(n.key=r,e=n.type,e||"hasMany"!==n.kind?e||(e=r):e=Ember.String.singularize(r),"string"==typeof e&&(n.type=this.store.modelFor(e)),t.set(r,n))}),t}),fields:Ember.computed(function(){var e=Ember.Map.create();return this.eachComputedProperty(function(t,r){r.isRelationship?e.set(t,r.kind):r.isAttribute&&e.set(t,"attribute")}),e}),eachRelationship:function(t,r){e(this,"relationshipsByName").forEach(function(e,n){t.call(r,e,n)})},eachRelatedType:function(t,r){e(this,"relatedTypes").forEach(function(e){t.call(r,e)})}}),DS.Model.reopen({eachRelationship:function(e,t){this.constructor.eachRelationship(e,t)}})}(),function(){var e=Ember.get;Ember.set;var t=Ember.run.once,r=Ember.EnumerableUtils.forEach;DS.RecordArrayManager=Ember.Object.extend({init:function(){this.filteredRecordArrays=Ember.MapWithDefault.create({defaultValue:function(){return[]}}),this.changedRecords=[]},recordDidChange:function(e){this.changedRecords.push(e),t(this,this.updateRecordArrays)},recordArraysForRecord:function(e){return e._recordArrays=e._recordArrays||Ember.OrderedSet.create(),e._recordArrays},updateRecordArrays:function(){r(this.changedRecords,function(t){var n,i=t.constructor,a=this.filteredRecordArrays.get(i);r(a,function(r){n=e(r,"filterFunction"),this.updateRecordArray(r,n,i,t)},this);var o=t._loadingRecordArrays;if(o){for(var s=0,c=o.length;c>s;s++)o[s].loadedRecord();t._loadingRecordArrays=[]}},this),this.changedRecords=[]},updateRecordArray:function(e,t,r,n){var i;i=t?t(n):!0;var a=this.recordArraysForRecord(n);i?(a.add(e),e.addRecord(n)):i||(a.remove(e),e.removeRecord(n))},remove:function(e){var t=e._recordArrays;t&&r(t,function(t){t.removeRecord(e)})},updateFilter:function(t,r,n){for(var i,a=this.store.typeMapFor(r),o=a.records,s=0,c=o.length;c>s;s++)i=o[s],e(i,"isDeleted")||e(i,"isEmpty")||this.updateRecordArray(t,n,r,i)},createManyArray:function(e,t){var n=DS.ManyArray.create({type:e,content:t,store:this.store});return r(t,function(e){var t=this.recordArraysForRecord(e);t.add(n)},this),n},registerFilteredRecordArray:function(e,t,r){var n=this.filteredRecordArrays.get(t);n.push(e),this.updateFilter(e,t,r)},registerWaitingRecordArray:function(e,t){var r=e._loadingRecordArrays||[];r.push(t),e._loadingRecordArrays=r}})}(),function(){var e=Ember.get;Ember.set;var t=Ember.ArrayPolyfills.map,r=["description","fileName","lineNumber","message","name","number","stack"];DS.InvalidError=function(e){var t=Error.prototype.constructor.call(this,"The backend rejected the commit because it was invalid: "+Ember.inspect(e));this.errors=e;for(var n=0,i=r.length;i>n;n++)this[r[n]]=t[r[n]]},DS.InvalidError.prototype=Ember.create(Error.prototype),DS.Adapter=Ember.Object.extend(DS._Mappable,{find:Ember.required(Function),findAll:null,findQuery:null,generateIdForRecord:null,serialize:function(t,r){return e(t,"store").serializerFor(t.constructor.typeKey).serialize(t,r)},createRecord:Ember.required(Function),updateRecord:Ember.required(Function),deleteRecord:Ember.required(Function),findMany:function(e,r,n){var i=t.call(n,function(t){return this.find(e,r,t)},this);return Ember.RSVP.all(i)}})}(),function(){var e=Ember.get,t=Ember.String.fmt,r=Ember.EnumerableUtils.indexOf,n=0;DS.FixtureAdapter=DS.Adapter.extend({serializer:null,simulateRemoteResponse:!0,latency:50,fixturesForType:function(e){if(e.FIXTURES){var r=Ember.A(e.FIXTURES);return r.map(function(e){var r=typeof e.id;if("number"!==r&&"string"!==r)throw new Error(t("the id property must be defined as a number or string for fixture %@",[e]));return e.id=e.id+"",e})}return null},queryFixtures:function(){},updateFixtures:function(e,t){e.FIXTURES||(e.FIXTURES=[]);var r=e.FIXTURES;this.deleteLoadedFixture(e,t),r.push(t)},mockJSON:function(e,t,r){return e.serializerFor(t).serialize(r,{includeId:!0})},generateIdForRecord:function(){return"fixture-"+n++},find:function(e,t,r){var n,i=this.fixturesForType(t);return i&&(n=Ember.A(i).findProperty("id",r)),n?this.simulateRemoteCall(function(){return n},this):void 0},findMany:function(e,t,n){var i=this.fixturesForType(t);return i&&(i=i.filter(function(e){return-1!==r(n,e.id)})),i?this.simulateRemoteCall(function(){return i},this):void 0},findAll:function(e,t){var r=this.fixturesForType(t);return this.simulateRemoteCall(function(){return r},this)},findQuery:function(e,t,r){var n=this.fixturesForType(t);return n=this.queryFixtures(n,r,t),n?this.simulateRemoteCall(function(){return n},this):void 0},createRecord:function(e,t,r){var n=this.mockJSON(e,t,r);return this.updateFixtures(t,n),this.simulateRemoteCall(function(){return n},this)},updateRecord:function(e,t,r){var n=this.mockJSON(e,t,r);return this.updateFixtures(t,n),this.simulateRemoteCall(function(){return n},this)},deleteRecord:function(e,t,r){var n=this.mockJSON(e,t,r);return this.deleteLoadedFixture(t,n),this.simulateRemoteCall(function(){return null})},deleteLoadedFixture:function(e,t){var n=this.findExistingFixture(e,t);if(n){var i=r(e.FIXTURES,n);return e.FIXTURES.splice(i,1),!0}},findExistingFixture:function(t,r){var n=this.fixturesForType(t),i=e(r,"id");return this.findFixtureById(n,i)},findFixtureById:function(t,r){return Ember.A(t).find(function(t){return""+e(t,"id")==""+r?!0:!1})},simulateRemoteCall:function(t,r){var n=this;return new Ember.RSVP.Promise(function(i){e(n,"simulateRemoteResponse")?Ember.run.later(function(){i(t.call(r))},e(n,"latency")):Ember.run.once(function(){i(t.call(r))})})}})}(),function(){function e(e){return null==e?null:e+""}var t=Ember.get;Ember.set;var r=Ember.ArrayPolyfills.forEach,n=Ember.ArrayPolyfills.map;DS.RESTSerializer=DS.JSONSerializer.extend({normalize:function(e,t,r){return this.normalizeId(t),this.normalizeUsingDeclaredMapping(e,t),this.normalizeAttributes(e,t),this.normalizeRelationships(e,t),this.normalizeHash&&this.normalizeHash[r]?this.normalizeHash[r](t):this._super(e,t,r)},normalizePayload:function(e,t){return t},normalizeId:function(e){var r=t(this,"primaryKey");"id"!==r&&(e.id=e[r],delete e[r])},normalizeUsingDeclaredMapping:function(e,r){var n,i,a=t(this,"attrs");if(a)for(i in a)n=a[i],r[i]=r[n],delete r[n]},normalizeAttributes:function(e,t){var r;this.keyForAttribute&&e.eachAttribute(function(e){r=this.keyForAttribute(e),e!==r&&(t[e]=t[r],delete t[r])},this)},normalizeRelationships:function(e,t){var r;this.keyForRelationship&&e.eachRelationship(function(e,n){r=this.keyForRelationship(e,n.kind),e!==r&&(t[e]=t[r],delete t[r])},this)},extractSingle:function(t,n,i,a){i=this.normalizePayload(n,i);var o,s=n.typeKey;for(var c in i){var u=this.typeForRoot(c),d=u===s;d&&"array"!==Ember.typeOf(i[c])?o=this.normalize(n,i[c],c):(t.modelFor(u),r.call(i[c],function(r){var n=this.typeForRoot(c),i=t.modelFor(n),s=t.serializerFor(i);r=s.normalize(i,r,c);var u=d&&!a&&!o,l=d&&e(r.id)===a;u||l?o=r:t.push(n,r)},this))}return o},extractArray:function(e,t,r){r=this.normalizePayload(t,r);var i,a=t.typeKey;for(var o in r){var s=o,c=!1;"_"===o.charAt(0)&&(c=!0,s=o.substr(1));var u=this.typeForRoot(s),d=e.modelFor(u),l=e.serializerFor(d),h=!c&&u===a,f=n.call(r[o],function(e){return l.normalize(d,e,o)},this);h?i=f:e.pushMany(u,f)}return i},pushPayload:function(e,t){t=this.normalizePayload(null,t);for(var r in t){var i=this.typeForRoot(r),a=e.modelFor(i),o=n.call(t[r],function(e){return this.normalize(a,e,r)},this);e.pushMany(i,o)}},typeForRoot:function(e){return Ember.String.singularize(e)},serialize:function(){return this._super.apply(this,arguments)},serializeIntoHash:function(e,t,r,n){e[t.typeKey]=this.serialize(r,n)},serializePolymorphicType:function(e,r,n){var i=n.key,a=t(e,i);i=this.keyForAttribute?this.keyForAttribute(i):i,r[i+"Type"]=a.constructor.typeKey}})}(),function(){var e=Ember.get;Ember.set;var t=Ember.ArrayPolyfills.forEach;DS.RESTAdapter=DS.Adapter.extend({defaultSerializer:"_rest",find:function(e,t,r){return this.ajax(this.buildURL(t.typeKey,r),"GET")},findAll:function(e,t,r){var n;return r&&(n={since:r}),this.ajax(this.buildURL(t.typeKey),"GET",{data:n})},findQuery:function(e,t,r){return this.ajax(this.buildURL(t.typeKey),"GET",{data:r})},findMany:function(e,t,r){return this.ajax(this.buildURL(t.typeKey),"GET",{data:{ids:r}})},findHasMany:function(t,r,n){var i=e(this,"host"),a=e(r,"id"),o=r.constructor.typeKey;return i&&"/"===n.charAt(0)&&"/"!==n.charAt(1)&&(n=i+n),this.ajax(this.urlPrefix(n,this.buildURL(o,a)),"GET")},findBelongsTo:function(t,r,n){var i=e(r,"id"),a=r.constructor.typeKey;return this.ajax(this.urlPrefix(n,this.buildURL(a,i)),"GET")},createRecord:function(e,t,r){var n={},i=e.serializerFor(t.typeKey);return i.serializeIntoHash(n,t,r,{includeId:!0}),this.ajax(this.buildURL(t.typeKey),"POST",{data:n})},updateRecord:function(t,r,n){var i={},a=t.serializerFor(r.typeKey);a.serializeIntoHash(i,r,n);var o=e(n,"id");return this.ajax(this.buildURL(r.typeKey,o),"PUT",{data:i})},deleteRecord:function(t,r,n){var i=e(n,"id");return this.ajax(this.buildURL(r.typeKey,i),"DELETE")},buildURL:function(t,r){var n=[],i=e(this,"host"),a=this.urlPrefix();return t&&n.push(this.pathForType(t)),r&&n.push(r),a&&n.unshift(a),n=n.join("/"),!i&&n&&(n="/"+n),n},urlPrefix:function(t,r){var n=e(this,"host"),i=e(this,"namespace"),a=[];return t?"/"===t.charAt(0)?n&&(t=t.slice(1),a.push(n)):/^http(s)?:\/\//.test(t)||a.push(r):(n&&a.push(n),i&&a.push(i)),t&&a.push(t),a.join("/")},pathForType:function(e){return Ember.String.pluralize(e)},ajaxError:function(e){return e&&(e.then=null),e},ajax:function(e,t,r){var n=this;return new Ember.RSVP.Promise(function(i,a){r=n.ajaxOptions(e,t,r),r.success=function(e){Ember.run(null,i,e)},r.error=function(e){Ember.run(null,a,n.ajaxError(e))},Ember.$.ajax(r)})},ajaxOptions:function(e,r,n){if(n=n||{},n.url=e,n.type=r,n.dataType="json",n.context=this,n.data&&"GET"!==r&&(n.contentType="application/json; charset=utf-8",n.data=JSON.stringify(n.data)),void 0!==this.headers){var i=this.headers;n.beforeSend=function(e){t.call(Ember.keys(i),function(t){e.setRequestHeader(t,i[t])})}}return n}})}(),function(){DS.Model.reopen({_debugInfo:function(){var e=["id"],t={belongsTo:[],hasMany:[]},r=[];this.eachAttribute(function(t){e.push(t)},this),this.eachRelationship(function(e,n){t[n.kind].push(e),r.push(e)});var n=[{name:"Attributes",properties:e,expand:!0},{name:"Belongs To",properties:t.belongsTo,expand:!0},{name:"Has Many",properties:t.hasMany,expand:!0},{name:"Flags",properties:["isLoaded","isDirty","isSaving","isDeleted","isError","isNew","isValid"]}];return{propertyInfo:{includeOtherProperties:!0,groups:n,expensiveProperties:r}}}})}(),function(){Ember.String.pluralize=function(e){return Ember.Inflector.inflector.pluralize(e)},Ember.String.singularize=function(e){return Ember.Inflector.inflector.singularize(e)}}(),function(){function e(e,t){for(var r=0,n=t.length;n>r;r++)e.uncountable[t[r]]=!0}function t(e,t){for(var r,n=0,i=t.length;i>n;n++)r=t[n],e.irregular[r[0]]=r[1],e.irregularInverse[r[1]]=r[0]}function r(r){r=r||{},r.uncountable=r.uncountable||{},r.irregularPairs=r.irregularPairs||{};var n=this.rules={plurals:r.plurals||[],singular:r.singular||[],irregular:{},irregularInverse:{},uncountable:{}};e(n,r.uncountable),t(n,r.irregularPairs)}var n=/^\s*$/;r.prototype={plural:function(e,t){this.rules.plurals.push([e,t])},singular:function(e,t){this.rules.singular.push([e,t])},uncountable:function(t){e(this.rules,[t])},irregular:function(e,r){t(this.rules,[[e,r]])},pluralize:function(e){return this.inflect(e,this.rules.plurals,this.rules.irregular)},singularize:function(e){return this.inflect(e,this.rules.singular,this.rules.irregularInverse)},inflect:function(e,t,r){var i,a,o,s,c,u,d,l;if(c=n.test(e))return e;if(s=e.toLowerCase(),u=this.rules.uncountable[s])return e;if(d=r&&r[s])return d;for(var h=t.length,f=0;h>f&&(i=t[h-1],l=i[0],!l.test(e));h--);return i=i||[],l=i[0],a=i[1],o=e.replace(l,a)}},Ember.Inflector=r}(),function(){Ember.Inflector.defaultRules={plurals:[[/$/,"s"],[/s$/i,"s"],[/^(ax|test)is$/i,"$1es"],[/(octop|vir)us$/i,"$1i"],[/(octop|vir)i$/i,"$1i"],[/(alias|status)$/i,"$1es"],[/(bu)s$/i,"$1ses"],[/(buffal|tomat)o$/i,"$1oes"],[/([ti])um$/i,"$1a"],[/([ti])a$/i,"$1a"],[/sis$/i,"ses"],[/(?:([^f])fe|([lr])f)$/i,"$1$2ves"],[/(hive)$/i,"$1s"],[/([^aeiouy]|qu)y$/i,"$1ies"],[/(x|ch|ss|sh)$/i,"$1es"],[/(matr|vert|ind)(?:ix|ex)$/i,"$1ices"],[/^(m|l)ouse$/i,"$1ice"],[/^(m|l)ice$/i,"$1ice"],[/^(ox)$/i,"$1en"],[/^(oxen)$/i,"$1"],[/(quiz)$/i,"$1zes"]],singular:[[/s$/i,""],[/(ss)$/i,"$1"],[/(n)ews$/i,"$1ews"],[/([ti])a$/i,"$1um"],[/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i,"$1sis"],[/(^analy)(sis|ses)$/i,"$1sis"],[/([^f])ves$/i,"$1fe"],[/(hive)s$/i,"$1"],[/(tive)s$/i,"$1"],[/([lr])ves$/i,"$1f"],[/([^aeiouy]|qu)ies$/i,"$1y"],[/(s)eries$/i,"$1eries"],[/(m)ovies$/i,"$1ovie"],[/(x|ch|ss|sh)es$/i,"$1"],[/^(m|l)ice$/i,"$1ouse"],[/(bus)(es)?$/i,"$1"],[/(o)es$/i,"$1"],[/(shoe)s$/i,"$1"],[/(cris|test)(is|es)$/i,"$1is"],[/^(a)x[ie]s$/i,"$1xis"],[/(octop|vir)(us|i)$/i,"$1us"],[/(alias|status)(es)?$/i,"$1"],[/^(ox)en/i,"$1"],[/(vert|ind)ices$/i,"$1ex"],[/(matr)ices$/i,"$1ix"],[/(quiz)zes$/i,"$1"],[/(database)s$/i,"$1"]],irregularPairs:[["person","people"],["man","men"],["child","children"],["sex","sexes"],["move","moves"],["cow","kine"],["zombie","zombies"]],uncountable:["equipment","information","rice","money","species","series","fish","sheep","jeans","police"]}}(),function(){(Ember.EXTEND_PROTOTYPES===!0||Ember.EXTEND_PROTOTYPES.String)&&(String.prototype.pluralize=function(){return Ember.String.pluralize(this)},String.prototype.singularize=function(){return Ember.String.singularize(this)})}(),function(){Ember.Inflector.inflector=new Ember.Inflector(Ember.Inflector.defaultRules)}(),function(){function e(n,i,a,o,s){var c=t(i,"attrs");c&&a.eachRelationship(function(i,a){var u,d,l,h,f=c[i],p=n.serializerFor(a.type.typeKey),m=t(p,"primaryKey");if("hasMany"===a.kind&&f&&("always"===f.embedded||"load"===f.embedded)){if(d="_"+Ember.String.pluralize(a.type.typeKey),u=this.keyForRelationship(i,a.kind),l=this.keyForAttribute(i),h=[],!o[l])return;s[d]=s[d]||[],r(o[l],function(t){var r=n.modelFor(a.type.typeKey);e(n,p,r,t,s),h.push(t[m]),s[d].push(t)}),o[u]=h,delete o[l]}},i)}var t=Ember.get,r=Ember.EnumerableUtils.forEach;DS.ActiveModelSerializer=DS.RESTSerializer.extend({keyForAttribute:function(e){return Ember.String.decamelize(e)},keyForRelationship:function(e,t){return e=Ember.String.decamelize(e),"belongsTo"===t?e+"_id":"hasMany"===t?Ember.String.singularize(e)+"_ids":e},serializeHasMany:function(e,r,n){var i=n.key,a=t(this,"attrs"),o=a&&a[i]&&"always"===a[i].embedded;o&&(r[this.keyForAttribute(i)]=t(e,i).map(function(e){var r=e.serialize(),n=t(this,"primaryKey");return r[n]=t(e,n),r},this))},serializeIntoHash:function(e,t,r,n){var i=Ember.String.decamelize(t.typeKey);e[i]=this.serialize(r,n)},serializePolymorphicType:function(e,r,n){var i=n.key,a=t(e,i);i=this.keyForAttribute(i),r[i+"_type"]=Ember.String.capitalize(a.constructor.typeKey)},typeForRoot:function(e){var t=Ember.String.camelize(e);return Ember.String.singularize(t)},normalizeRelationships:function(e,t){var n,i;this.keyForRelationship&&e.eachRelationship(function(e,a){if(a.options.polymorphic){if(n=this.keyForAttribute(e),i=t[n],i&&i.type)i.type=this.typeForRoot(i.type);else if(i&&"hasMany"===a.kind){var o=this;r(i,function(e){e.type=o.typeForRoot(e.type)})}}else n=this.keyForRelationship(e,a.kind),i=t[n];t[e]=i,e!==n&&delete t[n]},this)},extractSingle:function(t,r,n,i,a){var o=this.keyForAttribute(r.typeKey),s=n[o];return e(t,this,r,s,n),this._super(t,r,n,i,a)},extractArray:function(t,n,i){var a=this.keyForAttribute(n.typeKey),o=i[Ember.String.pluralize(a)];return r(o,function(r){e(t,this,n,r,i)},this),this._super(t,n,i)}})}(),function(){var e=Ember.EnumerableUtils.forEach;DS.ActiveModelAdapter=DS.RESTAdapter.extend({defaultSerializer:"_ams",pathForType:function(e){var t=Ember.String.decamelize(e);return Ember.String.pluralize(t)},ajaxError:function(t){var r=this._super(t);if(t&&422===t.status){var n=Ember.$.parseJSON(t.responseText).errors,i={};return e(Ember.keys(n),function(e){i[Ember.String.camelize(e)]=n[e]}),new DS.InvalidError(i)}return r}})}(),function(){Ember.onLoad("Ember.Application",function(e){e.initializer({name:"activeModelAdapter",initialize:function(e,t){t.register("serializer:_ams",DS.ActiveModelSerializer),t.register("adapter:_ams",DS.ActiveModelAdapter)}})})}()}(),"undefined"==typeof location||"localhost"!==location.hostname&&"127.0.0.1"!==location.hostname||Ember.Logger.warn("You are running a production build of Ember on localhost and won't receive detailed error messages. If you want full error messages please use the non-minified build provided on the Ember website.");
|
|
11
|
+
/*!
|
|
12
|
+
* @overview Ember Data
|
|
13
|
+
* @copyright Copyright 2011-2013 Tilde Inc. and contributors.
|
|
14
|
+
* Portions Copyright 2011 LivingSocial Inc.
|
|
15
|
+
* @license Licensed under MIT license (see license.js)
|
|
16
|
+
*/
|
|
17
|
+
!function(){var e,t;!function(){var r={},i={};e=function(e,t,i){r[e]={deps:t,callback:i}},t=function(e){if(i[e])return i[e];i[e]={};var n,a,o,s,c;if(n=r[e],!n)throw new Error("Module '"+e+"' not found.");a=n.deps,o=n.callback,s=[];for(var d=0,u=a.length;u>d;d++)"exports"===a[d]?s.push(c={}):s.push(t(a[d]));var l=o.apply(this,s);return i[e]=c||l}}(),function(){var e;"undefined"==typeof e&&(e=Ember.Namespace.create({VERSION:"1.0.0-beta.4"}),"undefined"!=typeof window&&(window.DS=e),Ember.libraries&&Ember.libraries.registerCoreLibrary("Ember Data",e.VERSION))}(),function(){function e(e){return function(){return this[e].apply(this,arguments)}}var t=Ember.get,r=(Ember.set,Ember.isNone);DS.JSONSerializer=Ember.Object.extend({primaryKey:"id",applyTransforms:function(e,t){return e.eachTransformedAttribute(function(e,r){var i=this.transformFor(r);t[e]=i.deserialize(t[e])},this),t},normalize:function(e,t){return t?(this.applyTransforms(e,t),t):t},serialize:function(e,r){var i={};if(r&&r.includeId){var n=t(e,"id");n&&(i[t(this,"primaryKey")]=t(e,"id"))}return e.eachAttribute(function(t,r){this.serializeAttribute(e,i,t,r)},this),e.eachRelationship(function(t,r){"belongsTo"===r.kind?this.serializeBelongsTo(e,i,r):"hasMany"===r.kind&&this.serializeHasMany(e,i,r)},this),i},serializeAttribute:function(e,r,i,n){var a=t(this,"attrs"),o=t(e,i),s=n.type;if(s){var c=this.transformFor(s);o=c.serialize(o)}i=a&&a[i]||(this.keyForAttribute?this.keyForAttribute(i):i),r[i]=o},serializeBelongsTo:function(e,i,n){var a=n.key,o=t(e,a);a=this.keyForRelationship?this.keyForRelationship(a,"belongsTo"):a,i[a]=r(o)?o:t(o,"id"),n.options.polymorphic&&this.serializePolymorphicType(e,i,n)},serializeHasMany:function(e,r,i){var n=i.key,a=DS.RelationshipChange.determineRelationshipType(e.constructor,i);("manyToNone"===a||"manyToMany"===a)&&(r[n]=t(e,n).mapBy("id"))},serializePolymorphicType:Ember.K,extract:function(e,t,r,i,n){this.extractMeta(e,t,r);var a="extract"+n.charAt(0).toUpperCase()+n.substr(1);return this[a](e,t,r,i,n)},extractFindAll:e("extractArray"),extractFindQuery:e("extractArray"),extractFindMany:e("extractArray"),extractFindHasMany:e("extractArray"),extractCreateRecord:e("extractSave"),extractUpdateRecord:e("extractSave"),extractDeleteRecord:e("extractSave"),extractFind:e("extractSingle"),extractFindBelongsTo:e("extractSingle"),extractSave:e("extractSingle"),extractSingle:function(e,t,r){return this.normalize(t,r)},extractArray:function(e,t,r){return this.normalize(t,r)},extractMeta:function(e,t,r){r&&r.meta&&(e.metaForType(t,r.meta),delete r.meta)},transformFor:function(e){var t=this.container.lookup("transform:"+e);return t}})}(),function(){var e=Ember.get,t=Ember.String.capitalize,r=Ember.String.underscore,i=window.DS;i.DebugAdapter=Ember.DataAdapter.extend({getFilters:function(){return[{name:"isNew",desc:"New"},{name:"isModified",desc:"Modified"},{name:"isClean",desc:"Clean"}]},detect:function(e){return e!==i.Model&&i.Model.detect(e)},columnsForType:function(i){var n=[{name:"id",desc:"Id"}],a=0,o=this;return e(i,"attributes").forEach(function(e){if(a++>o.attributeLimit)return!1;var i=t(r(e).replace("_"," "));n.push({name:e,desc:i})}),n},getRecords:function(e){return this.get("store").all(e)},getRecordColumnValues:function(t){var r=this,i=0,n={id:e(t,"id")};return t.eachAttribute(function(a){if(i++>r.attributeLimit)return!1;var o=e(t,a);n[a]=o}),n},getRecordKeywords:function(t){var r=[],i=Ember.A(["id"]);return t.eachAttribute(function(e){i.push(e)}),i.forEach(function(i){r.push(e(t,i))}),r},getRecordFilterValues:function(e){return{isNew:e.get("isNew"),isModified:e.get("isDirty")&&!e.get("isNew"),isClean:!e.get("isDirty")}},getRecordColor:function(e){var t="black";return e.get("isNew")?t="green":e.get("isDirty")&&(t="blue"),t},observeRecord:function(e,t){var r=Ember.A(),i=this,n=Ember.A(["id","isNew","isDirty"]);e.eachAttribute(function(e){n.push(e)}),n.forEach(function(n){var a=function(){t(i.wrapRecord(e))};Ember.addObserver(e,n,a),r.push(function(){Ember.removeObserver(e,n,a)})});var a=function(){r.forEach(function(e){e()})};return a}})}(),function(){DS.Transform=Ember.Object.extend({serialize:Ember.required(),deserialize:Ember.required()})}(),function(){DS.BooleanTransform=DS.Transform.extend({deserialize:function(e){var t=typeof e;return"boolean"===t?e:"string"===t?null!==e.match(/^true$|^t$|^1$/i):"number"===t?1===e:!1},serialize:function(e){return Boolean(e)}})}(),function(){DS.DateTransform=DS.Transform.extend({deserialize:function(e){var t=typeof e;return"string"===t?new Date(Ember.Date.parse(e)):"number"===t?new Date(e):null===e||void 0===e?e:null},serialize:function(e){if(e instanceof Date){var t=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],r=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],i=function(e){return 10>e?"0"+e:""+e},n=e.getUTCFullYear(),a=e.getUTCMonth(),o=e.getUTCDate(),s=e.getUTCDay(),c=e.getUTCHours(),d=e.getUTCMinutes(),u=e.getUTCSeconds(),l=t[s],h=i(o),f=r[a];return l+", "+h+" "+f+" "+n+" "+i(c)+":"+i(d)+":"+i(u)+" GMT"}return null}})}(),function(){var e=Ember.isEmpty;DS.NumberTransform=DS.Transform.extend({deserialize:function(t){return e(t)?null:Number(t)},serialize:function(t){return e(t)?null:Number(t)}})}(),function(){var e=Ember.isNone;DS.StringTransform=DS.Transform.extend({deserialize:function(t){return e(t)?null:String(t)},serialize:function(t){return e(t)?null:String(t)}})}(),function(){Ember.set;Ember.onLoad("Ember.Application",function(e){e.initializer({name:"store",initialize:function(e,t){t.register("store:main",t.Store||DS.Store),t.register("serializer:_default",DS.JSONSerializer),t.register("serializer:_rest",DS.RESTSerializer),t.register("adapter:_rest",DS.RESTAdapter),e.lookup("store:main")}}),e.initializer({name:"transforms",before:"store",initialize:function(e,t){t.register("transform:boolean",DS.BooleanTransform),t.register("transform:date",DS.DateTransform),t.register("transform:number",DS.NumberTransform),t.register("transform:string",DS.StringTransform)}}),e.initializer({name:"dataAdapter",before:"store",initialize:function(e,t){t.register("dataAdapter:main",DS.DebugAdapter)}}),e.initializer({name:"injectStore",before:"store",initialize:function(e,t){t.inject("controller","store","store:main"),t.inject("route","store","store:main"),t.inject("serializer","store","store:main"),t.inject("dataAdapter","store","store:main")}})})}(),function(){Ember.Date=Ember.Date||{};var e=Date.parse,t=[1,4,5,6,7,10,11];Ember.Date.parse=function(r){var i,n,a=0;if(n=/^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(r)){for(var o,s=0;o=t[s];++s)n[o]=+n[o]||0;n[2]=(+n[2]||1)-1,n[3]=+n[3]||1,"Z"!==n[8]&&void 0!==n[9]&&(a=60*n[10]+n[11],"+"===n[9]&&(a=0-a)),i=Date.UTC(n[1],n[2],n[3],n[4],n[5]+a,n[6],n[7])}else i=e?e(r):0/0;return i},(Ember.EXTEND_PROTOTYPES===!0||Ember.EXTEND_PROTOTYPES.Date)&&(Date.parse=Ember.Date.parse)}(),function(){{var e=Ember.get;Ember.set}DS.RecordArray=Ember.ArrayProxy.extend(Ember.Evented,{type:null,content:null,isLoaded:!1,isUpdating:!1,store:null,objectAtContent:function(t){var r=e(this,"content");return r.objectAt(t)},update:function(){if(!e(this,"isUpdating")){var t=e(this,"store"),r=e(this,"type");t.fetchAll(r,this)}},addRecord:function(t){e(this,"content").addObject(t)},removeRecord:function(t){e(this,"content").removeObject(t)},save:function(){var t="DS: RecordArray#save "+e(this,"type"),r=Ember.RSVP.all(this.invoke("save"),t).then(function(e){return Ember.A(e)},null,"DS: RecordArray#save apply Ember.NativeArray");return DS.PromiseArray.create({promise:r})}})}(),function(){var e=Ember.get;DS.FilteredRecordArray=DS.RecordArray.extend({filterFunction:null,isLoaded:!0,replace:function(){var t=e(this,"type").toString();throw new Error("The result of a client-side filter (on "+t+") is immutable.")},updateFilter:Ember.observer(function(){var t=e(this,"manager");t.updateFilter(this,e(this,"type"),e(this,"filterFunction"))},"filterFunction")})}(),function(){{var e=Ember.get;Ember.set}DS.AdapterPopulatedRecordArray=DS.RecordArray.extend({query:null,replace:function(){var t=e(this,"type").toString();throw new Error("The result of a server query (on "+t+") is immutable.")},load:function(t){var r=e(this,"store"),i=e(this,"type"),n=r.pushMany(i,t),a=r.metadataFor(i);this.setProperties({content:Ember.A(n),isLoaded:!0,meta:a}),Ember.run.once(this,"trigger","didLoad")}})}(),function(){var e=Ember.get,t=Ember.set,r=Ember.EnumerableUtils.map;DS.ManyArray=DS.RecordArray.extend({init:function(){this._super.apply(this,arguments),this._changesToSync=Ember.OrderedSet.create()},name:null,owner:null,isPolymorphic:!1,isLoaded:!1,promise:null,loadingRecordsCount:function(e){this.loadingRecordsCount=e},loadedRecord:function(){this.loadingRecordsCount--,0===this.loadingRecordsCount&&(t(this,"isLoaded",!0),this.trigger("didLoad"))},fetch:function(){var t=e(this,"content"),r=e(this,"store"),i=e(this,"owner"),n=Ember.RSVP.defer("DS: ManyArray#fetch "+e(this,"type")),a=t.filterProperty("isEmpty",!0);r.fetchMany(a,i,n)},replaceContent:function(e,t,i){i=r(i,function(e){return e},this),this._super(e,t,i)},arrangedContentDidChange:function(){Ember.run.once(this,"fetch")},arrayContentWillChange:function(t,r){var i=e(this,"owner"),n=e(this,"name");if(!i._suspendedRelationships)for(var a=t;t+r>a;a++){var o=e(this,"content").objectAt(a),s=DS.RelationshipChange.createChange(i,o,e(this,"store"),{parentType:i.constructor,changeType:"remove",kind:"hasMany",key:n});this._changesToSync.add(s)}return this._super.apply(this,arguments)},arrayContentDidChange:function(t,r,i){this._super.apply(this,arguments);var n=e(this,"owner"),a=e(this,"name"),o=e(this,"store");if(!n._suspendedRelationships){for(var s=t;t+i>s;s++){var c=e(this,"content").objectAt(s),d=DS.RelationshipChange.createChange(n,c,o,{parentType:n.constructor,changeType:"add",kind:"hasMany",key:a});d.hasManyName=a,this._changesToSync.add(d)}this._changesToSync.forEach(function(e){e.sync()}),this._changesToSync.clear()}},createRecord:function(t){var r,i=e(this,"owner"),n=e(i,"store"),a=e(this,"type");return r=n.createRecord.call(n,a,t),this.pushObject(r),r}})}(),function(){function e(e,r,a,o){return r.eachRelationship(function(r,s){if(a.links&&a.links[r])return o&&s.options.async&&(o._relationships[r]=null),void 0;var c=s.kind,d=a[r];null!=d&&("belongsTo"===c?t(e,a,r,s,d):"hasMany"===c&&(i(e,a,r,s,d),n(o,r,d)))}),a}function t(e,t,i,n,a){if(!(R(a)||a instanceof DS.Model)){var o;"number"==typeof a||"string"==typeof a?(o=r(n,i,t),t[i]=e.recordForId(o,a)):"object"==typeof a&&(t[i]=e.recordForId(a.type,a.id))}}function r(e,t,r){return e.options.polymorphic?r[t+"Type"]:e.type}function i(e,r,i,n,a){for(var o=0,s=a.length;s>o;o++)t(e,a,o,n,a[o])}function n(e,t,r){e&&r.pushObjects(e.get(t).filterBy("isNew"))}function a(e){return DS.PromiseObject.create({promise:e})}function o(e){return DS.PromiseArray.create({promise:e})}function s(e,t,r){return e.lookup("serializer:"+t)||e.lookup("serializer:application")||e.lookup("serializer:"+r)||e.lookup("serializer:_default")}function c(e){return e.lookup("serializer:application")||e.lookup("serializer:_default")}function d(e,t){var r=e.serializer,i=e.defaultSerializer,n=e.container;return n&&void 0===r&&(r=s(n,t.typeKey,i)),(null===r||void 0===r)&&(r={extract:function(e,t,r){return r}}),r}function u(e,t,r,i){var n=e.find(t,r,i),a=d(e,r);return T(n,"DS: Handle Adapter#find of "+r+" with id: "+i).then(function(e){return e=a.extract(t,r,e,i,"find"),t.push(r,e)},function(e){var n=t.getById(r,i);throw n.notFound(),e},"DS: Extract payload of '"+r+"'")}function l(e,t,r,i,n){var a=e.findMany(t,r,i,n),o=d(e,r);return T(a,"DS: Handle Adapter#findMany of "+r).then(function(e){e=o.extract(t,r,e,null,"findMany"),t.pushMany(r,e)},null,"DS: Extract payload of "+r)}function h(e,t,r,i,n){var a=e.findHasMany(t,r,i,n),o=d(e,n.type);return T(a,"DS: Handle Adapter#findHasMany of "+r+" : "+n.type).then(function(e){e=o.extract(t,n.type,e,null,"findHasMany");var i=t.pushMany(n.type,e);r.updateHasMany(n.key,i)},null,"DS: Extract payload of "+r+" : hasMany "+n.type)}function f(e,t,r,i,n){var a=e.findBelongsTo(t,r,i,n),o=d(e,n.type);return T(a,"DS: Handle Adapter#findBelongsTo of "+r+" : "+n.type).then(function(e){e=o.extract(t,n.type,e,null,"findBelongsTo");var r=t.push(n.type,e);return r.updateBelongsTo(n.key,r),r},null,"DS: Extract payload of "+r+" : "+n.type)}function p(e,t,r,i){var n=e.findAll(t,r,i),a=d(e,r);return T(n,"DS: Handle Adapter#findAll of "+r).then(function(e){return e=a.extract(t,r,e,null,"findAll"),t.pushMany(r,e),t.didUpdateAll(r),t.all(r)},null,"DS: Extract payload of findAll "+r)}function m(e,t,r,i,n){var a=e.findQuery(t,r,i,n),o=d(e,r);return T(a,"DS: Handle Adapter#findQuery of "+r).then(function(e){return e=o.extract(t,r,e,null,"findAll"),n.load(e),n},null,"DS: Extract payload of findQuery "+r)}function y(e,t,r,i){var n=i.constructor,a=e[r](t,n,i),o=d(e,n);return a.then(function(e){return e&&(e=o.extract(t,n,e,g(i,"id"),r)),t.didSaveRecord(i,e),i},function(e){throw e instanceof DS.InvalidError?t.recordWasInvalid(i,e.errors):t.recordWasError(i,e),e},"DS: Extract and notify about "+r+" completion of "+i)}var g=Ember.get,b=Ember.set,v=Ember.run.once,R=Ember.isNone,E=Ember.EnumerableUtils.forEach,S=Ember.EnumerableUtils.indexOf,D=Ember.EnumerableUtils.map,T=Ember.RSVP.resolve,A=Ember.copy,F=function(e){return null==e?null:e+""};DS.Store=Ember.Object.extend({init:function(){this.typeMaps={},this.recordArrayManager=DS.RecordArrayManager.create({store:this}),this._relationshipChanges={},this._pendingSave=[]},adapter:"_rest",serialize:function(e,t){return this.serializerFor(e.constructor.typeKey).serialize(e,t)},defaultAdapter:Ember.computed("adapter",function(){var e=g(this,"adapter");return"string"==typeof e&&(e=this.container.lookup("adapter:"+e)||this.container.lookup("adapter:application")||this.container.lookup("adapter:_rest")),DS.Adapter.detect(e)&&(e=e.create({container:this.container})),e}),createRecord:function(e,t){e=this.modelFor(e),t=A(t)||{},R(t.id)&&(t.id=this._generateId(e)),t.id=F(t.id);var r=this.buildRecord(e,t.id);return r.loadedData(),r.setProperties(t),r},_generateId:function(e){var t=this.adapterFor(e);return t&&t.generateIdForRecord?t.generateIdForRecord(this):null},deleteRecord:function(e){e.deleteRecord()},unloadRecord:function(e){e.unloadRecord()},find:function(e,t){return void 0===t?this.findAll(e):"object"===Ember.typeOf(t)?this.findQuery(e,t):this.findById(e,F(t))},findById:function(e,t){e=this.modelFor(e);var r=this.recordForId(e,t),i=this.fetchRecord(r)||T(r,"DS: Store#findById "+e+" with id: "+t);return a(i)},findByIds:function(e,t){var r=this;return o(Ember.RSVP.all(D(t,function(t){return r.findById(e,t)})).then(Ember.A,null,"DS: Store#findByIds of "+e+" complete"))},fetchRecord:function(e){if(R(e))return null;if(e._loadingPromise)return e._loadingPromise;if(!g(e,"isEmpty"))return null;var t=e.constructor,r=g(e,"id"),i=Ember.RSVP.defer("DS: Store#fetchRecord "+e);e.loadingData(i.promise);var n=this.adapterFor(t);return i.resolve(u(n,this,t,r)),i.promise},getById:function(e,t){return this.hasRecordForId(e,t)?this.recordForId(e,t):null},reloadRecord:function(e){var t=e.constructor,r=this.adapterFor(t),i=g(e,"id");return u(r,this,t,i)},fetchMany:function(e,t,r){if(e.length){var i=Ember.MapWithDefault.create({defaultValue:function(){return Ember.A()}});E(e,function(e){i.get(e.constructor).push(e)}),E(i,function(e,i){var n=i.mapProperty("id"),a=this.adapterFor(e);r.resolve(l(a,this,e,n,t))},this)}},hasRecordForId:function(e,t){return t=F(t),e=this.modelFor(e),!!this.typeMapFor(e).idToRecord[t]},recordForId:function(e,t){e=this.modelFor(e),t=F(t);var r=this.typeMapFor(e).idToRecord[t];return r||(r=this.buildRecord(e,t)),r},findMany:function(e,t,r,i){r=this.modelFor(r),t=Ember.A(t);var n=t.filterProperty("isEmpty",!0),a=this.recordArrayManager.createManyArray(r,t);return E(n,function(e){e.loadingData()}),a.loadingRecordsCount=n.length,n.length?(E(n,function(e){this.recordArrayManager.registerWaitingRecordArray(e,a)},this),this.fetchMany(n,e,i)):(i&&i.resolve(),a.set("isLoaded",!0),Ember.run.once(a,"trigger","didLoad")),a},findHasMany:function(e,t,r,i){var n=this.adapterFor(e.constructor),a=this.recordArrayManager.createManyArray(r.type,Ember.A([]));return i.resolve(h(n,this,e,t,r)),a},findBelongsTo:function(e,t,r,i){var n=this.adapterFor(e.constructor);i.resolve(f(n,this,e,t,r))},findQuery:function(e,t){e=this.modelFor(e);var r=DS.AdapterPopulatedRecordArray.create({type:e,query:t,content:Ember.A(),store:this}),i=this.adapterFor(e),n="DS: Store#findQuery "+e,a=Ember.RSVP.defer(n);return a.resolve(m(i,this,e,t,r)),o(a.promise)},findAll:function(e){return e=this.modelFor(e),this.fetchAll(e,this.all(e))},fetchAll:function(e,t){var r=this.adapterFor(e),i=this.typeMapFor(e).metadata.since,n=Ember.RSVP.defer("DS: Store#findAll "+e);return b(t,"isUpdating",!0),n.resolve(p(r,this,e,i)),o(n.promise)},didUpdateAll:function(e){var t=this.typeMapFor(e).findAllCache;b(t,"isUpdating",!1)},all:function(e){e=this.modelFor(e);var t=this.typeMapFor(e),r=t.findAllCache;if(r)return r;var i=DS.RecordArray.create({type:e,content:Ember.A(),store:this,isLoaded:!0});return this.recordArrayManager.registerFilteredRecordArray(i,e),t.findAllCache=i,i},unloadAll:function(e){e=this.modelFor(e);for(var t,r=this.typeMapFor(e),i=r.records;t=i.pop();)t.unloadRecord();r.findAllCache=null},filter:function(e,t,r){var i;3===arguments.length?i=this.findQuery(e,t):2===arguments.length&&(r=t),e=this.modelFor(e);var n=DS.FilteredRecordArray.create({type:e,content:Ember.A(),store:this,manager:this.recordArrayManager,filterFunction:r});return this.recordArrayManager.registerFilteredRecordArray(n,e,r),i?i.then(function(){return n},null,"DS: Store#filter of "+e):n},recordIsLoaded:function(e,t){return this.hasRecordForId(e,t)?!g(this.recordForId(e,t),"isEmpty"):!1},metadataFor:function(e){return e=this.modelFor(e),this.typeMapFor(e).metadata},dataWasUpdated:function(e,t){this.recordArrayManager.recordDidChange(t)},scheduleSave:function(e,t){e.adapterWillCommit(),this._pendingSave.push([e,t]),v(this,"flushPendingSave")},flushPendingSave:function(){var e=this._pendingSave.slice();this._pendingSave=[],E(e,function(e){var t,r=e[0],i=e[1],n=this.adapterFor(r.constructor);t=g(r,"isNew")?"createRecord":g(r,"isDeleted")?"deleteRecord":"updateRecord",i.resolve(y(n,this,t,r))},this)},didSaveRecord:function(t,r){r&&(r=e(this,t.constructor,r,t),this.updateId(t,r)),t.adapterDidCommit(r)},recordWasInvalid:function(e,t){e.adapterDidInvalidate(t)},recordWasError:function(e){e.adapterDidError()},updateId:function(e,t){var r=(g(e,"id"),F(t.id));this.typeMapFor(e.constructor).idToRecord[r]=e,b(e,"id",r)},typeMapFor:function(e){var t,r=g(this,"typeMaps"),i=Ember.guidFor(e);return(t=r[i])?t:(t={idToRecord:{},records:[],metadata:{}},r[i]=t,t)},_load:function(e,t,r){var i=F(t.id),n=this.recordForId(e,i);return n.setupData(t,r),this.recordArrayManager.recordDidChange(n),n},modelFor:function(e){var t;if("string"==typeof e){if(t=this.container.lookupFactory("model:"+e),!t)throw new Ember.Error("No model was found for '"+e+"'");t.typeKey=e}else t=e;return t.store=this,t},push:function(t,r,i){return t=this.modelFor(t),r=e(this,t,r),this._load(t,r,i),this.recordForId(t,r.id)},pushPayload:function(e,t){var r;t?r=this.serializerFor(e):(t=e,r=c(this.container)),r.pushPayload(this,t)},update:function(e,t){return this.push(e,t,!0)},pushMany:function(e,t){return D(t,function(t){return this.push(e,t)},this)},metaForType:function(e,t){e=this.modelFor(e),Ember.merge(this.typeMapFor(e).metadata,t)},buildRecord:function(e,t,r){var i=this.typeMapFor(e),n=i.idToRecord,a=e._create({id:t,store:this,container:this.container});return r&&a.setupData(r),t&&(n[t]=a),i.records.push(a),a},dematerializeRecord:function(e){var t=e.constructor,r=this.typeMapFor(t),i=g(e,"id");e.updateRecordArrays(),i&&delete r.idToRecord[i];var n=S(r.records,e);r.records.splice(n,1)},addRelationshipChangeFor:function(e,t,r,i,n){var a=e.clientId,o=r?r:r,s=t+i,c=this._relationshipChanges;a in c||(c[a]={}),o in c[a]||(c[a][o]={}),s in c[a][o]||(c[a][o][s]={}),c[a][o][s][n.changeType]=n},removeRelationshipChangeFor:function(e,t,r,i,n){var a=e.clientId,o=r?r.clientId:r,s=this._relationshipChanges,c=t+i;a in s&&o in s[a]&&c in s[a][o]&&delete s[a][o][c][n]},relationshipChangePairsFor:function(e){var t=[];if(!e)return t;var r=this._relationshipChanges[e.clientId];for(var i in r)if(r.hasOwnProperty(i))for(var n in r[i])r[i].hasOwnProperty(n)&&t.push(r[i][n]);return t},adapterFor:function(e){var t,r=this.container;return r&&(t=r.lookup("adapter:"+e.typeKey)||r.lookup("adapter:application")),t||g(this,"defaultAdapter")},serializerFor:function(e){e=this.modelFor(e);var t=this.adapterFor(e);return s(this.container,e.typeKey,t&&t.defaultSerializer)}}),DS.PromiseArray=Ember.ArrayProxy.extend(Ember.PromiseProxyMixin),DS.PromiseObject=Ember.ObjectProxy.extend(Ember.PromiseProxyMixin)}(),function(){function e(t){var r,i={};for(var n in t)r=t[n],i[n]=r&&"object"==typeof r?e(r):r;return i}function t(e,t){for(var r in t)e[r]=t[r];return e}function r(r){var i=e(c);return t(i,r)}function i(e,r,n){e=t(r?Ember.create(r):{},e),e.parentState=r,e.stateName=n;for(var a in e)e.hasOwnProperty(a)&&"parentState"!==a&&"stateName"!==a&&"object"==typeof e[a]&&(e[a]=i(e[a],e,n+"."+a));return e}var n=Ember.get,a=Ember.set,o=function(e){var t,r,i,n=Ember.keys(e);for(t=0,r=n.length;r>t;t++)if(i=n[t],e.hasOwnProperty(i)&&e[i])return!0;return!1},s=function(e,t){t.value===t.originalValue?(delete e._attributes[t.name],e.send("propertyWasReset",t.name)):t.value!==t.oldValue&&e.send("becomeDirty"),e.updateRecordArraysLater()},c={initialState:"uncommitted",isDirty:!0,uncommitted:{didSetProperty:s,propertyWasReset:function(e){var t=!1;for(var r in e._attributes){t=!0;break}t||e.send("rolledBack")},pushedData:Ember.K,becomeDirty:Ember.K,willCommit:function(e){e.transitionTo("inFlight")},reloadRecord:function(e,t){t(n(e,"store").reloadRecord(e))},rolledBack:function(e){e.transitionTo("loaded.saved")},becameInvalid:function(e){e.transitionTo("invalid")},rollback:function(e){e.rollback()}},inFlight:{isSaving:!0,didSetProperty:s,becomeDirty:Ember.K,pushedData:Ember.K,willCommit:Ember.K,didCommit:function(e){var t=n(this,"dirtyType");e.transitionTo("saved"),e.send("invokeLifecycleCallbacks",t)},becameInvalid:function(e,t){a(e,"errors",t),e.transitionTo("invalid"),e.send("invokeLifecycleCallbacks")},becameError:function(e){e.transitionTo("uncommitted"),e.triggerLater("becameError",e)}},invalid:{isValid:!1,deleteRecord:function(e){e.transitionTo("deleted.uncommitted"),e.clearRelationships()},didSetProperty:function(e,t){var r=n(e,"errors"),i=t.name;a(r,i,null),o(r)||e.send("becameValid"),s(e,t)},becomeDirty:Ember.K,rollback:function(e){e.send("becameValid"),e.send("rollback")},becameValid:function(e){e.transitionTo("uncommitted")},invokeLifecycleCallbacks:function(e){e.triggerLater("becameInvalid",e)}}},d=r({dirtyType:"created",isNew:!0});d.uncommitted.rolledBack=function(e){e.transitionTo("deleted.saved")};var u=r({dirtyType:"updated"});d.uncommitted.deleteRecord=function(e){e.clearRelationships(),e.transitionTo("deleted.saved")},d.uncommitted.rollback=function(e){c.uncommitted.rollback.apply(this,arguments),e.transitionTo("deleted.saved")},u.uncommitted.deleteRecord=function(e){e.transitionTo("deleted.uncommitted"),e.clearRelationships()};var l={isEmpty:!1,isLoading:!1,isLoaded:!1,isDirty:!1,isSaving:!1,isDeleted:!1,isNew:!1,isValid:!0,rolledBack:Ember.K,propertyWasReset:Ember.K,empty:{isEmpty:!0,loadingData:function(e,t){e._loadingPromise=t,e.transitionTo("loading")},loadedData:function(e){e.transitionTo("loaded.created.uncommitted"),e.suspendRelationshipObservers(function(){e.notifyPropertyChange("data")})},pushedData:function(e){e.transitionTo("loaded.saved"),e.triggerLater("didLoad")}},loading:{isLoading:!0,exit:function(e){e._loadingPromise=null},pushedData:function(e){e.transitionTo("loaded.saved"),e.triggerLater("didLoad"),a(e,"isError",!1)},becameError:function(e){e.triggerLater("becameError",e)},notFound:function(e){e.transitionTo("empty")}},loaded:{initialState:"saved",isLoaded:!0,saved:{setup:function(e){var t=e._attributes,r=!1;for(var i in t)if(t.hasOwnProperty(i)){r=!0;break}r&&e.adapterDidDirty()},didSetProperty:s,pushedData:Ember.K,becomeDirty:function(e){e.transitionTo("updated.uncommitted")},willCommit:function(e){e.transitionTo("updated.inFlight")},reloadRecord:function(e,t){t(n(e,"store").reloadRecord(e))},deleteRecord:function(e){e.transitionTo("deleted.uncommitted"),e.clearRelationships()},unloadRecord:function(e){e.clearRelationships(),e.transitionTo("deleted.saved")},didCommit:function(e){e.send("invokeLifecycleCallbacks",n(e,"lastDirtyType"))},notFound:Ember.K},created:d,updated:u},deleted:{initialState:"uncommitted",dirtyType:"deleted",isDeleted:!0,isLoaded:!0,isDirty:!0,setup:function(e){e.updateRecordArrays()},uncommitted:{willCommit:function(e){e.transitionTo("inFlight")},rollback:function(e){e.rollback()},becomeDirty:Ember.K,deleteRecord:Ember.K,rolledBack:function(e){e.transitionTo("loaded.saved")}},inFlight:{isSaving:!0,willCommit:Ember.K,didCommit:function(e){e.transitionTo("saved"),e.send("invokeLifecycleCallbacks")},becameError:function(e){e.transitionTo("uncommitted"),e.triggerLater("becameError",e)}},saved:{isDirty:!1,setup:function(e){var t=n(e,"store");t.dematerializeRecord(e)},invokeLifecycleCallbacks:function(e){e.triggerLater("didDelete",e),e.triggerLater("didCommit",e)}}},invokeLifecycleCallbacks:function(e,t){"created"===t?e.triggerLater("didCreate",e):e.triggerLater("didUpdate",e),e.triggerLater("didCommit",e)}};l=i(l,null,"root"),DS.RootState=l}(),function(){var e=Ember.get,t=Ember.set,r=Ember.merge,i=Ember.run.once,n=Ember.computed("currentState",function(t){return e(e(this,"currentState"),t)}).readOnly();DS.Model=Ember.Object.extend(Ember.Evented,{isEmpty:n,isLoading:n,isLoaded:n,isDirty:n,isSaving:n,isDeleted:n,isNew:n,isValid:n,dirtyType:n,isError:!1,isReloading:!1,clientId:null,id:null,transaction:null,currentState:null,errors:null,serialize:function(t){var r=e(this,"store");return r.serialize(this,t)},toJSON:function(e){var t=DS.JSONSerializer.create({container:this.container});return t.serialize(this,e)},didLoad:Ember.K,didUpdate:Ember.K,didCreate:Ember.K,didDelete:Ember.K,becameInvalid:Ember.K,becameError:Ember.K,data:Ember.computed(function(){return this._data=this._data||{},this._data}).property(),_data:null,init:function(){t(this,"currentState",DS.RootState.empty),this._super(),this._setup()},_setup:function(){this._changesToSync={},this._deferredTriggers=[],this._data={},this._attributes={},this._inFlightAttributes={},this._relationships={}},send:function(t,r){var i=e(this,"currentState");return i[t]||this._unhandledEvent(i,t,r),i[t](this,r)},transitionTo:function(r){var i=r.split(".",1),n=e(this,"currentState"),a=n;do a.exit&&a.exit(this),a=a.parentState;while(!a.hasOwnProperty(i));var o,s,c=r.split("."),d=[],u=[];for(o=0,s=c.length;s>o;o++)a=a[c[o]],a.enter&&u.push(a),a.setup&&d.push(a);for(o=0,s=u.length;s>o;o++)u[o].enter(this);for(t(this,"currentState",a),o=0,s=d.length;s>o;o++)d[o].setup(this);this.updateRecordArraysLater()},_unhandledEvent:function(e,t,r){var i="Attempted to handle event `"+t+"` ";throw i+="on "+String(this)+" while in state ",i+=e.stateName+". ",void 0!==r&&(i+="Called with "+Ember.inspect(r)+"."),new Ember.Error(i)},withTransaction:function(t){var r=e(this,"transaction");r&&t(r)},loadingData:function(e){this.send("loadingData",e)},loadedData:function(){this.send("loadedData")},notFound:function(){this.send("notFound")},pushedData:function(){this.send("pushedData")},deleteRecord:function(){this.send("deleteRecord")},destroyRecord:function(){return this.deleteRecord(),this.save()},unloadRecord:function(){this.send("unloadRecord")},clearRelationships:function(){this.eachRelationship(function(e,r){if("belongsTo"===r.kind)t(this,e,null);else if("hasMany"===r.kind){var i=this._relationships[r.name];i&&i.clear()}},this)},updateRecordArrays:function(){e(this,"store").dataWasUpdated(this.constructor,this)},changedAttributes:function(){var t,r=e(this,"_data"),i=e(this,"_attributes"),n={};for(t in i)n[t]=[r[t],i[t]];return n},adapterWillCommit:function(){this.send("willCommit")},adapterDidCommit:function(e){t(this,"isError",!1),e?this._data=e:Ember.mixin(this._data,this._inFlightAttributes),this._inFlightAttributes={},this.send("didCommit"),this.updateRecordArraysLater(),e&&this.suspendRelationshipObservers(function(){this.notifyPropertyChange("data")})},adapterDidDirty:function(){this.send("becomeDirty"),this.updateRecordArraysLater()},dataDidChange:Ember.observer(function(){this.reloadHasManys()},"data"),reloadHasManys:function(){var t=e(this.constructor,"relationshipsByName");this.updateRecordArraysLater(),t.forEach(function(e,t){this._data.links&&this._data.links[e]||"hasMany"===t.kind&&this.hasManyDidChange(t.key)},this)},hasManyDidChange:function(e){var r=this._relationships[e];if(r){var i=this._data[e]||[];t(r,"content",Ember.A(i)),t(r,"isLoaded",!0),r.trigger("didLoad")}},updateRecordArraysLater:function(){Ember.run.once(this,this.updateRecordArrays)},setupData:function(e,t){t?Ember.merge(this._data,e):this._data=e;var r=this._relationships;this.eachRelationship(function(t,i){e.links&&e.links[t]||i.options.async&&(r[t]=null)}),e&&this.pushedData(),this.suspendRelationshipObservers(function(){this.notifyPropertyChange("data")})},materializeId:function(e){t(this,"id",e)},materializeAttributes:function(e){r(this._data,e)},materializeAttribute:function(e,t){this._data[e]=t},updateHasMany:function(e,t){this._data[e]=t,this.hasManyDidChange(e)},updateBelongsTo:function(e,t){this._data[e]=t},rollback:function(){this._attributes={},e(this,"isError")&&(this._inFlightAttributes={},t(this,"isError",!1)),e(this,"isValid")||(this._inFlightAttributes={},this.send("becameValid")),this.send("rolledBack"),this.suspendRelationshipObservers(function(){this.notifyPropertyChange("data")})},toStringExtension:function(){return e(this,"id")},suspendRelationshipObservers:function(t,r){var i=e(this.constructor,"relationshipNames").belongsTo,n=this;try{this._suspendedRelationships=!0,Ember._suspendObservers(n,i,null,"belongsToDidChange",function(){Ember._suspendBeforeObservers(n,i,null,"belongsToWillChange",function(){t.call(r||n)})})}finally{this._suspendedRelationships=!1}},save:function(){var e="DS: Model#save "+this,t=Ember.RSVP.defer(e);return this.get("store").scheduleSave(this,t),this._inFlightAttributes=this._attributes,this._attributes={},DS.PromiseObject.create({promise:t.promise})},reload:function(){t(this,"isReloading",!0);var e=this,r="DS: Model#reload of "+this,i=new Ember.RSVP.Promise(function(t){e.send("reloadRecord",t)},r).then(function(){return e.set("isReloading",!1),e.set("isError",!1),e},function(t){throw e.set("isError",!0),t},"DS: Model#reload complete, update flags");return DS.PromiseObject.create({promise:i})},adapterDidUpdateAttribute:function(e,t){void 0!==t?(this._data[e]=t,this.notifyPropertyChange(e)):this._data[e]=this._inFlightAttributes[e],this.updateRecordArraysLater()},adapterDidInvalidate:function(e){this.send("becameInvalid",e)},adapterDidError:function(){this.send("becameError"),t(this,"isError",!0)},trigger:function(e){Ember.tryInvoke(this,e,[].slice.call(arguments,1)),this._super.apply(this,arguments)},triggerLater:function(){this._deferredTriggers.push(arguments),i(this,"_triggerDeferredTriggers")},_triggerDeferredTriggers:function(){for(var e=0,t=this._deferredTriggers.length;t>e;e++)this.trigger.apply(this,this._deferredTriggers[e]);this._deferredTriggers=[]}}),DS.Model.reopenClass({_create:DS.Model.create,create:function(){throw new Ember.Error("You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.")}})}(),function(){function e(e,t){return"function"==typeof t.defaultValue?t.defaultValue():t.defaultValue}function t(e,t){return e._attributes.hasOwnProperty(t)||e._inFlightAttributes.hasOwnProperty(t)||e._data.hasOwnProperty(t)}function r(e,t){return e._attributes.hasOwnProperty(t)?e._attributes[t]:e._inFlightAttributes.hasOwnProperty(t)?e._inFlightAttributes[t]:e._data[t]}var i=Ember.get;DS.Model.reopenClass({attributes:Ember.computed(function(){var e=Ember.Map.create();return this.eachComputedProperty(function(t,r){r.isAttribute&&(r.name=t,e.set(t,r))}),e}),transformedAttributes:Ember.computed(function(){var e=Ember.Map.create();return this.eachAttribute(function(t,r){r.type&&e.set(t,r.type)}),e}),eachAttribute:function(e,t){i(this,"attributes").forEach(function(r,i){e.call(t,r,i)
|
|
18
|
+
},t)},eachTransformedAttribute:function(e,t){i(this,"transformedAttributes").forEach(function(r,i){e.call(t,r,i)})}}),DS.Model.reopen({eachAttribute:function(e,t){this.constructor.eachAttribute(e,t)}}),DS.attr=function(i,n){n=n||{};var a={type:i,isAttribute:!0,options:n};return Ember.computed(function(i,a){if(arguments.length>1){var o=this._attributes[i]||this._inFlightAttributes[i]||this._data[i];return this.send("didSetProperty",{name:i,oldValue:o,originalValue:this._data[i],value:a}),this._attributes[i]=a,a}return t(this,i)?r(this,i):e(this,n,i)}).property("data").meta(a)}}(),function(){var e=DS.AttributeChange=function(e){this.record=e.record,this.store=e.store,this.name=e.name,this.value=e.value,this.oldValue=e.oldValue};e.createChange=function(t){return new e(t)},e.prototype={sync:function(){this.value!==this.oldValue&&(this.record.send("becomeDirty"),this.record.updateRecordArraysLater()),this.destroy()},destroy:function(){delete this.record._changesToSync[this.name]}}}(),function(){function e(e){return"object"==typeof e&&(!e.then||"function"!=typeof e.then)}var t=Ember.get,r=Ember.set,i=Ember.EnumerableUtils.forEach;DS.RelationshipChange=function(e){this.parentRecord=e.parentRecord,this.childRecord=e.childRecord,this.firstRecord=e.firstRecord,this.firstRecordKind=e.firstRecordKind,this.firstRecordName=e.firstRecordName,this.secondRecord=e.secondRecord,this.secondRecordKind=e.secondRecordKind,this.secondRecordName=e.secondRecordName,this.changeType=e.changeType,this.store=e.store,this.committed={}},DS.RelationshipChangeAdd=function(e){DS.RelationshipChange.call(this,e)},DS.RelationshipChangeRemove=function(e){DS.RelationshipChange.call(this,e)},DS.RelationshipChange.create=function(e){return new DS.RelationshipChange(e)},DS.RelationshipChangeAdd.create=function(e){return new DS.RelationshipChangeAdd(e)},DS.RelationshipChangeRemove.create=function(e){return new DS.RelationshipChangeRemove(e)},DS.OneToManyChange={},DS.OneToNoneChange={},DS.ManyToNoneChange={},DS.OneToOneChange={},DS.ManyToManyChange={},DS.RelationshipChange._createChange=function(e){return"add"===e.changeType?DS.RelationshipChangeAdd.create(e):"remove"===e.changeType?DS.RelationshipChangeRemove.create(e):void 0},DS.RelationshipChange.determineRelationshipType=function(e,t){var r,i,n=t.key,a=t.kind,o=e.inverseFor(n);return o&&(r=o.name,i=o.kind),o?"belongsTo"===i?"belongsTo"===a?"oneToOne":"manyToOne":"belongsTo"===a?"oneToMany":"manyToMany":"belongsTo"===a?"oneToNone":"manyToNone"},DS.RelationshipChange.createChange=function(e,t,r,i){var n,a=e.constructor;return n=DS.RelationshipChange.determineRelationshipType(a,i),"oneToMany"===n?DS.OneToManyChange.createChange(e,t,r,i):"manyToOne"===n?DS.OneToManyChange.createChange(t,e,r,i):"oneToNone"===n?DS.OneToNoneChange.createChange(e,t,r,i):"manyToNone"===n?DS.ManyToNoneChange.createChange(e,t,r,i):"oneToOne"===n?DS.OneToOneChange.createChange(e,t,r,i):"manyToMany"===n?DS.ManyToManyChange.createChange(e,t,r,i):void 0},DS.OneToNoneChange.createChange=function(e,t,r,i){var n=i.key,a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,store:r,changeType:i.changeType,firstRecordName:n,firstRecordKind:"belongsTo"});return r.addRelationshipChangeFor(e,n,t,null,a),a},DS.ManyToNoneChange.createChange=function(e,t,r,i){var n=i.key,a=DS.RelationshipChange._createChange({parentRecord:e,childRecord:t,secondRecord:e,store:r,changeType:i.changeType,secondRecordName:i.key,secondRecordKind:"hasMany"});return r.addRelationshipChangeFor(e,n,t,null,a),a},DS.ManyToManyChange.createChange=function(e,t,r,i){var n=i.key,a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,secondRecord:t,firstRecordKind:"hasMany",secondRecordKind:"hasMany",store:r,changeType:i.changeType,firstRecordName:n});return r.addRelationshipChangeFor(e,n,t,null,a),a},DS.OneToOneChange.createChange=function(e,t,r,i){var n;i.parentType?n=i.parentType.inverseFor(i.key).name:i.key&&(n=i.key);var a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,secondRecord:t,firstRecordKind:"belongsTo",secondRecordKind:"belongsTo",store:r,changeType:i.changeType,firstRecordName:n});return r.addRelationshipChangeFor(e,n,t,null,a),a},DS.OneToOneChange.maintainInvariant=function(e,r,i,n){if("add"===e.changeType&&r.recordIsMaterialized(i)){var a=t(i,n);if(a){var o=DS.OneToOneChange.createChange(i,a,r,{parentType:e.parentType,hasManyName:e.hasManyName,changeType:"remove",key:e.key});r.addRelationshipChangeFor(i,n,e.parentRecord,null,o),o.sync()}}},DS.OneToManyChange.createChange=function(e,t,r,i){var n;i.parentType?(n=i.parentType.inverseFor(i.key).name,DS.OneToManyChange.maintainInvariant(i,r,e,n)):i.key&&(n=i.key);var a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,secondRecord:t,firstRecordKind:"belongsTo",secondRecordKind:"hasMany",store:r,changeType:i.changeType,firstRecordName:n});return r.addRelationshipChangeFor(e,n,t,a.getSecondRecordName(),a),a},DS.OneToManyChange.maintainInvariant=function(e,r,i,n){if("add"===e.changeType&&i){var a=t(i,n);if(a){var o=DS.OneToManyChange.createChange(i,a,r,{parentType:e.parentType,hasManyName:e.hasManyName,changeType:"remove",key:e.key});r.addRelationshipChangeFor(i,n,e.parentRecord,o.getSecondRecordName(),o),o.sync()}}},DS.RelationshipChange.prototype={getSecondRecordName:function(){var e,t=this.secondRecordName;if(!t){if(e=this.secondRecord,!e)return;var r=this.firstRecord.constructor,i=r.inverseFor(this.firstRecordName);this.secondRecordName=i.name}return this.secondRecordName},getFirstRecordName:function(){var e=this.firstRecordName;return e},destroy:function(){var e=this.childRecord,t=this.getFirstRecordName(),r=this.getSecondRecordName(),i=this.store;i.removeRelationshipChangeFor(e,t,this.parentRecord,r,this.changeType)},getSecondRecord:function(){return this.secondRecord},getFirstRecord:function(){return this.firstRecord},coalesce:function(){var e=this.store.relationshipChangePairsFor(this.firstRecord);i(e,function(e){var t=e.add,r=e.remove;t&&r&&(t.destroy(),r.destroy())})}},DS.RelationshipChangeAdd.prototype=Ember.create(DS.RelationshipChange.create({})),DS.RelationshipChangeRemove.prototype=Ember.create(DS.RelationshipChange.create({})),DS.RelationshipChangeAdd.prototype.changeType="add",DS.RelationshipChangeAdd.prototype.sync=function(){var i=this.getSecondRecordName(),n=this.getFirstRecordName(),a=this.getFirstRecord(),o=this.getSecondRecord();o instanceof DS.Model&&a instanceof DS.Model&&("belongsTo"===this.secondRecordKind?o.suspendRelationshipObservers(function(){r(o,i,a)}):"hasMany"===this.secondRecordKind&&o.suspendRelationshipObservers(function(){var r=t(o,i);e(r)&&r.addObject(a)})),a instanceof DS.Model&&o instanceof DS.Model&&t(a,n)!==o&&("belongsTo"===this.firstRecordKind?a.suspendRelationshipObservers(function(){r(a,n,o)}):"hasMany"===this.firstRecordKind&&a.suspendRelationshipObservers(function(){var r=t(a,n);e(r)&&r.addObject(o)})),this.coalesce()},DS.RelationshipChangeRemove.prototype.changeType="remove",DS.RelationshipChangeRemove.prototype.sync=function(){var i=this.getSecondRecordName(),n=this.getFirstRecordName(),a=this.getFirstRecord(),o=this.getSecondRecord();o instanceof DS.Model&&a instanceof DS.Model&&("belongsTo"===this.secondRecordKind?o.suspendRelationshipObservers(function(){r(o,i,null)}):"hasMany"===this.secondRecordKind&&o.suspendRelationshipObservers(function(){var r=t(o,i);e(r)&&r.removeObject(a)})),a instanceof DS.Model&&t(a,n)&&("belongsTo"===this.firstRecordKind?a.suspendRelationshipObservers(function(){r(a,n,null)}):"hasMany"===this.firstRecordKind&&a.suspendRelationshipObservers(function(){var r=t(a,n);e(r)&&r.removeObject(o)})),this.coalesce()}}(),function(){function e(e,i,n){return Ember.computed(function(e,i){var a=t(this,"data"),o=t(this,"store"),s="DS: Async belongsTo "+this+" : "+e;if(2===arguments.length)return void 0===i?null:DS.PromiseObject.create({promise:Ember.RSVP.resolve(i,s)});var c=a.links&&a.links[e],d=a[e];if(r(d)){if(c){var u=Ember.RSVP.defer("DS: Async belongsTo (link) "+this+" : "+e);return o.findBelongsTo(this,c,n,u),DS.PromiseObject.create({promise:u.promise})}return null}var l=o.fetchRecord(d)||Ember.RSVP.resolve(d,s);return DS.PromiseObject.create({promise:l})}).property("data").meta(n)}var t=Ember.get,r=(Ember.set,Ember.isNone);DS.belongsTo=function(i,n){"object"==typeof i&&(n=i,i=void 0),n=n||{};var a={type:i,isRelationship:!0,options:n,kind:"belongsTo"};return n.async?e(i,n,a):Ember.computed(function(e,n){var a,o,s=t(this,"data"),c=t(this,"store");return o="string"==typeof i?c.modelFor(i):i,2===arguments.length?void 0===n?null:n:(a=s[e],r(a)?null:(c.fetchRecord(a),a))}).property("data").meta(a)},DS.Model.reopen({belongsToWillChange:Ember.beforeObserver(function(e,r){if(t(e,"isLoaded")){var i=t(e,r);if(i){var n=t(e,"store"),a=DS.RelationshipChange.createChange(e,i,n,{key:r,kind:"belongsTo",changeType:"remove"});a.sync(),this._changesToSync[r]=a}}}),belongsToDidChange:Ember.immediateObserver(function(e,r){if(t(e,"isLoaded")){var i=t(e,r);if(i){var n=t(e,"store"),a=DS.RelationshipChange.createChange(e,i,n,{key:r,kind:"belongsTo",changeType:"add"});a.sync()}}delete this._changesToSync[r]})})}(),function(){function e(e,r,i){return Ember.computed(function(e){var a=this._relationships[e],o="DS: Async hasMany "+this+" : "+e;if(!a){var s=Ember.RSVP.defer(o);a=t(this,e,r,function(t,r){var a,o=r.links&&r.links[e];return a=o?t.findHasMany(this,o,i,s):t.findMany(this,r[e],i.type,s),n(a,"promise",s.promise),a})}var c=a.get("promise").then(function(){return a},null,"DS: Async hasMany records received");return DS.PromiseArray.create({promise:c})}).property("data").meta(i)}function t(e,t,r,n){var o=e._relationships;if(o[t])return o[t];var s=i(e,"data"),c=i(e,"store"),d=o[t]=n.call(e,c,s);return a(d,{owner:e,name:t,isPolymorphic:r.polymorphic})}function r(r,i){i=i||{};var n={type:r,isRelationship:!0,options:i,kind:"hasMany"};return i.async?e(r,i,n):Ember.computed(function(e){return t(this,e,i,function(t,r){r[e];return t.findMany(this,r[e],n.type)})}).property("data").meta(n)}var i=Ember.get,n=Ember.set,a=Ember.setProperties;DS.hasMany=function(e,t){return"object"==typeof e&&(t=e,e=void 0),r(e,t)}}(),function(){{var e=Ember.get;Ember.set}DS.Model.reopen({didDefineProperty:function(e,t,r){if(r instanceof Ember.Descriptor){var i=r.meta();i.isRelationship&&"belongsTo"===i.kind&&(Ember.addObserver(e,t,null,"belongsToDidChange"),Ember.addBeforeObserver(e,t,null,"belongsToWillChange")),i.parentType=e.constructor}}}),DS.Model.reopenClass({typeForRelationship:function(t){var r=e(this,"relationshipsByName").get(t);return r&&r.type},inverseFor:function(t){function r(t,i,n){n=n||[];var a=e(i,"relationships");if(a){var o=a.get(t);return o&&n.push.apply(n,a.get(t)),t.superclass&&r(t.superclass,i,n),n}}var i=this.typeForRelationship(t);if(!i)return null;var n=this.metaForProperty(t).options;if(null===n.inverse)return null;var a,o;if(n.inverse)a=n.inverse,o=Ember.get(i,"relationshipsByName").get(a).kind;else{var s=r(this,i);if(0===s.length)return null;a=s[0].name,o=s[0].kind}return{type:i,name:a,kind:o}},relationships:Ember.computed(function(){var e=new Ember.MapWithDefault({defaultValue:function(){return[]}});return this.eachComputedProperty(function(t,r){if(r.isRelationship){"string"==typeof r.type&&(r.type=this.store.modelFor(r.type));var i=e.get(r.type);i.push({name:t,kind:r.kind})}}),e}),relationshipNames:Ember.computed(function(){var e={hasMany:[],belongsTo:[]};return this.eachComputedProperty(function(t,r){r.isRelationship&&e[r.kind].push(t)}),e}),relatedTypes:Ember.computed(function(){var t,r=Ember.A();return this.eachComputedProperty(function(i,n){n.isRelationship&&(t=n.type,"string"==typeof t&&(t=e(this,t,!1)||this.store.modelFor(t)),r.contains(t)||r.push(t))}),r}),relationshipsByName:Ember.computed(function(){var e,t=Ember.Map.create();return this.eachComputedProperty(function(r,i){i.isRelationship&&(i.key=r,e=i.type,e||"hasMany"!==i.kind?e||(e=r):e=Ember.String.singularize(r),"string"==typeof e&&(i.type=this.store.modelFor(e)),t.set(r,i))}),t}),fields:Ember.computed(function(){var e=Ember.Map.create();return this.eachComputedProperty(function(t,r){r.isRelationship?e.set(t,r.kind):r.isAttribute&&e.set(t,"attribute")}),e}),eachRelationship:function(t,r){e(this,"relationshipsByName").forEach(function(e,i){t.call(r,e,i)})},eachRelatedType:function(t,r){e(this,"relatedTypes").forEach(function(e){t.call(r,e)})}}),DS.Model.reopen({eachRelationship:function(e,t){this.constructor.eachRelationship(e,t)}})}(),function(){var e=Ember.get,t=(Ember.set,Ember.run.once),r=Ember.EnumerableUtils.forEach;DS.RecordArrayManager=Ember.Object.extend({init:function(){this.filteredRecordArrays=Ember.MapWithDefault.create({defaultValue:function(){return[]}}),this.changedRecords=[]},recordDidChange:function(e){this.changedRecords.push(e),t(this,this.updateRecordArrays)},recordArraysForRecord:function(e){return e._recordArrays=e._recordArrays||Ember.OrderedSet.create(),e._recordArrays},updateRecordArrays:function(){r(this.changedRecords,function(t){e(t,"isDeleted")?this._recordWasDeleted(t):this._recordWasChanged(t)},this),this.changedRecords=[]},_recordWasDeleted:function(e){var t=e._recordArrays;t&&r(t,function(t){t.removeRecord(e)})},_recordWasChanged:function(t){var i,n=t.constructor,a=this.filteredRecordArrays.get(n);r(a,function(r){i=e(r,"filterFunction"),this.updateRecordArray(r,i,n,t)},this);var o=t._loadingRecordArrays;if(o){for(var s=0,c=o.length;c>s;s++)o[s].loadedRecord();t._loadingRecordArrays=[]}},updateRecordArray:function(e,t,r,i){var n;n=t?t(i):!0;var a=this.recordArraysForRecord(i);n?(a.add(e),e.addRecord(i)):n||(a.remove(e),e.removeRecord(i))},updateFilter:function(t,r,i){for(var n,a=this.store.typeMapFor(r),o=a.records,s=0,c=o.length;c>s;s++)n=o[s],e(n,"isDeleted")||e(n,"isEmpty")||this.updateRecordArray(t,i,r,n)},createManyArray:function(e,t){var i=DS.ManyArray.create({type:e,content:t,store:this.store});return r(t,function(e){var t=this.recordArraysForRecord(e);t.add(i)},this),i},registerFilteredRecordArray:function(e,t,r){var i=this.filteredRecordArrays.get(t);i.push(e),this.updateFilter(e,t,r)},registerWaitingRecordArray:function(e,t){var r=e._loadingRecordArrays||[];r.push(t),e._loadingRecordArrays=r}})}(),function(){var e=Ember.get,t=(Ember.set,Ember.ArrayPolyfills.map),r=["description","fileName","lineNumber","message","name","number","stack"];DS.InvalidError=function(e){var t=Error.prototype.constructor.call(this,"The backend rejected the commit because it was invalid: "+Ember.inspect(e));this.errors=e;for(var i=0,n=r.length;n>i;i++)this[r[i]]=t[r[i]]},DS.InvalidError.prototype=Ember.create(Error.prototype),DS.Adapter=Ember.Object.extend({find:Ember.required(Function),findAll:null,findQuery:null,generateIdForRecord:null,serialize:function(t,r){return e(t,"store").serializerFor(t.constructor.typeKey).serialize(t,r)},createRecord:Ember.required(Function),updateRecord:Ember.required(Function),deleteRecord:Ember.required(Function),findMany:function(e,r,i){var n=t.call(i,function(t){return this.find(e,r,t)},this);return Ember.RSVP.all(n)}})}(),function(){var e=Ember.get,t=Ember.String.fmt,r=Ember.EnumerableUtils.indexOf,i=0;DS.FixtureAdapter=DS.Adapter.extend({serializer:null,simulateRemoteResponse:!0,latency:50,fixturesForType:function(e){if(e.FIXTURES){var r=Ember.A(e.FIXTURES);return r.map(function(e){var r=typeof e.id;if("number"!==r&&"string"!==r)throw new Error(t("the id property must be defined as a number or string for fixture %@",[e]));return e.id=e.id+"",e})}return null},queryFixtures:function(){},updateFixtures:function(e,t){e.FIXTURES||(e.FIXTURES=[]);var r=e.FIXTURES;this.deleteLoadedFixture(e,t),r.push(t)},mockJSON:function(e,t,r){return e.serializerFor(t).serialize(r,{includeId:!0})},generateIdForRecord:function(){return"fixture-"+i++},find:function(e,t,r){var i,n=this.fixturesForType(t);return n&&(i=Ember.A(n).findProperty("id",r)),i?this.simulateRemoteCall(function(){return i},this):void 0},findMany:function(e,t,i){var n=this.fixturesForType(t);return n&&(n=n.filter(function(e){return-1!==r(i,e.id)})),n?this.simulateRemoteCall(function(){return n},this):void 0},findAll:function(e,t){var r=this.fixturesForType(t);return this.simulateRemoteCall(function(){return r},this)},findQuery:function(e,t,r){var i=this.fixturesForType(t);return i=this.queryFixtures(i,r,t),i?this.simulateRemoteCall(function(){return i},this):void 0},createRecord:function(e,t,r){var i=this.mockJSON(e,t,r);return this.updateFixtures(t,i),this.simulateRemoteCall(function(){return i},this)},updateRecord:function(e,t,r){var i=this.mockJSON(e,t,r);return this.updateFixtures(t,i),this.simulateRemoteCall(function(){return i},this)},deleteRecord:function(e,t,r){var i=this.mockJSON(e,t,r);return this.deleteLoadedFixture(t,i),this.simulateRemoteCall(function(){return null})},deleteLoadedFixture:function(e,t){var i=this.findExistingFixture(e,t);if(i){var n=r(e.FIXTURES,i);return e.FIXTURES.splice(n,1),!0}},findExistingFixture:function(t,r){var i=this.fixturesForType(t),n=e(r,"id");return this.findFixtureById(i,n)},findFixtureById:function(t,r){return Ember.A(t).find(function(t){return""+e(t,"id")==""+r?!0:!1})},simulateRemoteCall:function(t,r){var i=this;return new Ember.RSVP.Promise(function(n){e(i,"simulateRemoteResponse")?Ember.run.later(function(){n(t.call(r))},e(i,"latency")):Ember.run.schedule("actions",null,function(){n(t.call(r))})},"DS: FixtureAdapter#simulateRemoteCall")}})}(),function(){function e(e){return null==e?null:e+""}var t=Ember.get,r=(Ember.set,Ember.ArrayPolyfills.forEach),i=Ember.ArrayPolyfills.map;DS.RESTSerializer=DS.JSONSerializer.extend({normalize:function(e,t,r){return this.normalizeId(t),this.normalizeUsingDeclaredMapping(e,t),this.normalizeAttributes(e,t),this.normalizeRelationships(e,t),this.normalizeHash&&this.normalizeHash[r]&&this.normalizeHash[r](t),this._super(e,t,r)},normalizePayload:function(e,t){return t},normalizeId:function(e){var r=t(this,"primaryKey");"id"!==r&&(e.id=e[r],delete e[r])},normalizeUsingDeclaredMapping:function(e,r){var i,n,a=t(this,"attrs");if(a)for(n in a)i=a[n],r[n]=r[i],delete r[i]},normalizeAttributes:function(e,t){var r;this.keyForAttribute&&e.eachAttribute(function(e){r=this.keyForAttribute(e),e!==r&&(t[e]=t[r],delete t[r])},this)},normalizeRelationships:function(e,t){var r;this.keyForRelationship&&e.eachRelationship(function(e,i){r=this.keyForRelationship(e,i.kind),e!==r&&(t[e]=t[r],delete t[r])},this)},extractSingle:function(t,i,n,a){n=this.normalizePayload(i,n);var o,s=i.typeKey;for(var c in n){var d=this.typeForRoot(c),u=d===s;if(u&&"array"!==Ember.typeOf(n[c]))o=this.normalize(i,n[c],c);else{{t.modelFor(d)}r.call(n[c],function(r){var i=this.typeForRoot(c),n=t.modelFor(i),s=t.serializerFor(n);r=s.normalize(n,r,c);var d=u&&!a&&!o,l=u&&e(r.id)===a;d||l?o=r:t.push(i,r)},this)}}return o},extractArray:function(e,t,r){r=this.normalizePayload(t,r);var n,a=t.typeKey;for(var o in r){var s=o,c=!1;"_"===o.charAt(0)&&(c=!0,s=o.substr(1));var d=this.typeForRoot(s),u=e.modelFor(d),l=e.serializerFor(u),h=!c&&d===a,f=i.call(r[o],function(e){return l.normalize(u,e,o)},this);h?n=f:e.pushMany(d,f)}return n},pushPayload:function(e,t){t=this.normalizePayload(null,t);for(var r in t){var n=this.typeForRoot(r),a=e.modelFor(n),o=i.call(t[r],function(e){return this.normalize(a,e,r)},this);e.pushMany(n,o)}},typeForRoot:function(e){return Ember.String.singularize(e)},serialize:function(){return this._super.apply(this,arguments)},serializeIntoHash:function(e,t,r,i){e[t.typeKey]=this.serialize(r,i)},serializePolymorphicType:function(e,r,i){var n=i.key,a=t(e,n);n=this.keyForAttribute?this.keyForAttribute(n):n,r[n+"Type"]=a.constructor.typeKey}})}(),function(){var e=Ember.get,t=(Ember.set,Ember.ArrayPolyfills.forEach);DS.RESTAdapter=DS.Adapter.extend({defaultSerializer:"_rest",find:function(e,t,r){return this.ajax(this.buildURL(t.typeKey,r),"GET")},findAll:function(e,t,r){var i;return r&&(i={since:r}),this.ajax(this.buildURL(t.typeKey),"GET",{data:i})},findQuery:function(e,t,r){return this.ajax(this.buildURL(t.typeKey),"GET",{data:r})},findMany:function(e,t,r){return this.ajax(this.buildURL(t.typeKey),"GET",{data:{ids:r}})},findHasMany:function(t,r,i){var n=e(this,"host"),a=e(r,"id"),o=r.constructor.typeKey;return n&&"/"===i.charAt(0)&&"/"!==i.charAt(1)&&(i=n+i),this.ajax(this.urlPrefix(i,this.buildURL(o,a)),"GET")},findBelongsTo:function(t,r,i){var n=e(r,"id"),a=r.constructor.typeKey;return this.ajax(this.urlPrefix(i,this.buildURL(a,n)),"GET")},createRecord:function(e,t,r){var i={},n=e.serializerFor(t.typeKey);return n.serializeIntoHash(i,t,r,{includeId:!0}),this.ajax(this.buildURL(t.typeKey),"POST",{data:i})},updateRecord:function(t,r,i){var n={},a=t.serializerFor(r.typeKey);a.serializeIntoHash(n,r,i);var o=e(i,"id");return this.ajax(this.buildURL(r.typeKey,o),"PUT",{data:n})},deleteRecord:function(t,r,i){var n=e(i,"id");return this.ajax(this.buildURL(r.typeKey,n),"DELETE")},buildURL:function(t,r){var i=[],n=e(this,"host"),a=this.urlPrefix();return t&&i.push(this.pathForType(t)),r&&i.push(r),a&&i.unshift(a),i=i.join("/"),!n&&i&&(i="/"+i),i},urlPrefix:function(t,r){var i=e(this,"host"),n=e(this,"namespace"),a=[];return t?"/"===t.charAt(0)?i&&(t=t.slice(1),a.push(i)):/^http(s)?:\/\//.test(t)||a.push(r):(i&&a.push(i),n&&a.push(n)),t&&a.push(t),a.join("/")},pathForType:function(e){return Ember.String.pluralize(e)},ajaxError:function(e){return e&&(e.then=null),e},ajax:function(e,t,r){var i=this;return new Ember.RSVP.Promise(function(n,a){r=i.ajaxOptions(e,t,r),r.success=function(e){Ember.run(null,n,e)},r.error=function(e){Ember.run(null,a,i.ajaxError(e))},Ember.$.ajax(r)},"DS: RestAdapter#ajax "+t+" to "+e)},ajaxOptions:function(e,r,i){if(i=i||{},i.url=e,i.type=r,i.dataType="json",i.context=this,i.data&&"GET"!==r&&(i.contentType="application/json; charset=utf-8",i.data=JSON.stringify(i.data)),void 0!==this.headers){var n=this.headers;i.beforeSend=function(e){t.call(Ember.keys(n),function(t){e.setRequestHeader(t,n[t])})}}return i}})}(),function(){DS.Model.reopen({_debugInfo:function(){var e=["id"],t={belongsTo:[],hasMany:[]},r=[];this.eachAttribute(function(t){e.push(t)},this),this.eachRelationship(function(e,i){t[i.kind].push(e),r.push(e)});var i=[{name:"Attributes",properties:e,expand:!0},{name:"Belongs To",properties:t.belongsTo,expand:!0},{name:"Has Many",properties:t.hasMany,expand:!0},{name:"Flags",properties:["isLoaded","isDirty","isSaving","isDeleted","isError","isNew","isValid"]}];return{propertyInfo:{includeOtherProperties:!0,groups:i,expensiveProperties:r}}}})}(),function(){Ember.String.pluralize=function(e){return Ember.Inflector.inflector.pluralize(e)},Ember.String.singularize=function(e){return Ember.Inflector.inflector.singularize(e)}}(),function(){function e(e,t){for(var r=0,i=t.length;i>r;r++)e.uncountable[t[r].toLowerCase()]=!0}function t(e,t){for(var r,i=0,n=t.length;n>i;i++)r=t[i],e.irregular[r[0].toLowerCase()]=r[1],e.irregularInverse[r[1].toLowerCase()]=r[0]}function r(r){r=r||{},r.uncountable=r.uncountable||{},r.irregularPairs=r.irregularPairs||{};var i=this.rules={plurals:r.plurals||[],singular:r.singular||[],irregular:{},irregularInverse:{},uncountable:{}};e(i,r.uncountable),t(i,r.irregularPairs)}var i=/^\s*$/;r.prototype={plural:function(e,t){this.rules.plurals.push([e,t.toLowerCase()])},singular:function(e,t){this.rules.singular.push([e,t.toLowerCase()])},uncountable:function(t){e(this.rules,[t.toLowerCase()])},irregular:function(e,r){t(this.rules,[[e,r]])},pluralize:function(e){return this.inflect(e,this.rules.plurals,this.rules.irregular)},singularize:function(e){return this.inflect(e,this.rules.singular,this.rules.irregularInverse)},inflect:function(e,t,r){var n,a,o,s,c,d,u,l;if(c=i.test(e))return e;if(s=e.toLowerCase(),d=this.rules.uncountable[s])return e;if(u=r&&r[s])return u;for(var h=t.length,f=0;h>f&&(n=t[h-1],l=n[0],!l.test(e));h--);return n=n||[],l=n[0],a=n[1],o=e.replace(l,a)}},Ember.Inflector=r}(),function(){Ember.Inflector.defaultRules={plurals:[[/$/,"s"],[/s$/i,"s"],[/^(ax|test)is$/i,"$1es"],[/(octop|vir)us$/i,"$1i"],[/(octop|vir)i$/i,"$1i"],[/(alias|status)$/i,"$1es"],[/(bu)s$/i,"$1ses"],[/(buffal|tomat)o$/i,"$1oes"],[/([ti])um$/i,"$1a"],[/([ti])a$/i,"$1a"],[/sis$/i,"ses"],[/(?:([^f])fe|([lr])f)$/i,"$1$2ves"],[/(hive)$/i,"$1s"],[/([^aeiouy]|qu)y$/i,"$1ies"],[/(x|ch|ss|sh)$/i,"$1es"],[/(matr|vert|ind)(?:ix|ex)$/i,"$1ices"],[/^(m|l)ouse$/i,"$1ice"],[/^(m|l)ice$/i,"$1ice"],[/^(ox)$/i,"$1en"],[/^(oxen)$/i,"$1"],[/(quiz)$/i,"$1zes"]],singular:[[/s$/i,""],[/(ss)$/i,"$1"],[/(n)ews$/i,"$1ews"],[/([ti])a$/i,"$1um"],[/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i,"$1sis"],[/(^analy)(sis|ses)$/i,"$1sis"],[/([^f])ves$/i,"$1fe"],[/(hive)s$/i,"$1"],[/(tive)s$/i,"$1"],[/([lr])ves$/i,"$1f"],[/([^aeiouy]|qu)ies$/i,"$1y"],[/(s)eries$/i,"$1eries"],[/(m)ovies$/i,"$1ovie"],[/(x|ch|ss|sh)es$/i,"$1"],[/^(m|l)ice$/i,"$1ouse"],[/(bus)(es)?$/i,"$1"],[/(o)es$/i,"$1"],[/(shoe)s$/i,"$1"],[/(cris|test)(is|es)$/i,"$1is"],[/^(a)x[ie]s$/i,"$1xis"],[/(octop|vir)(us|i)$/i,"$1us"],[/(alias|status)(es)?$/i,"$1"],[/^(ox)en/i,"$1"],[/(vert|ind)ices$/i,"$1ex"],[/(matr)ices$/i,"$1ix"],[/(quiz)zes$/i,"$1"],[/(database)s$/i,"$1"]],irregularPairs:[["person","people"],["man","men"],["child","children"],["sex","sexes"],["move","moves"],["cow","kine"],["zombie","zombies"]],uncountable:["equipment","information","rice","money","species","series","fish","sheep","jeans","police"]}}(),function(){(Ember.EXTEND_PROTOTYPES===!0||Ember.EXTEND_PROTOTYPES.String)&&(String.prototype.pluralize=function(){return Ember.String.pluralize(this)},String.prototype.singularize=function(){return Ember.String.singularize(this)})}(),function(){Ember.Inflector.inflector=new Ember.Inflector(Ember.Inflector.defaultRules)}(),function(){var e=Ember.get,t=Ember.EnumerableUtils.forEach;DS.ActiveModelSerializer=DS.RESTSerializer.extend({keyForAttribute:function(e){return Ember.String.decamelize(e)},keyForRelationship:function(e,t){return e=Ember.String.decamelize(e),"belongsTo"===t?e+"_id":"hasMany"===t?Ember.String.singularize(e)+"_ids":e},serializeHasMany:Ember.K,serializeIntoHash:function(e,t,r,i){var n=Ember.String.decamelize(t.typeKey);e[n]=this.serialize(r,i)},serializePolymorphicType:function(t,r,i){var n=i.key,a=e(t,n);n=this.keyForAttribute(n),r[n+"_type"]=Ember.String.capitalize(a.constructor.typeKey)},typeForRoot:function(e){var t=Ember.String.camelize(e);return Ember.String.singularize(t)},normalize:function(e,t,r){return this.normalizeLinks(t),this._super(e,t,r)},normalizeLinks:function(e){if(e.links){var t=e.links;for(var r in t){var i=Ember.String.camelize(r);i!==r&&(t[i]=t[r],delete t[r])}}},normalizeRelationships:function(e,r){var i,n;this.keyForRelationship&&e.eachRelationship(function(e,a){if(a.options.polymorphic){if(i=this.keyForAttribute(e),n=r[i],n&&n.type)n.type=this.typeForRoot(n.type);else if(n&&"hasMany"===a.kind){var o=this;t(n,function(e){e.type=o.typeForRoot(e.type)})}}else i=this.keyForRelationship(e,a.kind),n=r[i];r[e]=n,e!==i&&delete r[i]},this)}})}(),function(){function e(i,n,a,o,s){var c=t(n,"attrs");c&&a.eachRelationship(function(n,a){var d,u,l,h,f=c[n],p=i.serializerFor(a.type.typeKey),m=t(p,"primaryKey");if("hasMany"===a.kind&&f&&("always"===f.embedded||"load"===f.embedded)){if(u="_"+Ember.String.pluralize(a.type.typeKey),d=this.keyForRelationship(n,a.kind),l=this.keyForAttribute(n),h=[],!o[l])return;s[u]=s[u]||[],r(o[l],function(t){var r=i.modelFor(a.type.typeKey);e(i,p,r,t,s),h.push(t[m]),s[u].push(t)}),o[d]=h,delete o[l]}},n)}var t=Ember.get,r=Ember.EnumerableUtils.forEach;DS.EmbeddedRecordsMixin=Ember.Mixin.create({serializeHasMany:function(e,r,i){var n=i.key,a=t(this,"attrs"),o=a&&a[n]&&"always"===a[n].embedded;o&&(r[this.keyForAttribute(n)]=t(e,n).map(function(e){var r=e.serialize(),i=t(this,"primaryKey");return r[i]=t(e,i),r},this))},extractSingle:function(t,r,i,n,a){var o=this.keyForAttribute(r.typeKey),s=i[o];return e(t,this,r,s,i),this._super(t,r,i,n,a)},extractArray:function(t,i,n){var a=this.keyForAttribute(i.typeKey),o=n[Ember.String.pluralize(a)];return r(o,function(r){e(t,this,i,r,n)},this),this._super(t,i,n)}})}(),function(){var e=Ember.EnumerableUtils.forEach;DS.ActiveModelAdapter=DS.RESTAdapter.extend({defaultSerializer:"_ams",pathForType:function(e){var t=Ember.String.decamelize(e);return Ember.String.pluralize(t)},ajaxError:function(t){var r=this._super(t);if(t&&422===t.status){var i=Ember.$.parseJSON(t.responseText).errors,n={};return e(Ember.keys(i),function(e){n[Ember.String.camelize(e)]=i[e]}),new DS.InvalidError(n)}return r}})}(),function(){Ember.onLoad("Ember.Application",function(e){e.initializer({name:"activeModelAdapter",initialize:function(e,t){t.register("serializer:_ams",DS.ActiveModelSerializer),t.register("adapter:_ams",DS.ActiveModelAdapter)}})})}()}(),"undefined"==typeof location||"localhost"!==location.hostname&&"127.0.0.1"!==location.hostname||Ember.Logger.warn("You are running a production build of Ember on localhost and won't receive detailed error messages. If you want full error messages please use the non-minified build provided on the Ember website.");
|
data/dist/ember-data.prod.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
/*!
|
|
2
|
+
* @overview Ember Data
|
|
3
|
+
* @copyright Copyright 2011-2013 Tilde Inc. and contributors.
|
|
4
|
+
* Portions Copyright 2011 LivingSocial Inc.
|
|
5
|
+
* @license Licensed under MIT license (see license.js)
|
|
6
|
+
*/
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
// Version: v1.0.0-beta.3-48-gb47afef
|
|
11
|
-
// Last commit: b47afef (2013-10-08 19:07:59 -0700)
|
|
12
|
-
|
|
9
|
+
// Version: 1.0.0-beta.4
|
|
13
10
|
|
|
14
11
|
(function() {
|
|
15
12
|
var define, requireModule;
|
|
@@ -61,10 +58,10 @@ var define, requireModule;
|
|
|
61
58
|
@class DS
|
|
62
59
|
@static
|
|
63
60
|
*/
|
|
64
|
-
|
|
61
|
+
var DS;
|
|
65
62
|
if ('undefined' === typeof DS) {
|
|
66
63
|
DS = Ember.Namespace.create({
|
|
67
|
-
VERSION: '1.0.0-beta.
|
|
64
|
+
VERSION: '1.0.0-beta.4'
|
|
68
65
|
});
|
|
69
66
|
|
|
70
67
|
if ('undefined' !== typeof window) {
|
|
@@ -75,6 +72,7 @@ if ('undefined' === typeof DS) {
|
|
|
75
72
|
Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION);
|
|
76
73
|
}
|
|
77
74
|
}
|
|
75
|
+
|
|
78
76
|
})();
|
|
79
77
|
|
|
80
78
|
|
|
@@ -90,9 +88,56 @@ function aliasMethod(methodName) {
|
|
|
90
88
|
};
|
|
91
89
|
}
|
|
92
90
|
|
|
91
|
+
/**
|
|
92
|
+
In Ember Data a Serializer is used to serialize and deserialize
|
|
93
|
+
records when they are transfered in and out of an external source.
|
|
94
|
+
This process involves normalizing property names, transforming
|
|
95
|
+
attribute values and serializeing relationships.
|
|
96
|
+
|
|
97
|
+
For maximum performance Ember Data recomends you use the
|
|
98
|
+
[RESTSerializer](DS.RESTSerializer.html) or one of its subclasses.
|
|
99
|
+
|
|
100
|
+
`JSONSerializer` is useful for simpler or legacy backends that may
|
|
101
|
+
not support the http://jsonapi.org/ spec.
|
|
102
|
+
|
|
103
|
+
@class JSONSerializer
|
|
104
|
+
@namespace DS
|
|
105
|
+
*/
|
|
93
106
|
DS.JSONSerializer = Ember.Object.extend({
|
|
107
|
+
/**
|
|
108
|
+
The primaryKey is used when serializing and deserializing
|
|
109
|
+
data. Ember Data always uses the `id` propery to store the id of
|
|
110
|
+
the record. The external source may not always follow this
|
|
111
|
+
convention. In these cases it is usesful to override the
|
|
112
|
+
primaryKey property to match the primaryKey of your external
|
|
113
|
+
store.
|
|
114
|
+
|
|
115
|
+
Example
|
|
116
|
+
|
|
117
|
+
```javascript
|
|
118
|
+
App.ApplicationSerializer = DS.JSONSerializer.extend({
|
|
119
|
+
primaryKey: '_id'
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
@property primaryKey
|
|
124
|
+
@type {String}
|
|
125
|
+
*/
|
|
94
126
|
primaryKey: 'id',
|
|
95
127
|
|
|
128
|
+
/**
|
|
129
|
+
Given a subclass of `DS.Model` and a JSON object this method will
|
|
130
|
+
iterate through each attribute of the `DS.Model` and invoke the
|
|
131
|
+
`DS.Transform#deserialize` method on the matching property of the
|
|
132
|
+
JSON object. This method is typically called after the
|
|
133
|
+
serializer's `normalize` method.
|
|
134
|
+
|
|
135
|
+
@method applyTransforms
|
|
136
|
+
@private
|
|
137
|
+
@param {subclass of DS.Model} type
|
|
138
|
+
@param {Object} data The data to transform
|
|
139
|
+
@return {Object} data The transformed data object
|
|
140
|
+
*/
|
|
96
141
|
applyTransforms: function(type, data) {
|
|
97
142
|
type.eachTransformedAttribute(function(key, type) {
|
|
98
143
|
var transform = this.transformFor(type);
|
|
@@ -102,6 +147,39 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
|
102
147
|
return data;
|
|
103
148
|
},
|
|
104
149
|
|
|
150
|
+
/**
|
|
151
|
+
Normalizes a part of the JSON payload returned by
|
|
152
|
+
the server. You should override this method, munge the hash
|
|
153
|
+
and call super if you have generic normalization to do.
|
|
154
|
+
|
|
155
|
+
It takes the type of the record that is being normalized
|
|
156
|
+
(as a DS.Model class), the property where the hash was
|
|
157
|
+
originally found, and the hash to normalize.
|
|
158
|
+
|
|
159
|
+
You can use this method, for example, to normalize underscored keys to camelized
|
|
160
|
+
or other general-purpose normalizations.
|
|
161
|
+
|
|
162
|
+
Example
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
App.ApplicationSerializer = DS.JSONSerializer.extend({
|
|
166
|
+
normalize: function(type, hash) {
|
|
167
|
+
var normalizedHash = {};
|
|
168
|
+
var fields = Ember.get(type, 'fields');
|
|
169
|
+
fields.forEach(function(field) {
|
|
170
|
+
var normalizedProp = Ember.String.camelize(field);
|
|
171
|
+
normalizedHash[normalizedProp] = hash[field];
|
|
172
|
+
});
|
|
173
|
+
return this._super.apply(this, arguments);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
@method normalize
|
|
179
|
+
@param {subclass of DS.Model} type
|
|
180
|
+
@param {Object} hash
|
|
181
|
+
@return {Object}
|
|
182
|
+
*/
|
|
105
183
|
normalize: function(type, hash) {
|
|
106
184
|
if (!hash) { return hash; }
|
|
107
185
|
|
|
@@ -110,7 +188,149 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
|
110
188
|
},
|
|
111
189
|
|
|
112
190
|
// SERIALIZE
|
|
191
|
+
/**
|
|
192
|
+
Called when a record is saved in order to convert the
|
|
193
|
+
record into JSON.
|
|
194
|
+
|
|
195
|
+
By default, it creates a JSON object with a key for
|
|
196
|
+
each attribute and belongsTo relationship.
|
|
197
|
+
|
|
198
|
+
For example, consider this model:
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
App.Comment = DS.Model.extend({
|
|
202
|
+
title: DS.attr(),
|
|
203
|
+
body: DS.attr(),
|
|
204
|
+
|
|
205
|
+
author: DS.belongsTo('user')
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The default serialization would create a JSON object like:
|
|
210
|
+
|
|
211
|
+
```javascript
|
|
212
|
+
{
|
|
213
|
+
"title": "Rails is unagi",
|
|
214
|
+
"body": "Rails? Omakase? O_O",
|
|
215
|
+
"author": 12
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
By default, attributes are passed through as-is, unless
|
|
220
|
+
you specified an attribute type (`DS.attr('date')`). If
|
|
221
|
+
you specify a transform, the JavaScript value will be
|
|
222
|
+
serialized when inserted into the JSON hash.
|
|
223
|
+
|
|
224
|
+
By default, belongs-to relationships are converted into
|
|
225
|
+
IDs when inserted into the JSON hash.
|
|
226
|
+
|
|
227
|
+
## IDs
|
|
228
|
+
|
|
229
|
+
`serialize` takes an options hash with a single option:
|
|
230
|
+
`includeId`. If this option is `true`, `serialize` will,
|
|
231
|
+
by default include the ID in the JSON object it builds.
|
|
232
|
+
|
|
233
|
+
The adapter passes in `includeId: true` when serializing
|
|
234
|
+
a record for `createRecord`, but not for `updateRecord`.
|
|
235
|
+
|
|
236
|
+
## Customization
|
|
237
|
+
|
|
238
|
+
Your server may expect a different JSON format than the
|
|
239
|
+
built-in serialization format.
|
|
240
|
+
|
|
241
|
+
In that case, you can implement `serialize` yourself and
|
|
242
|
+
return a JSON hash of your choosing.
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
App.PostSerializer = DS.JSONSerializer.extend({
|
|
246
|
+
serialize: function(post, options) {
|
|
247
|
+
var json = {
|
|
248
|
+
POST_TTL: post.get('title'),
|
|
249
|
+
POST_BDY: post.get('body'),
|
|
250
|
+
POST_CMS: post.get('comments').mapProperty('id')
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (options.includeId) {
|
|
254
|
+
json.POST_ID_ = post.get('id');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return json;
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Customizing an App-Wide Serializer
|
|
263
|
+
|
|
264
|
+
If you want to define a serializer for your entire
|
|
265
|
+
application, you'll probably want to use `eachAttribute`
|
|
266
|
+
and `eachRelationship` on the record.
|
|
267
|
+
|
|
268
|
+
```javascript
|
|
269
|
+
App.ApplicationSerializer = DS.JSONSerializer.extend({
|
|
270
|
+
serialize: function(record, options) {
|
|
271
|
+
var json = {};
|
|
272
|
+
|
|
273
|
+
record.eachAttribute(function(name) {
|
|
274
|
+
json[serverAttributeName(name)] = record.get(name);
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
record.eachRelationship(function(name, relationship) {
|
|
278
|
+
if (relationship.kind === 'hasMany') {
|
|
279
|
+
json[serverHasManyName(name)] = record.get(name).mapBy('id');
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
if (options.includeId) {
|
|
284
|
+
json.ID_ = record.get('id');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return json;
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
function serverAttributeName(attribute) {
|
|
292
|
+
return attribute.underscore().toUpperCase();
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function serverHasManyName(name) {
|
|
296
|
+
return serverAttributeName(name.singularize()) + "_IDS";
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
This serializer will generate JSON that looks like this:
|
|
113
301
|
|
|
302
|
+
```javascript
|
|
303
|
+
{
|
|
304
|
+
"TITLE": "Rails is omakase",
|
|
305
|
+
"BODY": "Yep. Omakase.",
|
|
306
|
+
"COMMENT_IDS": [ 1, 2, 3 ]
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Tweaking the Default JSON
|
|
311
|
+
|
|
312
|
+
If you just want to do some small tweaks on the default JSON,
|
|
313
|
+
you can call super first and make the tweaks on the returned
|
|
314
|
+
JSON.
|
|
315
|
+
|
|
316
|
+
```javascript
|
|
317
|
+
App.PostSerializer = DS.JSONSerializer.extend({
|
|
318
|
+
serialize: function(record, options) {
|
|
319
|
+
var json = this._super.apply(this, arguments);
|
|
320
|
+
|
|
321
|
+
json.subject = json.title;
|
|
322
|
+
delete json.title;
|
|
323
|
+
|
|
324
|
+
return json;
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
@method serialize
|
|
330
|
+
@param {subclass of DS.Model} record
|
|
331
|
+
@param {Object} options
|
|
332
|
+
@return {Object} json
|
|
333
|
+
*/
|
|
114
334
|
serialize: function(record, options) {
|
|
115
335
|
var json = {};
|
|
116
336
|
|
|
@@ -137,6 +357,29 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
|
137
357
|
return json;
|
|
138
358
|
},
|
|
139
359
|
|
|
360
|
+
/**
|
|
361
|
+
`serializeAttribute` can be used to customize how `DS.attr`
|
|
362
|
+
properties are serialized
|
|
363
|
+
|
|
364
|
+
For example if you wanted to ensure all you attributes were always
|
|
365
|
+
serialized as properties on an `attributes` object you could
|
|
366
|
+
write:
|
|
367
|
+
|
|
368
|
+
```javascript
|
|
369
|
+
App.ApplicationSerializer = DS.JSONSerializer.extend({
|
|
370
|
+
serializeAttribute: function(record, json, key, attributes) {
|
|
371
|
+
json.attributes = json.attributes || {};
|
|
372
|
+
this._super(record, json.attributes, key, attributes);
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
@method serializeAttribute
|
|
378
|
+
@param {DS.Model} record
|
|
379
|
+
@param {Object} json
|
|
380
|
+
@param {String} key
|
|
381
|
+
@param {Object} attribute
|
|
382
|
+
*/
|
|
140
383
|
serializeAttribute: function(record, json, key, attribute) {
|
|
141
384
|
var attrs = get(this, 'attrs');
|
|
142
385
|
var value = get(record, key), type = attribute.type;
|
|
@@ -153,6 +396,31 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
|
153
396
|
json[key] = value;
|
|
154
397
|
},
|
|
155
398
|
|
|
399
|
+
/**
|
|
400
|
+
`serializeBelongsTo` can be used to customize how `DS.belongsTo`
|
|
401
|
+
properties are serialized.
|
|
402
|
+
|
|
403
|
+
Example
|
|
404
|
+
|
|
405
|
+
```javascript
|
|
406
|
+
App.PostSerializer = DS.JSONSerializer.extend({
|
|
407
|
+
serializeBelongsTo: function(record, json, relationship) {
|
|
408
|
+
var key = relationship.key;
|
|
409
|
+
|
|
410
|
+
var belongsTo = get(record, key);
|
|
411
|
+
|
|
412
|
+
key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo") : key;
|
|
413
|
+
|
|
414
|
+
json[key] = Ember.isNone(belongsTo) ? belongsTo : belongsTo.toJSON();
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
@method serializeBelongsTo
|
|
420
|
+
@param {DS.Model} record
|
|
421
|
+
@param {Object} json
|
|
422
|
+
@param {Object} relationship
|
|
423
|
+
*/
|
|
156
424
|
serializeBelongsTo: function(record, json, relationship) {
|
|
157
425
|
var key = relationship.key;
|
|
158
426
|
|
|
@@ -171,6 +439,30 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
|
171
439
|
}
|
|
172
440
|
},
|
|
173
441
|
|
|
442
|
+
/**
|
|
443
|
+
`serializeHasMany` can be used to customize how `DS.hasMany`
|
|
444
|
+
properties are serialized.
|
|
445
|
+
|
|
446
|
+
Example
|
|
447
|
+
|
|
448
|
+
```javascript
|
|
449
|
+
App.PostSerializer = DS.JSONSerializer.extend({
|
|
450
|
+
serializeHasMany: function(record, json, relationship) {
|
|
451
|
+
var key = relationship.key;
|
|
452
|
+
if (key === 'comments') {
|
|
453
|
+
return;
|
|
454
|
+
} else {
|
|
455
|
+
this._super.apply(this, arguments);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
@method serializeHasMany
|
|
462
|
+
@param {DS.Model} record
|
|
463
|
+
@param {Object} json
|
|
464
|
+
@param {Object} relationship
|
|
465
|
+
*/
|
|
174
466
|
serializeHasMany: function(record, json, relationship) {
|
|
175
467
|
var key = relationship.key;
|
|
176
468
|
|
|
@@ -183,12 +475,65 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
|
183
475
|
},
|
|
184
476
|
|
|
185
477
|
/**
|
|
186
|
-
You can use this method to customize how polymorphic objects are
|
|
478
|
+
You can use this method to customize how polymorphic objects are
|
|
479
|
+
serialized. Objects are considered to be polymorphic if
|
|
480
|
+
`{polymorphic: true}` is pass as the second argument to the
|
|
481
|
+
`DS.belongsTo` function.
|
|
482
|
+
|
|
483
|
+
Example
|
|
484
|
+
|
|
485
|
+
```javascript
|
|
486
|
+
App.CommentSerializer = DS.JSONSerializer.extend({
|
|
487
|
+
serializePolymorphicType: function(record, json, relationship) {
|
|
488
|
+
var key = relationship.key,
|
|
489
|
+
belongsTo = get(record, key);
|
|
490
|
+
key = this.keyForAttribute ? this.keyForAttribute(key) : key;
|
|
491
|
+
json[key + "_type"] = belongsTo.constructor.typeKey;
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
@method serializePolymorphicType
|
|
497
|
+
@param {DS.Model} record
|
|
498
|
+
@param {Object} json
|
|
499
|
+
@param {Object} relationship
|
|
187
500
|
*/
|
|
188
501
|
serializePolymorphicType: Ember.K,
|
|
189
502
|
|
|
190
503
|
// EXTRACT
|
|
191
504
|
|
|
505
|
+
/**
|
|
506
|
+
The `extract` method is used to deserialize payload data from the
|
|
507
|
+
server. By default the `JSONSerializer` does not push the records
|
|
508
|
+
into the store. However records that subclass `JSONSerializer`
|
|
509
|
+
such as the `RESTSerializer` may push records into the store as
|
|
510
|
+
part of the extract call.
|
|
511
|
+
|
|
512
|
+
This method deletegates to a more specific extract method based on
|
|
513
|
+
the `requestType`.
|
|
514
|
+
|
|
515
|
+
Example
|
|
516
|
+
|
|
517
|
+
```javascript
|
|
518
|
+
var get = Ember.get;
|
|
519
|
+
socket.on('message', function(message) {
|
|
520
|
+
var modelName = message.model;
|
|
521
|
+
var data = message.data;
|
|
522
|
+
var type = store.modelFor(modelName);
|
|
523
|
+
var serializer = store.serializerFor(type.typeKey);
|
|
524
|
+
var record = serializer.extract(store, type, data, get(data, 'id'), 'single');
|
|
525
|
+
store.push(modelName, record);
|
|
526
|
+
});
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
@method extract
|
|
530
|
+
@param {DS.Store} store
|
|
531
|
+
@param {subclass of DS.Model} type
|
|
532
|
+
@param {Object} payload
|
|
533
|
+
@param {String or Number} id
|
|
534
|
+
@param {String} requestType
|
|
535
|
+
@return {Object} json The deserialized payload
|
|
536
|
+
*/
|
|
192
537
|
extract: function(store, type, payload, id, requestType) {
|
|
193
538
|
this.extractMeta(store, type, payload);
|
|
194
539
|
|
|
@@ -196,27 +541,205 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
|
196
541
|
return this[specificExtract](store, type, payload, id, requestType);
|
|
197
542
|
},
|
|
198
543
|
|
|
544
|
+
/**
|
|
545
|
+
`extractFindAll` is a hook into the extract method used when a
|
|
546
|
+
call is made to `DS.Store#findAll`. By default this method is an
|
|
547
|
+
alias for [extractArray](#method_extractArray).
|
|
548
|
+
|
|
549
|
+
@method extractFindAll
|
|
550
|
+
@param {DS.Store} store
|
|
551
|
+
@param {subclass of DS.Model} type
|
|
552
|
+
@param {Object} payload
|
|
553
|
+
@return {Array} array An array of deserialized objects
|
|
554
|
+
*/
|
|
199
555
|
extractFindAll: aliasMethod('extractArray'),
|
|
556
|
+
/**
|
|
557
|
+
`extractFindQuery` is a hook into the extract method used when a
|
|
558
|
+
call is made to `DS.Store#findQuery`. By default this method is an
|
|
559
|
+
alias for [extractArray](#method_extractArray).
|
|
560
|
+
|
|
561
|
+
@method extractFindQuery
|
|
562
|
+
@param {DS.Store} store
|
|
563
|
+
@param {subclass of DS.Model} type
|
|
564
|
+
@param {Object} payload
|
|
565
|
+
@return {Array} array An array of deserialized objects
|
|
566
|
+
*/
|
|
200
567
|
extractFindQuery: aliasMethod('extractArray'),
|
|
568
|
+
/**
|
|
569
|
+
`extractFindMany` is a hook into the extract method used when a
|
|
570
|
+
call is made to `DS.Store#findMany`. By default this method is
|
|
571
|
+
alias for [extractArray](#method_extractArray).
|
|
572
|
+
|
|
573
|
+
@method extractFindMany
|
|
574
|
+
@param {DS.Store} store
|
|
575
|
+
@param {subclass of DS.Model} type
|
|
576
|
+
@param {Object} payload
|
|
577
|
+
@return {Array} array An array of deserialized objects
|
|
578
|
+
*/
|
|
201
579
|
extractFindMany: aliasMethod('extractArray'),
|
|
580
|
+
/**
|
|
581
|
+
`extractFindHasMany` is a hook into the extract method used when a
|
|
582
|
+
call is made to `DS.Store#findHasMany`. By default this method is
|
|
583
|
+
alias for [extractArray](#method_extractArray).
|
|
584
|
+
|
|
585
|
+
@method extractFindHasMany
|
|
586
|
+
@param {DS.Store} store
|
|
587
|
+
@param {subclass of DS.Model} type
|
|
588
|
+
@param {Object} payload
|
|
589
|
+
@return {Array} array An array of deserialized objects
|
|
590
|
+
*/
|
|
202
591
|
extractFindHasMany: aliasMethod('extractArray'),
|
|
203
592
|
|
|
593
|
+
/**
|
|
594
|
+
`extractCreateRecord` is a hook into the extract method used when a
|
|
595
|
+
call is made to `DS.Store#createRecord`. By default this method is
|
|
596
|
+
alias for [extractSave](#method_extractSave).
|
|
597
|
+
|
|
598
|
+
@method extractCreateRecord
|
|
599
|
+
@param {DS.Store} store
|
|
600
|
+
@param {subclass of DS.Model} type
|
|
601
|
+
@param {Object} payload
|
|
602
|
+
@return {Object} json The deserialized payload
|
|
603
|
+
*/
|
|
204
604
|
extractCreateRecord: aliasMethod('extractSave'),
|
|
605
|
+
/**
|
|
606
|
+
`extractUpdateRecord` is a hook into the extract method used when
|
|
607
|
+
a call is made to `DS.Store#update`. By default this method is alias
|
|
608
|
+
for [extractSave](#method_extractSave).
|
|
609
|
+
|
|
610
|
+
@method extractUpdateRecord
|
|
611
|
+
@param {DS.Store} store
|
|
612
|
+
@param {subclass of DS.Model} type
|
|
613
|
+
@param {Object} payload
|
|
614
|
+
@return {Object} json The deserialized payload
|
|
615
|
+
*/
|
|
205
616
|
extractUpdateRecord: aliasMethod('extractSave'),
|
|
617
|
+
/**
|
|
618
|
+
`extractDeleteRecord` is a hook into the extract method used when
|
|
619
|
+
a call is made to `DS.Store#deleteRecord`. By default this method is
|
|
620
|
+
alias for [extractSave](#method_extractSave).
|
|
621
|
+
|
|
622
|
+
@method extractDeleteRecord
|
|
623
|
+
@param {DS.Store} store
|
|
624
|
+
@param {subclass of DS.Model} type
|
|
625
|
+
@param {Object} payload
|
|
626
|
+
@return {Object} json The deserialized payload
|
|
627
|
+
*/
|
|
206
628
|
extractDeleteRecord: aliasMethod('extractSave'),
|
|
207
629
|
|
|
630
|
+
/**
|
|
631
|
+
`extractFind` is a hook into the extract method used when
|
|
632
|
+
a call is made to `DS.Store#find`. By default this method is
|
|
633
|
+
alias for [extractSingle](#method_extractSingle).
|
|
634
|
+
|
|
635
|
+
@method extractFind
|
|
636
|
+
@param {DS.Store} store
|
|
637
|
+
@param {subclass of DS.Model} type
|
|
638
|
+
@param {Object} payload
|
|
639
|
+
@return {Object} json The deserialized payload
|
|
640
|
+
*/
|
|
208
641
|
extractFind: aliasMethod('extractSingle'),
|
|
642
|
+
/**
|
|
643
|
+
`extractFindBelongsTo` is a hook into the extract method used when
|
|
644
|
+
a call is made to `DS.Store#findBelongsTo`. By default this method is
|
|
645
|
+
alias for [extractSingle](#method_extractSingle).
|
|
646
|
+
|
|
647
|
+
@method extractFindBelongsTo
|
|
648
|
+
@param {DS.Store} store
|
|
649
|
+
@param {subclass of DS.Model} type
|
|
650
|
+
@param {Object} payload
|
|
651
|
+
@return {Object} json The deserialized payload
|
|
652
|
+
*/
|
|
209
653
|
extractFindBelongsTo: aliasMethod('extractSingle'),
|
|
654
|
+
/**
|
|
655
|
+
`extractSave` is a hook into the extract method used when a call
|
|
656
|
+
is made to `DS.Model#save`. By default this method is alias
|
|
657
|
+
for [extractSingle](#method_extractSingle).
|
|
658
|
+
|
|
659
|
+
@method extractSave
|
|
660
|
+
@param {DS.Store} store
|
|
661
|
+
@param {subclass of DS.Model} type
|
|
662
|
+
@param {Object} payload
|
|
663
|
+
@return {Object} json The deserialized payload
|
|
664
|
+
*/
|
|
210
665
|
extractSave: aliasMethod('extractSingle'),
|
|
211
666
|
|
|
667
|
+
/**
|
|
668
|
+
`extractSingle` is used to deserialize a single record returned
|
|
669
|
+
from the adapter.
|
|
670
|
+
|
|
671
|
+
Example
|
|
672
|
+
|
|
673
|
+
```javascript
|
|
674
|
+
App.PostSerializer = DS.JSONSerializer.extend({
|
|
675
|
+
extractSingle: function(store, type, payload) {
|
|
676
|
+
payload.comments = payload._embedded.comment;
|
|
677
|
+
delete payload._embedded;
|
|
678
|
+
|
|
679
|
+
return this._super(store, type, payload);
|
|
680
|
+
},
|
|
681
|
+
});
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
@method extractSingle
|
|
685
|
+
@param {DS.Store} store
|
|
686
|
+
@param {subclass of DS.Model} type
|
|
687
|
+
@param {Object} payload
|
|
688
|
+
@return {Object} json The deserialized payload
|
|
689
|
+
*/
|
|
212
690
|
extractSingle: function(store, type, payload) {
|
|
213
691
|
return this.normalize(type, payload);
|
|
214
692
|
},
|
|
215
693
|
|
|
694
|
+
/**
|
|
695
|
+
`extractArray` is used to deserialize an array of records
|
|
696
|
+
returned from the adapter.
|
|
697
|
+
|
|
698
|
+
Example
|
|
699
|
+
|
|
700
|
+
```javascript
|
|
701
|
+
App.PostSerializer = DS.JSONSerializer.extend({
|
|
702
|
+
extractArray: function(store, type, payload) {
|
|
703
|
+
return payload.map(function(json) {
|
|
704
|
+
return this.extractSingle(json);
|
|
705
|
+
}, this);
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
@method extractArray
|
|
711
|
+
@param {DS.Store} store
|
|
712
|
+
@param {subclass of DS.Model} type
|
|
713
|
+
@param {Object} payload
|
|
714
|
+
@return {Array} array An array of deserialized objects
|
|
715
|
+
*/
|
|
216
716
|
extractArray: function(store, type, payload) {
|
|
217
717
|
return this.normalize(type, payload);
|
|
218
718
|
},
|
|
219
719
|
|
|
720
|
+
/**
|
|
721
|
+
`extractMeta` is used to deserialize any meta information in the
|
|
722
|
+
adapter payload. By default Ember Data expects meta information to
|
|
723
|
+
be located on the `meta` property of the payload object.
|
|
724
|
+
|
|
725
|
+
Example
|
|
726
|
+
|
|
727
|
+
```javascript
|
|
728
|
+
App.PostSerializer = DS.JSONSerializer.extend({
|
|
729
|
+
extractMeta: function(store, type, payload) {
|
|
730
|
+
if (payload && payload._pagination) {
|
|
731
|
+
store.metaForType(type, payload._pagination);
|
|
732
|
+
delete payload._pagination;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
@method extractMeta
|
|
739
|
+
@param {DS.Store} store
|
|
740
|
+
@param {subclass of DS.Model} type
|
|
741
|
+
@param {Object} payload
|
|
742
|
+
*/
|
|
220
743
|
extractMeta: function(store, type, payload) {
|
|
221
744
|
if (payload && payload.meta) {
|
|
222
745
|
store.metaForType(type, payload.meta);
|
|
@@ -224,8 +747,36 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
|
224
747
|
}
|
|
225
748
|
},
|
|
226
749
|
|
|
750
|
+
/**
|
|
751
|
+
`keyForRelationship` can be used to define a custom key when
|
|
752
|
+
serializeing relationship properties. By default `JSONSerializer`
|
|
753
|
+
does not provide an implementation of this method.
|
|
754
|
+
|
|
755
|
+
Example
|
|
756
|
+
|
|
757
|
+
```javascript
|
|
758
|
+
App.PostSerializer = DS.JSONSerializer.extend({
|
|
759
|
+
keyForRelationship: function(key, relationship) {
|
|
760
|
+
return 'rel_' + Ember.String.underscore(key);
|
|
761
|
+
}
|
|
762
|
+
});
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
@method keyForRelationship
|
|
766
|
+
@param {String} key
|
|
767
|
+
@param {String} relationship type
|
|
768
|
+
@return {String} normalized key
|
|
769
|
+
*/
|
|
770
|
+
|
|
227
771
|
// HELPERS
|
|
228
772
|
|
|
773
|
+
/**
|
|
774
|
+
@method transformFor
|
|
775
|
+
@private
|
|
776
|
+
@param {String} attributeType
|
|
777
|
+
@param {Boolean} skipAssertion
|
|
778
|
+
@return {DS.Transform} transform
|
|
779
|
+
*/
|
|
229
780
|
transformFor: function(attributeType, skipAssertion) {
|
|
230
781
|
var transform = this.container.lookup('transform:' + attributeType);
|
|
231
782
|
|
|
@@ -353,19 +904,105 @@ DS.DebugAdapter = Ember.DataAdapter.extend({
|
|
|
353
904
|
|
|
354
905
|
|
|
355
906
|
(function() {
|
|
907
|
+
/**
|
|
908
|
+
The `DS.Transform` class is used to serialize and deserialize model
|
|
909
|
+
attributes when they are saved or loaded from an
|
|
910
|
+
adapter. Subclassing `DS.Transform` is useful for creating custom
|
|
911
|
+
attributes. All subclasses of `DS.Transform` must implement a
|
|
912
|
+
`serialize` and a `deserialize` method.
|
|
913
|
+
|
|
914
|
+
Example
|
|
915
|
+
|
|
916
|
+
```javascript
|
|
917
|
+
App.RawTransform = DS.Transform.extend({
|
|
918
|
+
deserialize: function(serialized) {
|
|
919
|
+
return serialized;
|
|
920
|
+
},
|
|
921
|
+
serialize: function(deserialized) {
|
|
922
|
+
return deserialized;
|
|
923
|
+
}
|
|
924
|
+
});
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
Usage
|
|
928
|
+
|
|
929
|
+
```javascript
|
|
930
|
+
var attr = DS.attr;
|
|
931
|
+
App.Requirement = DS.Model.extend({
|
|
932
|
+
name: attr('string'),
|
|
933
|
+
optionsArray: attr('raw')
|
|
934
|
+
});
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
@class Transform
|
|
938
|
+
@namespace DS
|
|
939
|
+
*/
|
|
356
940
|
DS.Transform = Ember.Object.extend({
|
|
941
|
+
/**
|
|
942
|
+
When given a deserialized value from a record attribute this
|
|
943
|
+
method must return the serialized value.
|
|
357
944
|
|
|
945
|
+
Example
|
|
946
|
+
|
|
947
|
+
```javascript
|
|
948
|
+
serialize: function(deserialized) {
|
|
949
|
+
return Ember.isEmpty(deserialized) ? null : Number(deserialized);
|
|
950
|
+
}
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
@method serialize
|
|
954
|
+
@param deserialized The deserialized value
|
|
955
|
+
@return The serialized value
|
|
956
|
+
*/
|
|
358
957
|
serialize: Ember.required(),
|
|
359
|
-
|
|
958
|
+
|
|
959
|
+
/**
|
|
960
|
+
When given a serialize value from a JSON object this method must
|
|
961
|
+
return the deserialized value for the record attribute.
|
|
962
|
+
|
|
963
|
+
Example
|
|
964
|
+
|
|
965
|
+
```javascript
|
|
966
|
+
deserialize: function(serialized) {
|
|
967
|
+
return empty(serialized) ? null : Number(serialized);
|
|
968
|
+
}
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
@method deserialized
|
|
972
|
+
@param serialized The serialized value
|
|
973
|
+
@return The deserialized value
|
|
974
|
+
*/
|
|
360
975
|
deserialize: Ember.required()
|
|
361
976
|
|
|
362
977
|
});
|
|
978
|
+
|
|
363
979
|
})();
|
|
364
980
|
|
|
365
981
|
|
|
366
982
|
|
|
367
983
|
(function() {
|
|
368
984
|
|
|
985
|
+
/**
|
|
986
|
+
The `DS.BooleanTransform` class is used to serialize and deserialize
|
|
987
|
+
boolean attributes on Ember Data record objects. This transform is
|
|
988
|
+
used when `boolean` is passed as the type parameter to the
|
|
989
|
+
[DS.attr](../../data#method_attr) function.
|
|
990
|
+
|
|
991
|
+
Usage
|
|
992
|
+
|
|
993
|
+
```javascript
|
|
994
|
+
var attr = DS.attr;
|
|
995
|
+
App.User = DS.Model.extend({
|
|
996
|
+
isAdmin: attr('boolean'),
|
|
997
|
+
name: attr('string'),
|
|
998
|
+
email: attr('string')
|
|
999
|
+
});
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
@class BooleanTransform
|
|
1003
|
+
@extends DS.Transform
|
|
1004
|
+
@namespace DS
|
|
1005
|
+
*/
|
|
369
1006
|
DS.BooleanTransform = DS.Transform.extend({
|
|
370
1007
|
deserialize: function(serialized) {
|
|
371
1008
|
var type = typeof serialized;
|
|
@@ -391,6 +1028,25 @@ DS.BooleanTransform = DS.Transform.extend({
|
|
|
391
1028
|
|
|
392
1029
|
|
|
393
1030
|
(function() {
|
|
1031
|
+
/**
|
|
1032
|
+
The `DS.DateTransform` class is used to serialize and deserialize
|
|
1033
|
+
date attributes on Ember Data record objects. This transform is used
|
|
1034
|
+
when `date` is passed as the type parameter to the
|
|
1035
|
+
[DS.attr](../../data#method_attr) function.
|
|
1036
|
+
|
|
1037
|
+
```javascript
|
|
1038
|
+
var attr = DS.attr;
|
|
1039
|
+
App.Score = DS.Model.extend({
|
|
1040
|
+
value: attr('number'),
|
|
1041
|
+
player: DS.belongsTo('player'),
|
|
1042
|
+
date: attr('date')
|
|
1043
|
+
});
|
|
1044
|
+
```
|
|
1045
|
+
|
|
1046
|
+
@class DateTransform
|
|
1047
|
+
@extends DS.Transform
|
|
1048
|
+
@namespace DS
|
|
1049
|
+
*/
|
|
394
1050
|
DS.DateTransform = DS.Transform.extend({
|
|
395
1051
|
|
|
396
1052
|
deserialize: function(serialized) {
|
|
@@ -446,7 +1102,27 @@ DS.DateTransform = DS.Transform.extend({
|
|
|
446
1102
|
|
|
447
1103
|
(function() {
|
|
448
1104
|
var empty = Ember.isEmpty;
|
|
1105
|
+
/**
|
|
1106
|
+
The `DS.NumberTransform` class is used to serialize and deserialize
|
|
1107
|
+
numeric attributes on Ember Data record objects. This transform is
|
|
1108
|
+
used when `number` is passed as the type parameter to the
|
|
1109
|
+
[DS.attr](../../data#method_attr) function.
|
|
1110
|
+
|
|
1111
|
+
Usage
|
|
1112
|
+
|
|
1113
|
+
```javascript
|
|
1114
|
+
var attr = DS.attr;
|
|
1115
|
+
App.Score = DS.Model.extend({
|
|
1116
|
+
value: attr('number'),
|
|
1117
|
+
player: DS.belongsTo('player'),
|
|
1118
|
+
date: attr('date')
|
|
1119
|
+
});
|
|
1120
|
+
```
|
|
449
1121
|
|
|
1122
|
+
@class NumberTransform
|
|
1123
|
+
@extends DS.Transform
|
|
1124
|
+
@namespace DS
|
|
1125
|
+
*/
|
|
450
1126
|
DS.NumberTransform = DS.Transform.extend({
|
|
451
1127
|
|
|
452
1128
|
deserialize: function(serialized) {
|
|
@@ -457,6 +1133,7 @@ DS.NumberTransform = DS.Transform.extend({
|
|
|
457
1133
|
return empty(deserialized) ? null : Number(deserialized);
|
|
458
1134
|
}
|
|
459
1135
|
});
|
|
1136
|
+
|
|
460
1137
|
})();
|
|
461
1138
|
|
|
462
1139
|
|
|
@@ -464,6 +1141,27 @@ DS.NumberTransform = DS.Transform.extend({
|
|
|
464
1141
|
(function() {
|
|
465
1142
|
var none = Ember.isNone;
|
|
466
1143
|
|
|
1144
|
+
/**
|
|
1145
|
+
The `DS.StringTransform` class is used to serialize and deserialize
|
|
1146
|
+
string attributes on Ember Data record objects. This transform is
|
|
1147
|
+
used when `string` is passed as the type parameter to the
|
|
1148
|
+
[DS.attr](../../data#method_attr) function.
|
|
1149
|
+
|
|
1150
|
+
Usage
|
|
1151
|
+
|
|
1152
|
+
```javascript
|
|
1153
|
+
var attr = DS.attr;
|
|
1154
|
+
App.User = DS.Model.extend({
|
|
1155
|
+
isAdmin: attr('boolean'),
|
|
1156
|
+
name: attr('string'),
|
|
1157
|
+
email: attr('string')
|
|
1158
|
+
});
|
|
1159
|
+
```
|
|
1160
|
+
|
|
1161
|
+
@class StringTransform
|
|
1162
|
+
@extends DS.Transform
|
|
1163
|
+
@namespace DS
|
|
1164
|
+
*/
|
|
467
1165
|
DS.StringTransform = DS.Transform.extend({
|
|
468
1166
|
|
|
469
1167
|
deserialize: function(serialized) {
|
|
@@ -541,6 +1239,7 @@ Ember.onLoad('Ember.Application', function(Application) {
|
|
|
541
1239
|
|
|
542
1240
|
Application.initializer({
|
|
543
1241
|
name: "transforms",
|
|
1242
|
+
before: "store",
|
|
544
1243
|
|
|
545
1244
|
initialize: function(container, application) {
|
|
546
1245
|
application.register('transform:boolean', DS.BooleanTransform);
|
|
@@ -552,6 +1251,7 @@ Ember.onLoad('Ember.Application', function(Application) {
|
|
|
552
1251
|
|
|
553
1252
|
Application.initializer({
|
|
554
1253
|
name: "dataAdapter",
|
|
1254
|
+
before: "store",
|
|
555
1255
|
|
|
556
1256
|
initialize: function(container, application) {
|
|
557
1257
|
application.register('dataAdapter:main', DS.DebugAdapter);
|
|
@@ -560,6 +1260,7 @@ Ember.onLoad('Ember.Application', function(Application) {
|
|
|
560
1260
|
|
|
561
1261
|
Application.initializer({
|
|
562
1262
|
name: "injectStore",
|
|
1263
|
+
before: "store",
|
|
563
1264
|
|
|
564
1265
|
initialize: function(container, application) {
|
|
565
1266
|
application.inject('controller', 'store', 'store:main');
|
|
@@ -712,9 +1413,10 @@ DS.RecordArray = Ember.ArrayProxy.extend(Ember.Evented, {
|
|
|
712
1413
|
},
|
|
713
1414
|
|
|
714
1415
|
save: function() {
|
|
715
|
-
var
|
|
1416
|
+
var promiseLabel = "DS: RecordArray#save " + get(this, 'type');
|
|
1417
|
+
var promise = Ember.RSVP.all(this.invoke("save"), promiseLabel).then(function(array) {
|
|
716
1418
|
return Ember.A(array);
|
|
717
|
-
});
|
|
1419
|
+
}, null, "DS: RecordArray#save apply Ember.NativeArray");
|
|
718
1420
|
|
|
719
1421
|
return DS.PromiseArray.create({ promise: promise });
|
|
720
1422
|
}
|
|
@@ -844,6 +1546,14 @@ DS.ManyArray = DS.RecordArray.extend({
|
|
|
844
1546
|
this._changesToSync = Ember.OrderedSet.create();
|
|
845
1547
|
},
|
|
846
1548
|
|
|
1549
|
+
/**
|
|
1550
|
+
The property name of the relationship
|
|
1551
|
+
|
|
1552
|
+
@property {String}
|
|
1553
|
+
@private
|
|
1554
|
+
*/
|
|
1555
|
+
name: null,
|
|
1556
|
+
|
|
847
1557
|
/**
|
|
848
1558
|
The record to which this relationship belongs.
|
|
849
1559
|
|
|
@@ -864,6 +1574,15 @@ DS.ManyArray = DS.RecordArray.extend({
|
|
|
864
1574
|
|
|
865
1575
|
isLoaded: false,
|
|
866
1576
|
|
|
1577
|
+
/**
|
|
1578
|
+
Used for async `hasMany` arrays
|
|
1579
|
+
to keep track of when they will resolve.
|
|
1580
|
+
|
|
1581
|
+
@property {Ember.RSVP.Promise}
|
|
1582
|
+
@private
|
|
1583
|
+
*/
|
|
1584
|
+
promise: null,
|
|
1585
|
+
|
|
867
1586
|
loadingRecordsCount: function(count) {
|
|
868
1587
|
this.loadingRecordsCount = count;
|
|
869
1588
|
},
|
|
@@ -880,7 +1599,7 @@ DS.ManyArray = DS.RecordArray.extend({
|
|
|
880
1599
|
var records = get(this, 'content'),
|
|
881
1600
|
store = get(this, 'store'),
|
|
882
1601
|
owner = get(this, 'owner'),
|
|
883
|
-
resolver = Ember.RSVP.defer();
|
|
1602
|
+
resolver = Ember.RSVP.defer("DS: ManyArray#fetch " + get(this, 'type'));
|
|
884
1603
|
|
|
885
1604
|
var unloadedRecords = records.filterProperty('isEmpty', true);
|
|
886
1605
|
store.fetchMany(unloadedRecords, owner, resolver);
|
|
@@ -1000,160 +1719,6 @@ DS.ManyArray = DS.RecordArray.extend({
|
|
|
1000
1719
|
|
|
1001
1720
|
|
|
1002
1721
|
|
|
1003
|
-
(function() {
|
|
1004
|
-
/**
|
|
1005
|
-
@module ember-data
|
|
1006
|
-
*/
|
|
1007
|
-
|
|
1008
|
-
var get = Ember.get;
|
|
1009
|
-
var forEach = Ember.ArrayPolyfills.forEach;
|
|
1010
|
-
|
|
1011
|
-
var resolveMapConflict = function(oldValue, newValue) {
|
|
1012
|
-
return oldValue;
|
|
1013
|
-
};
|
|
1014
|
-
|
|
1015
|
-
var transformMapKey = function(key, value) {
|
|
1016
|
-
return key;
|
|
1017
|
-
};
|
|
1018
|
-
|
|
1019
|
-
var transformMapValue = function(key, value) {
|
|
1020
|
-
return value;
|
|
1021
|
-
};
|
|
1022
|
-
|
|
1023
|
-
/**
|
|
1024
|
-
The Mappable mixin is designed for classes that would like to
|
|
1025
|
-
behave as a map for configuration purposes.
|
|
1026
|
-
|
|
1027
|
-
For example, the DS.Adapter class can behave like a map, with
|
|
1028
|
-
more semantic API, via the `map` API:
|
|
1029
|
-
|
|
1030
|
-
DS.Adapter.map('App.Person', { firstName: { key: 'FIRST' } });
|
|
1031
|
-
|
|
1032
|
-
Class configuration via a map-like API has a few common requirements
|
|
1033
|
-
that differentiate it from the standard Ember.Map implementation.
|
|
1034
|
-
|
|
1035
|
-
First, values often are provided as strings that should be normalized
|
|
1036
|
-
into classes the first time the configuration options are used.
|
|
1037
|
-
|
|
1038
|
-
Second, the values configured on parent classes should also be taken
|
|
1039
|
-
into account.
|
|
1040
|
-
|
|
1041
|
-
Finally, setting the value of a key sometimes should merge with the
|
|
1042
|
-
previous value, rather than replacing it.
|
|
1043
|
-
|
|
1044
|
-
This mixin provides a instance method, `createInstanceMapFor`, that
|
|
1045
|
-
will reify all of the configuration options set on an instance's
|
|
1046
|
-
constructor and provide it for the instance to use.
|
|
1047
|
-
|
|
1048
|
-
Classes can implement certain hooks that allow them to customize
|
|
1049
|
-
the requirements listed above:
|
|
1050
|
-
|
|
1051
|
-
* `resolveMapConflict` - called when a value is set for an existing
|
|
1052
|
-
value
|
|
1053
|
-
* `transformMapKey` - allows a key name (for example, a global path
|
|
1054
|
-
to a class) to be normalized
|
|
1055
|
-
* `transformMapValue` - allows a value (for example, a class that
|
|
1056
|
-
should be instantiated) to be normalized
|
|
1057
|
-
|
|
1058
|
-
Classes that implement this mixin should also implement a class
|
|
1059
|
-
method built using the `generateMapFunctionFor` method:
|
|
1060
|
-
|
|
1061
|
-
DS.Adapter.reopenClass({
|
|
1062
|
-
map: DS.Mappable.generateMapFunctionFor('attributes', function(key, newValue, map) {
|
|
1063
|
-
var existingValue = map.get(key);
|
|
1064
|
-
|
|
1065
|
-
for (var prop in newValue) {
|
|
1066
|
-
if (!newValue.hasOwnProperty(prop)) { continue; }
|
|
1067
|
-
existingValue[prop] = newValue[prop];
|
|
1068
|
-
}
|
|
1069
|
-
})
|
|
1070
|
-
});
|
|
1071
|
-
|
|
1072
|
-
The function passed to `generateMapFunctionFor` is invoked every time a
|
|
1073
|
-
new value is added to the map.
|
|
1074
|
-
|
|
1075
|
-
@class _Mappable
|
|
1076
|
-
@private
|
|
1077
|
-
@namespace DS
|
|
1078
|
-
**/
|
|
1079
|
-
DS._Mappable = Ember.Mixin.create({
|
|
1080
|
-
createInstanceMapFor: function(mapName) {
|
|
1081
|
-
var instanceMeta = getMappableMeta(this);
|
|
1082
|
-
|
|
1083
|
-
instanceMeta.values = instanceMeta.values || {};
|
|
1084
|
-
|
|
1085
|
-
if (instanceMeta.values[mapName]) { return instanceMeta.values[mapName]; }
|
|
1086
|
-
|
|
1087
|
-
var instanceMap = instanceMeta.values[mapName] = new Ember.Map();
|
|
1088
|
-
|
|
1089
|
-
var klass = this.constructor;
|
|
1090
|
-
|
|
1091
|
-
while (klass && klass !== DS.Store) {
|
|
1092
|
-
this._copyMap(mapName, klass, instanceMap);
|
|
1093
|
-
klass = klass.superclass;
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
instanceMeta.values[mapName] = instanceMap;
|
|
1097
|
-
return instanceMap;
|
|
1098
|
-
},
|
|
1099
|
-
|
|
1100
|
-
_copyMap: function(mapName, klass, instanceMap) {
|
|
1101
|
-
var classMeta = getMappableMeta(klass);
|
|
1102
|
-
|
|
1103
|
-
var classMap = classMeta[mapName];
|
|
1104
|
-
if (classMap) {
|
|
1105
|
-
forEach.call(classMap, eachMap, this);
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
function eachMap(key, value) {
|
|
1109
|
-
var transformedKey = (klass.transformMapKey || transformMapKey)(key, value);
|
|
1110
|
-
var transformedValue = (klass.transformMapValue || transformMapValue)(key, value);
|
|
1111
|
-
|
|
1112
|
-
var oldValue = instanceMap.get(transformedKey);
|
|
1113
|
-
var newValue = transformedValue;
|
|
1114
|
-
|
|
1115
|
-
if (oldValue) {
|
|
1116
|
-
newValue = (this.constructor.resolveMapConflict || resolveMapConflict)(oldValue, newValue);
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
instanceMap.set(transformedKey, newValue);
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
});
|
|
1124
|
-
|
|
1125
|
-
DS._Mappable.generateMapFunctionFor = function(mapName, transform) {
|
|
1126
|
-
return function(key, value) {
|
|
1127
|
-
var meta = getMappableMeta(this);
|
|
1128
|
-
|
|
1129
|
-
var map = meta[mapName] || Ember.MapWithDefault.create({
|
|
1130
|
-
defaultValue: function() { return {}; }
|
|
1131
|
-
});
|
|
1132
|
-
|
|
1133
|
-
transform.call(this, key, value, map);
|
|
1134
|
-
|
|
1135
|
-
meta[mapName] = map;
|
|
1136
|
-
};
|
|
1137
|
-
};
|
|
1138
|
-
|
|
1139
|
-
function getMappableMeta(obj) {
|
|
1140
|
-
var meta = Ember.meta(obj, true),
|
|
1141
|
-
keyName = 'DS.Mappable',
|
|
1142
|
-
value = meta[keyName];
|
|
1143
|
-
|
|
1144
|
-
if (!value) { meta[keyName] = {}; }
|
|
1145
|
-
|
|
1146
|
-
if (!meta.hasOwnProperty(keyName)) {
|
|
1147
|
-
meta[keyName] = Ember.create(meta[keyName]);
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
|
-
return meta[keyName];
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
})();
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
1722
|
(function() {
|
|
1158
1723
|
/*globals Ember*/
|
|
1159
1724
|
/*jshint eqnull:true*/
|
|
@@ -1168,6 +1733,7 @@ var forEach = Ember.EnumerableUtils.forEach;
|
|
|
1168
1733
|
var indexOf = Ember.EnumerableUtils.indexOf;
|
|
1169
1734
|
var map = Ember.EnumerableUtils.map;
|
|
1170
1735
|
var resolve = Ember.RSVP.resolve;
|
|
1736
|
+
var copy = Ember.copy;
|
|
1171
1737
|
|
|
1172
1738
|
// Implementors Note:
|
|
1173
1739
|
//
|
|
@@ -1202,7 +1768,9 @@ var coerceId = function(id) {
|
|
|
1202
1768
|
|
|
1203
1769
|
Define your application's store like this:
|
|
1204
1770
|
|
|
1205
|
-
|
|
1771
|
+
```javascript
|
|
1772
|
+
MyApp.Store = DS.Store.extend();
|
|
1773
|
+
```
|
|
1206
1774
|
|
|
1207
1775
|
Most Ember.js applications will only have a single `DS.Store` that is
|
|
1208
1776
|
automatically created by their `Ember.Application`.
|
|
@@ -1210,12 +1778,16 @@ var coerceId = function(id) {
|
|
|
1210
1778
|
You can retrieve models from the store in several ways. To retrieve a record
|
|
1211
1779
|
for a specific id, use `DS.Model`'s `find()` method:
|
|
1212
1780
|
|
|
1213
|
-
|
|
1781
|
+
```javascript
|
|
1782
|
+
var person = App.Person.find(123);
|
|
1783
|
+
```
|
|
1214
1784
|
|
|
1215
1785
|
If your application has multiple `DS.Store` instances (an unusual case), you can
|
|
1216
1786
|
specify which store should be used:
|
|
1217
1787
|
|
|
1218
|
-
|
|
1788
|
+
```javascript
|
|
1789
|
+
var person = store.find(App.Person, 123);
|
|
1790
|
+
```
|
|
1219
1791
|
|
|
1220
1792
|
In general, you should retrieve models using the methods on `DS.Model`; you should
|
|
1221
1793
|
rarely need to interact with the store directly.
|
|
@@ -1223,9 +1795,11 @@ var coerceId = function(id) {
|
|
|
1223
1795
|
By default, the store will talk to your backend using a standard REST mechanism.
|
|
1224
1796
|
You can customize how the store talks to your backend by specifying a custom adapter:
|
|
1225
1797
|
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1798
|
+
```javascript
|
|
1799
|
+
MyApp.store = DS.Store.create({
|
|
1800
|
+
adapter: 'MyApp.CustomAdapter'
|
|
1801
|
+
});
|
|
1802
|
+
```
|
|
1229
1803
|
|
|
1230
1804
|
You can learn more about writing a custom adapter by reading the `DS.Adapter`
|
|
1231
1805
|
documentation.
|
|
@@ -1233,9 +1807,8 @@ var coerceId = function(id) {
|
|
|
1233
1807
|
@class Store
|
|
1234
1808
|
@namespace DS
|
|
1235
1809
|
@extends Ember.Object
|
|
1236
|
-
@uses DS._Mappable
|
|
1237
1810
|
*/
|
|
1238
|
-
DS.Store = Ember.Object.extend(
|
|
1811
|
+
DS.Store = Ember.Object.extend({
|
|
1239
1812
|
|
|
1240
1813
|
/**
|
|
1241
1814
|
@method init
|
|
@@ -1301,7 +1874,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1301
1874
|
@private
|
|
1302
1875
|
@returns DS.Adapter
|
|
1303
1876
|
*/
|
|
1304
|
-
defaultAdapter: Ember.computed(function() {
|
|
1877
|
+
defaultAdapter: Ember.computed('adapter', function() {
|
|
1305
1878
|
var adapter = get(this, 'adapter');
|
|
1306
1879
|
|
|
1307
1880
|
|
|
@@ -1314,7 +1887,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1314
1887
|
}
|
|
1315
1888
|
|
|
1316
1889
|
return adapter;
|
|
1317
|
-
})
|
|
1890
|
+
}),
|
|
1318
1891
|
|
|
1319
1892
|
// .....................
|
|
1320
1893
|
// . CREATE NEW RECORD .
|
|
@@ -1341,7 +1914,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1341
1914
|
createRecord: function(type, properties) {
|
|
1342
1915
|
type = this.modelFor(type);
|
|
1343
1916
|
|
|
1344
|
-
properties = properties || {};
|
|
1917
|
+
properties = copy(properties) || {};
|
|
1345
1918
|
|
|
1346
1919
|
// If the passed properties do not include a primary key,
|
|
1347
1920
|
// give the adapter an opportunity to generate one. Typically,
|
|
@@ -1421,7 +1994,9 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1421
1994
|
|
|
1422
1995
|
To find a record by ID, pass the `id` as the second parameter:
|
|
1423
1996
|
|
|
1424
|
-
|
|
1997
|
+
```javascript
|
|
1998
|
+
store.find('person', 1);
|
|
1999
|
+
```
|
|
1425
2000
|
|
|
1426
2001
|
The `find` method will always return a **promise** that will be resolved
|
|
1427
2002
|
with the record. If the record was already in the store, the promise will
|
|
@@ -1435,7 +2010,9 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1435
2010
|
|
|
1436
2011
|
To find all records for a type, call `find` with no additional parameters:
|
|
1437
2012
|
|
|
1438
|
-
|
|
2013
|
+
```javascript
|
|
2014
|
+
store.find('person');
|
|
2015
|
+
```
|
|
1439
2016
|
|
|
1440
2017
|
This will ask the adapter's `findAll` method to find the records for the
|
|
1441
2018
|
given type, and return a promise that will be resolved once the server
|
|
@@ -1446,7 +2023,9 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1446
2023
|
To find a record by a query, call `find` with a hash as the second
|
|
1447
2024
|
parameter:
|
|
1448
2025
|
|
|
1449
|
-
|
|
2026
|
+
```javascript
|
|
2027
|
+
store.find(App.Person, { page: 1 });
|
|
2028
|
+
```
|
|
1450
2029
|
|
|
1451
2030
|
This will ask the adapter's `findQuery` method to find the records for
|
|
1452
2031
|
the query, and return a promise that will be resolved once the server
|
|
@@ -1482,7 +2061,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1482
2061
|
|
|
1483
2062
|
var record = this.recordForId(type, id);
|
|
1484
2063
|
|
|
1485
|
-
var promise = this.fetchRecord(record) || resolve(record);
|
|
2064
|
+
var promise = this.fetchRecord(record) || resolve(record, "DS: Store#findById " + type + " with id: " + id);
|
|
1486
2065
|
return promiseObject(promise);
|
|
1487
2066
|
},
|
|
1488
2067
|
|
|
@@ -1490,6 +2069,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1490
2069
|
This method makes a series of requests to the adapter's `find` method
|
|
1491
2070
|
and returns a promise that resolves once they are all loaded.
|
|
1492
2071
|
|
|
2072
|
+
@private
|
|
1493
2073
|
@method findByIds
|
|
1494
2074
|
@param {String} type
|
|
1495
2075
|
@param {Array} ids
|
|
@@ -1497,12 +2077,10 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1497
2077
|
*/
|
|
1498
2078
|
findByIds: function(type, ids) {
|
|
1499
2079
|
var store = this;
|
|
1500
|
-
|
|
2080
|
+
var promiseLabel = "DS: Store#findByIds " + type;
|
|
1501
2081
|
return promiseArray(Ember.RSVP.all(map(ids, function(id) {
|
|
1502
2082
|
return store.findById(type, id);
|
|
1503
|
-
})).then(
|
|
1504
|
-
return Ember.A(array);
|
|
1505
|
-
}));
|
|
2083
|
+
})).then(Ember.A, null, "DS: Store#findByIds of " + type + " complete"));
|
|
1506
2084
|
},
|
|
1507
2085
|
|
|
1508
2086
|
/**
|
|
@@ -1522,7 +2100,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1522
2100
|
|
|
1523
2101
|
var type = record.constructor,
|
|
1524
2102
|
id = get(record, 'id'),
|
|
1525
|
-
resolver = Ember.RSVP.defer();
|
|
2103
|
+
resolver = Ember.RSVP.defer("DS: Store#fetchRecord " + record );
|
|
1526
2104
|
|
|
1527
2105
|
record.loadingData(resolver.promise);
|
|
1528
2106
|
|
|
@@ -1530,7 +2108,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1530
2108
|
|
|
1531
2109
|
|
|
1532
2110
|
|
|
1533
|
-
_find(adapter, this, type, id
|
|
2111
|
+
resolver.resolve(_find(adapter, this, type, id));
|
|
1534
2112
|
|
|
1535
2113
|
return resolver.promise;
|
|
1536
2114
|
},
|
|
@@ -1550,8 +2128,6 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1550
2128
|
@param id
|
|
1551
2129
|
*/
|
|
1552
2130
|
getById: function(type, id) {
|
|
1553
|
-
type = this.modelFor(type);
|
|
1554
|
-
|
|
1555
2131
|
if (this.hasRecordForId(type, id)) {
|
|
1556
2132
|
return this.recordForId(type, id);
|
|
1557
2133
|
} else {
|
|
@@ -1572,7 +2148,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1572
2148
|
@param {DS.Model} record
|
|
1573
2149
|
@param {Resolver} resolver
|
|
1574
2150
|
*/
|
|
1575
|
-
reloadRecord: function(record
|
|
2151
|
+
reloadRecord: function(record) {
|
|
1576
2152
|
var type = record.constructor,
|
|
1577
2153
|
adapter = this.adapterFor(type),
|
|
1578
2154
|
id = get(record, 'id');
|
|
@@ -1580,7 +2156,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1580
2156
|
|
|
1581
2157
|
|
|
1582
2158
|
|
|
1583
|
-
return _find(adapter, this, type, id
|
|
2159
|
+
return _find(adapter, this, type, id);
|
|
1584
2160
|
},
|
|
1585
2161
|
|
|
1586
2162
|
/**
|
|
@@ -1618,7 +2194,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1618
2194
|
|
|
1619
2195
|
|
|
1620
2196
|
|
|
1621
|
-
_findMany(adapter, this, type, ids, owner
|
|
2197
|
+
resolver.resolve(_findMany(adapter, this, type, ids, owner));
|
|
1622
2198
|
}, this);
|
|
1623
2199
|
},
|
|
1624
2200
|
|
|
@@ -1632,7 +2208,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1632
2208
|
*/
|
|
1633
2209
|
hasRecordForId: function(type, id) {
|
|
1634
2210
|
id = coerceId(id);
|
|
1635
|
-
|
|
2211
|
+
type = this.modelFor(type);
|
|
1636
2212
|
return !!this.typeMapFor(type).idToRecord[id];
|
|
1637
2213
|
},
|
|
1638
2214
|
|
|
@@ -1722,7 +2298,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1722
2298
|
|
|
1723
2299
|
|
|
1724
2300
|
var records = this.recordArrayManager.createManyArray(relationship.type, Ember.A([]));
|
|
1725
|
-
_findHasMany(adapter, this, owner, link, relationship
|
|
2301
|
+
resolver.resolve(_findHasMany(adapter, this, owner, link, relationship));
|
|
1726
2302
|
return records;
|
|
1727
2303
|
},
|
|
1728
2304
|
|
|
@@ -1731,7 +2307,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1731
2307
|
|
|
1732
2308
|
|
|
1733
2309
|
|
|
1734
|
-
_findBelongsTo(adapter, this, owner, link, relationship
|
|
2310
|
+
resolver.resolve(_findBelongsTo(adapter, this, owner, link, relationship));
|
|
1735
2311
|
},
|
|
1736
2312
|
|
|
1737
2313
|
/**
|
|
@@ -1762,11 +2338,12 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1762
2338
|
});
|
|
1763
2339
|
|
|
1764
2340
|
var adapter = this.adapterFor(type),
|
|
1765
|
-
|
|
2341
|
+
promiseLabel = "DS: Store#findQuery " + type,
|
|
2342
|
+
resolver = Ember.RSVP.defer(promiseLabel);
|
|
1766
2343
|
|
|
1767
2344
|
|
|
1768
2345
|
|
|
1769
|
-
_findQuery(adapter, this, type, query, array
|
|
2346
|
+
resolver.resolve(_findQuery(adapter, this, type, query, array));
|
|
1770
2347
|
|
|
1771
2348
|
return promiseArray(resolver.promise);
|
|
1772
2349
|
},
|
|
@@ -1797,13 +2374,13 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1797
2374
|
fetchAll: function(type, array) {
|
|
1798
2375
|
var adapter = this.adapterFor(type),
|
|
1799
2376
|
sinceToken = this.typeMapFor(type).metadata.since,
|
|
1800
|
-
resolver = Ember.RSVP.defer();
|
|
2377
|
+
resolver = Ember.RSVP.defer("DS: Store#findAll " + type);
|
|
1801
2378
|
|
|
1802
2379
|
set(array, 'isUpdating', true);
|
|
1803
2380
|
|
|
1804
2381
|
|
|
1805
2382
|
|
|
1806
|
-
_findAll(adapter, this, type, sinceToken
|
|
2383
|
+
resolver.resolve(_findAll(adapter, this, type, sinceToken));
|
|
1807
2384
|
|
|
1808
2385
|
return promiseArray(resolver.promise);
|
|
1809
2386
|
},
|
|
@@ -1868,6 +2445,8 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1868
2445
|
while(record = records.pop()) {
|
|
1869
2446
|
record.unloadRecord();
|
|
1870
2447
|
}
|
|
2448
|
+
|
|
2449
|
+
typeMap.findAllCache = null;
|
|
1871
2450
|
},
|
|
1872
2451
|
|
|
1873
2452
|
/**
|
|
@@ -1886,8 +2465,13 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1886
2465
|
filter function will be invoked again to determine whether it should
|
|
1887
2466
|
still be in the array.
|
|
1888
2467
|
|
|
2468
|
+
Optionally you can pass a query which will be triggered at first. The
|
|
2469
|
+
results returned by the server could then appear in the filter if they
|
|
2470
|
+
match the filter function.
|
|
2471
|
+
|
|
1889
2472
|
@method filter
|
|
1890
2473
|
@param {Class} type
|
|
2474
|
+
@param {Object} query optional query
|
|
1891
2475
|
@param {Function} filter
|
|
1892
2476
|
@return {DS.FilteredRecordArray}
|
|
1893
2477
|
*/
|
|
@@ -1914,7 +2498,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1914
2498
|
this.recordArrayManager.registerFilteredRecordArray(array, type, filter);
|
|
1915
2499
|
|
|
1916
2500
|
if (promise) {
|
|
1917
|
-
return promise.then(function() { return array; });
|
|
2501
|
+
return promise.then(function() { return array; }, null, "DS: Store#filter of " + type);
|
|
1918
2502
|
} else {
|
|
1919
2503
|
return array;
|
|
1920
2504
|
}
|
|
@@ -1926,7 +2510,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1926
2510
|
will result in a request or that it will be a cache hit.
|
|
1927
2511
|
|
|
1928
2512
|
@method recordIsLoaded
|
|
1929
|
-
@param
|
|
2513
|
+
@param type
|
|
1930
2514
|
@param {string} id
|
|
1931
2515
|
@return {boolean}
|
|
1932
2516
|
*/
|
|
@@ -1955,8 +2539,8 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1955
2539
|
If the adapter updates attributes or acknowledges creation
|
|
1956
2540
|
or deletion, the record will notify the store to update its
|
|
1957
2541
|
membership in any filters.
|
|
1958
|
-
|
|
1959
2542
|
To avoid thrashing, this method is invoked only once per
|
|
2543
|
+
|
|
1960
2544
|
run loop per record.
|
|
1961
2545
|
|
|
1962
2546
|
@method dataWasUpdated
|
|
@@ -1966,20 +2550,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
1966
2550
|
@param {DS.Model} record
|
|
1967
2551
|
*/
|
|
1968
2552
|
dataWasUpdated: function(type, record) {
|
|
1969
|
-
|
|
1970
|
-
// it is possible that a record might be deleted after its data
|
|
1971
|
-
// has been modified and this method was scheduled to be called.
|
|
1972
|
-
//
|
|
1973
|
-
// If that's the case, the record would have already been removed
|
|
1974
|
-
// from all record arrays; calling updateRecordArrays would just
|
|
1975
|
-
// add it back. If the record is deleted, just bail. It shouldn't
|
|
1976
|
-
// give us any more trouble after this.
|
|
1977
|
-
|
|
1978
|
-
if (get(record, 'isDeleted')) { return; }
|
|
1979
|
-
|
|
1980
|
-
if (get(record, 'isLoaded')) {
|
|
1981
|
-
this.recordArrayManager.recordDidChange(record);
|
|
1982
|
-
}
|
|
2553
|
+
this.recordArrayManager.recordDidChange(record);
|
|
1983
2554
|
},
|
|
1984
2555
|
|
|
1985
2556
|
// ..............
|
|
@@ -2027,7 +2598,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
2027
2598
|
operation = 'updateRecord';
|
|
2028
2599
|
}
|
|
2029
2600
|
|
|
2030
|
-
_commit(adapter, this, operation, record
|
|
2601
|
+
resolver.resolve(_commit(adapter, this, operation, record));
|
|
2031
2602
|
}, this);
|
|
2032
2603
|
},
|
|
2033
2604
|
|
|
@@ -2167,7 +2738,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
2167
2738
|
|
|
2168
2739
|
if (typeof key === 'string') {
|
|
2169
2740
|
factory = this.container.lookupFactory('model:' + key);
|
|
2170
|
-
|
|
2741
|
+
if (!factory) { throw new Ember.Error("No model was found for '" + key + "'"); }
|
|
2171
2742
|
factory.typeKey = key;
|
|
2172
2743
|
} else {
|
|
2173
2744
|
// A factory already supplied.
|
|
@@ -2283,13 +2854,20 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
|
2283
2854
|
store.pushPayload('post', pushData);
|
|
2284
2855
|
```
|
|
2285
2856
|
|
|
2286
|
-
@method
|
|
2857
|
+
@method pushPayload
|
|
2287
2858
|
@param {String} type
|
|
2288
2859
|
@param {Object} payload
|
|
2289
2860
|
*/
|
|
2290
2861
|
|
|
2291
2862
|
pushPayload: function (type, payload) {
|
|
2292
|
-
var serializer
|
|
2863
|
+
var serializer;
|
|
2864
|
+
if (!payload) {
|
|
2865
|
+
payload = type;
|
|
2866
|
+
serializer = defaultSerializer(this.container);
|
|
2867
|
+
|
|
2868
|
+
} else {
|
|
2869
|
+
serializer = this.serializerFor(type);
|
|
2870
|
+
}
|
|
2293
2871
|
serializer.pushPayload(this, payload);
|
|
2294
2872
|
},
|
|
2295
2873
|
|
|
@@ -2583,6 +3161,11 @@ function serializerFor(container, type, defaultSerializer) {
|
|
|
2583
3161
|
container.lookup('serializer:_default');
|
|
2584
3162
|
}
|
|
2585
3163
|
|
|
3164
|
+
function defaultSerializer(container) {
|
|
3165
|
+
return container.lookup('serializer:application') ||
|
|
3166
|
+
container.lookup('serializer:_default');
|
|
3167
|
+
}
|
|
3168
|
+
|
|
2586
3169
|
function serializerForAdapter(adapter, type) {
|
|
2587
3170
|
var serializer = adapter.serializer,
|
|
2588
3171
|
defaultSerializer = adapter.defaultSerializer,
|
|
@@ -2601,11 +3184,11 @@ function serializerForAdapter(adapter, type) {
|
|
|
2601
3184
|
return serializer;
|
|
2602
3185
|
}
|
|
2603
3186
|
|
|
2604
|
-
function _find(adapter, store, type, id
|
|
3187
|
+
function _find(adapter, store, type, id) {
|
|
2605
3188
|
var promise = adapter.find(store, type, id),
|
|
2606
3189
|
serializer = serializerForAdapter(adapter, type);
|
|
2607
3190
|
|
|
2608
|
-
return resolve(promise).then(function(payload) {
|
|
3191
|
+
return resolve(promise, "DS: Handle Adapter#find of " + type + " with id: " + id).then(function(payload) {
|
|
2609
3192
|
|
|
2610
3193
|
payload = serializer.extract(store, type, payload, id, 'find');
|
|
2611
3194
|
|
|
@@ -2614,75 +3197,75 @@ function _find(adapter, store, type, id, resolver) {
|
|
|
2614
3197
|
var record = store.getById(type, id);
|
|
2615
3198
|
record.notFound();
|
|
2616
3199
|
throw error;
|
|
2617
|
-
}
|
|
3200
|
+
}, "DS: Extract payload of '" + type + "'");
|
|
2618
3201
|
}
|
|
2619
3202
|
|
|
2620
|
-
function _findMany(adapter, store, type, ids, owner
|
|
3203
|
+
function _findMany(adapter, store, type, ids, owner) {
|
|
2621
3204
|
var promise = adapter.findMany(store, type, ids, owner),
|
|
2622
3205
|
serializer = serializerForAdapter(adapter, type);
|
|
2623
3206
|
|
|
2624
|
-
return resolve(promise).then(function(payload) {
|
|
3207
|
+
return resolve(promise, "DS: Handle Adapter#findMany of " + type).then(function(payload) {
|
|
2625
3208
|
payload = serializer.extract(store, type, payload, null, 'findMany');
|
|
2626
3209
|
|
|
2627
3210
|
|
|
2628
3211
|
store.pushMany(type, payload);
|
|
2629
|
-
}
|
|
3212
|
+
}, null, "DS: Extract payload of " + type);
|
|
2630
3213
|
}
|
|
2631
3214
|
|
|
2632
|
-
function _findHasMany(adapter, store, record, link, relationship
|
|
3215
|
+
function _findHasMany(adapter, store, record, link, relationship) {
|
|
2633
3216
|
var promise = adapter.findHasMany(store, record, link, relationship),
|
|
2634
3217
|
serializer = serializerForAdapter(adapter, relationship.type);
|
|
2635
3218
|
|
|
2636
|
-
return resolve(promise).then(function(payload) {
|
|
3219
|
+
return resolve(promise, "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type).then(function(payload) {
|
|
2637
3220
|
payload = serializer.extract(store, relationship.type, payload, null, 'findHasMany');
|
|
2638
3221
|
|
|
2639
3222
|
|
|
2640
3223
|
var records = store.pushMany(relationship.type, payload);
|
|
2641
3224
|
record.updateHasMany(relationship.key, records);
|
|
2642
|
-
}
|
|
3225
|
+
}, null, "DS: Extract payload of " + record + " : hasMany " + relationship.type);
|
|
2643
3226
|
}
|
|
2644
3227
|
|
|
2645
|
-
function _findBelongsTo(adapter, store, record, link, relationship
|
|
3228
|
+
function _findBelongsTo(adapter, store, record, link, relationship) {
|
|
2646
3229
|
var promise = adapter.findBelongsTo(store, record, link, relationship),
|
|
2647
3230
|
serializer = serializerForAdapter(adapter, relationship.type);
|
|
2648
3231
|
|
|
2649
|
-
return resolve(promise).then(function(payload) {
|
|
3232
|
+
return resolve(promise, "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type).then(function(payload) {
|
|
2650
3233
|
payload = serializer.extract(store, relationship.type, payload, null, 'findBelongsTo');
|
|
2651
3234
|
|
|
2652
3235
|
var record = store.push(relationship.type, payload);
|
|
2653
3236
|
record.updateBelongsTo(relationship.key, record);
|
|
2654
3237
|
return record;
|
|
2655
|
-
}
|
|
3238
|
+
}, null, "DS: Extract payload of " + record + " : " + relationship.type);
|
|
2656
3239
|
}
|
|
2657
3240
|
|
|
2658
|
-
function _findAll(adapter, store, type, sinceToken
|
|
3241
|
+
function _findAll(adapter, store, type, sinceToken) {
|
|
2659
3242
|
var promise = adapter.findAll(store, type, sinceToken),
|
|
2660
3243
|
serializer = serializerForAdapter(adapter, type);
|
|
2661
3244
|
|
|
2662
|
-
return resolve(promise).then(function(payload) {
|
|
3245
|
+
return resolve(promise, "DS: Handle Adapter#findAll of " + type).then(function(payload) {
|
|
2663
3246
|
payload = serializer.extract(store, type, payload, null, 'findAll');
|
|
2664
3247
|
|
|
2665
3248
|
|
|
2666
3249
|
store.pushMany(type, payload);
|
|
2667
3250
|
store.didUpdateAll(type);
|
|
2668
3251
|
return store.all(type);
|
|
2669
|
-
}
|
|
3252
|
+
}, null, "DS: Extract payload of findAll " + type);
|
|
2670
3253
|
}
|
|
2671
3254
|
|
|
2672
|
-
function _findQuery(adapter, store, type, query, recordArray
|
|
3255
|
+
function _findQuery(adapter, store, type, query, recordArray) {
|
|
2673
3256
|
var promise = adapter.findQuery(store, type, query, recordArray),
|
|
2674
3257
|
serializer = serializerForAdapter(adapter, type);
|
|
2675
3258
|
|
|
2676
|
-
return resolve(promise).then(function(payload) {
|
|
3259
|
+
return resolve(promise, "DS: Handle Adapter#findQuery of " + type).then(function(payload) {
|
|
2677
3260
|
payload = serializer.extract(store, type, payload, null, 'findAll');
|
|
2678
3261
|
|
|
2679
3262
|
|
|
2680
3263
|
recordArray.load(payload);
|
|
2681
3264
|
return recordArray;
|
|
2682
|
-
}
|
|
3265
|
+
}, null, "DS: Extract payload of findQuery " + type);
|
|
2683
3266
|
}
|
|
2684
3267
|
|
|
2685
|
-
function _commit(adapter, store, operation, record
|
|
3268
|
+
function _commit(adapter, store, operation, record) {
|
|
2686
3269
|
var type = record.constructor,
|
|
2687
3270
|
promise = adapter[operation](store, type, record),
|
|
2688
3271
|
serializer = serializerForAdapter(adapter, type);
|
|
@@ -2700,7 +3283,7 @@ function _commit(adapter, store, operation, record, resolver) {
|
|
|
2700
3283
|
}
|
|
2701
3284
|
|
|
2702
3285
|
throw reason;
|
|
2703
|
-
}
|
|
3286
|
+
}, "DS: Extract and notify about " + operation + " completion of " + record);
|
|
2704
3287
|
}
|
|
2705
3288
|
|
|
2706
3289
|
})();
|
|
@@ -2713,95 +3296,111 @@ function _commit(adapter, store, operation, record, resolver) {
|
|
|
2713
3296
|
*/
|
|
2714
3297
|
|
|
2715
3298
|
var get = Ember.get, set = Ember.set;
|
|
2716
|
-
|
|
2717
3299
|
/*
|
|
2718
|
-
WARNING: Much of these docs are inaccurate as of bf8497.
|
|
2719
|
-
|
|
2720
3300
|
This file encapsulates the various states that a record can transition
|
|
2721
3301
|
through during its lifecycle.
|
|
3302
|
+
*/
|
|
3303
|
+
/**
|
|
3304
|
+
### State
|
|
3305
|
+
|
|
3306
|
+
Each record has a `currentState` property that explicitly tracks what
|
|
3307
|
+
state a record is in at any given time. For instance, if a record is
|
|
3308
|
+
newly created and has not yet been sent to the adapter to be saved,
|
|
3309
|
+
it would be in the `root.loaded.created.uncommitted` state. If a
|
|
3310
|
+
record has had local modifications made to it that are in the
|
|
3311
|
+
process of being saved, the record would be in the
|
|
3312
|
+
`root.loaded.updated.inFlight` state. (These state paths will be
|
|
3313
|
+
explained in more detail below.)
|
|
3314
|
+
|
|
3315
|
+
Events are sent by the record or its store to the record's
|
|
3316
|
+
`currentState` property. How the state reacts to these events is
|
|
3317
|
+
dependent on which state it is in. In some states, certain events
|
|
3318
|
+
will be invalid and will cause an exception to be raised.
|
|
3319
|
+
|
|
3320
|
+
States are hierarchical and every state is a substate of the
|
|
3321
|
+
`RootState`. For example, a record can be in the
|
|
3322
|
+
`root.deleted.uncommitted` state, then transition into the
|
|
3323
|
+
`root.deleted.inFlight` state. If a child state does not implement
|
|
3324
|
+
an event handler, the state manager will attempt to invoke the event
|
|
3325
|
+
on all parent states until the root state is reached. The state
|
|
3326
|
+
hierarchy of a record is described in terms of a path string. You
|
|
3327
|
+
can determine a record's current state by getting the state's
|
|
3328
|
+
`stateName` property:
|
|
2722
3329
|
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
The `DS.Model` states are themselves stateless. What we mean is that,
|
|
2750
|
-
though each instance of a record also has a unique instance of a
|
|
2751
|
-
`DS.StateManager`, the hierarchical states that each of *those* points
|
|
2752
|
-
to is a shared data structure. For performance reasons, instead of each
|
|
2753
|
-
record getting its own copy of the hierarchy of states, each state
|
|
2754
|
-
manager points to this global, immutable shared instance. How does a
|
|
2755
|
-
state know which record it should be acting on? We pass a reference to
|
|
2756
|
-
the current state manager as the first parameter to every method invoked
|
|
2757
|
-
on a state.
|
|
2758
|
-
|
|
2759
|
-
The state manager passed as the first parameter is where you should stash
|
|
2760
|
-
state about the record if needed; you should never store data on the state
|
|
2761
|
-
object itself. If you need access to the record being acted on, you can
|
|
2762
|
-
retrieve the state manager's `record` property. For example, if you had
|
|
2763
|
-
an event handler `myEvent`:
|
|
3330
|
+
```javascript
|
|
3331
|
+
record.get('currentState.stateName');
|
|
3332
|
+
//=> "root.created.uncommitted"
|
|
3333
|
+
```
|
|
3334
|
+
|
|
3335
|
+
The hierarchy of valid states that ship with ember data looks like
|
|
3336
|
+
this:
|
|
3337
|
+
|
|
3338
|
+
```text
|
|
3339
|
+
* root
|
|
3340
|
+
* deleted
|
|
3341
|
+
* saved
|
|
3342
|
+
* uncommitted
|
|
3343
|
+
* inFlight
|
|
3344
|
+
* empty
|
|
3345
|
+
* loaded
|
|
3346
|
+
* created
|
|
3347
|
+
* uncommitted
|
|
3348
|
+
* inFlight
|
|
3349
|
+
* saved
|
|
3350
|
+
* updated
|
|
3351
|
+
* uncommitted
|
|
3352
|
+
* inFlight
|
|
3353
|
+
* loading
|
|
3354
|
+
```
|
|
2764
3355
|
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
3356
|
+
The `DS.Model` states are themselves stateless. What we mean is
|
|
3357
|
+
that, the hierarchical states that each of *those* points to is a
|
|
3358
|
+
shared data structure. For performance reasons, instead of each
|
|
3359
|
+
record getting its own copy of the hierarchy of states, each record
|
|
3360
|
+
points to this global, immutable shared instance. How does a state
|
|
3361
|
+
know which record it should be acting on? We pass the record
|
|
3362
|
+
instance into the state's event handlers as the first argument.
|
|
2769
3363
|
|
|
2770
|
-
|
|
2771
|
-
|
|
3364
|
+
The record passed as the first parameter is where you should stash
|
|
3365
|
+
state about the record if needed; you should never store data on the state
|
|
3366
|
+
object itself.
|
|
2772
3367
|
|
|
2773
|
-
### Events
|
|
3368
|
+
### Events and Flags
|
|
2774
3369
|
|
|
2775
|
-
A state may implement zero or more events
|
|
3370
|
+
A state may implement zero or more events and flags.
|
|
2776
3371
|
|
|
2777
3372
|
#### Events
|
|
2778
3373
|
|
|
2779
3374
|
Events are named functions that are invoked when sent to a record. The
|
|
2780
|
-
|
|
2781
|
-
current state. If no method is found, it will search the current
|
|
2782
|
-
parent, and then its grandparent, and so on until reaching
|
|
2783
|
-
the hierarchy. If the root is reached without an event
|
|
2784
|
-
an exception will be raised. This can be very
|
|
2785
|
-
features.
|
|
3375
|
+
record will first look for a method with the given name on the
|
|
3376
|
+
current state. If no method is found, it will search the current
|
|
3377
|
+
state's parent, and then its grandparent, and so on until reaching
|
|
3378
|
+
the top of the hierarchy. If the root is reached without an event
|
|
3379
|
+
handler being found, an exception will be raised. This can be very
|
|
3380
|
+
helpful when debugging new features.
|
|
2786
3381
|
|
|
2787
3382
|
Here's an example implementation of a state with a `myEvent` event handler:
|
|
2788
3383
|
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
3384
|
+
```javascript
|
|
3385
|
+
aState: DS.State.create({
|
|
3386
|
+
myEvent: function(manager, param) {
|
|
3387
|
+
console.log("Received myEvent with", param);
|
|
3388
|
+
}
|
|
3389
|
+
})
|
|
3390
|
+
```
|
|
2794
3391
|
|
|
2795
3392
|
To trigger this event:
|
|
2796
3393
|
|
|
2797
|
-
|
|
2798
|
-
|
|
3394
|
+
```javascript
|
|
3395
|
+
record.send('myEvent', 'foo');
|
|
3396
|
+
//=> "Received myEvent with foo"
|
|
3397
|
+
```
|
|
2799
3398
|
|
|
2800
3399
|
Note that an optional parameter can be sent to a record's `send()` method,
|
|
2801
3400
|
which will be passed as the second parameter to the event handler.
|
|
2802
3401
|
|
|
2803
3402
|
Events should transition to a different state if appropriate. This can be
|
|
2804
|
-
done by calling the
|
|
3403
|
+
done by calling the record's `transitionTo()` method with a path to the
|
|
2805
3404
|
desired state. The state manager will attempt to resolve the state path
|
|
2806
3405
|
relative to the current state. If no state is found at that path, it will
|
|
2807
3406
|
attempt to resolve it relative to the current state's parent, and then its
|
|
@@ -2809,12 +3408,12 @@ var get = Ember.get, set = Ember.set;
|
|
|
2809
3408
|
like this:
|
|
2810
3409
|
|
|
2811
3410
|
* created
|
|
2812
|
-
*
|
|
3411
|
+
* uncommitted <-- currentState
|
|
2813
3412
|
* inFlight
|
|
2814
3413
|
* updated
|
|
2815
3414
|
* inFlight
|
|
2816
3415
|
|
|
2817
|
-
If we are currently in the `
|
|
3416
|
+
If we are currently in the `uncommitted` state, calling
|
|
2818
3417
|
`transitionTo('inFlight')` would transition to the `created.inFlight` state,
|
|
2819
3418
|
while calling `transitionTo('updated.inFlight')` would transition to
|
|
2820
3419
|
the `updated.inFlight` state.
|
|
@@ -2829,16 +3428,20 @@ var get = Ember.get, set = Ember.set;
|
|
|
2829
3428
|
state in a more user-friendly way than examining its state path. For example,
|
|
2830
3429
|
instead of doing this:
|
|
2831
3430
|
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
3431
|
+
```javascript
|
|
3432
|
+
var statePath = record.get('stateManager.currentPath');
|
|
3433
|
+
if (statePath === 'created.inFlight') {
|
|
3434
|
+
doSomething();
|
|
3435
|
+
}
|
|
3436
|
+
```
|
|
2836
3437
|
|
|
2837
3438
|
You can say:
|
|
2838
3439
|
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
3440
|
+
```javascript
|
|
3441
|
+
if (record.get('isNew') && record.get('isSaving')) {
|
|
3442
|
+
doSomething();
|
|
3443
|
+
}
|
|
3444
|
+
```
|
|
2842
3445
|
|
|
2843
3446
|
If your state does not set a value for a given flag, the value will
|
|
2844
3447
|
be inherited from its parent (or the first place in the state hierarchy
|
|
@@ -2848,23 +3451,18 @@ var get = Ember.get, set = Ember.set;
|
|
|
2848
3451
|
in addition to the area below, you will also need to declare it in the
|
|
2849
3452
|
`DS.Model` class.
|
|
2850
3453
|
|
|
2851
|
-
#### Transitions
|
|
2852
|
-
|
|
2853
|
-
Transitions are like event handlers but are called automatically upon
|
|
2854
|
-
entering or exiting a state. To implement a transition, just call a method
|
|
2855
|
-
either `enter` or `exit`:
|
|
2856
3454
|
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
3455
|
+
* [isEmpty](DS.Model.html#property_isEmpty)
|
|
3456
|
+
* [isLoading](DS.Model.html#property_isLoading)
|
|
3457
|
+
* [isLoaded](DS.Model.html#property_isLoaded)
|
|
3458
|
+
* [isDirty](DS.Model.html#property_isDirty)
|
|
3459
|
+
* [isSaving](DS.Model.html#property_isSaving)
|
|
3460
|
+
* [isDeleted](DS.Model.html#property_isDeleted)
|
|
3461
|
+
* [isNew](DS.Model.html#property_isNew)
|
|
3462
|
+
* [isValid](DS.Model.html#property_isValid)
|
|
2864
3463
|
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
the transition event on the parent will not be triggered.
|
|
3464
|
+
@namespace DS
|
|
3465
|
+
@class RootState
|
|
2868
3466
|
*/
|
|
2869
3467
|
|
|
2870
3468
|
var hasDefinedProperties = function(object) {
|
|
@@ -2967,8 +3565,8 @@ var DirtyState = {
|
|
|
2967
3565
|
record.transitionTo('inFlight');
|
|
2968
3566
|
},
|
|
2969
3567
|
|
|
2970
|
-
reloadRecord: function(record,
|
|
2971
|
-
get(record, 'store').reloadRecord(record
|
|
3568
|
+
reloadRecord: function(record, resolve) {
|
|
3569
|
+
resolve(get(record, 'store').reloadRecord(record));
|
|
2972
3570
|
},
|
|
2973
3571
|
|
|
2974
3572
|
rolledBack: function(record) {
|
|
@@ -3248,8 +3846,8 @@ var RootState = {
|
|
|
3248
3846
|
record.transitionTo('updated.inFlight');
|
|
3249
3847
|
},
|
|
3250
3848
|
|
|
3251
|
-
reloadRecord: function(record,
|
|
3252
|
-
get(record, 'store').reloadRecord(record
|
|
3849
|
+
reloadRecord: function(record, resolve) {
|
|
3850
|
+
resolve(get(record, 'store').reloadRecord(record));
|
|
3253
3851
|
},
|
|
3254
3852
|
|
|
3255
3853
|
deleteRecord: function(record) {
|
|
@@ -3266,7 +3864,11 @@ var RootState = {
|
|
|
3266
3864
|
|
|
3267
3865
|
didCommit: function(record) {
|
|
3268
3866
|
record.send('invokeLifecycleCallbacks', get(record, 'lastDirtyType'));
|
|
3269
|
-
}
|
|
3867
|
+
},
|
|
3868
|
+
|
|
3869
|
+
// loaded.saved.notFound would be triggered by a failed
|
|
3870
|
+
// `reload()` on an unchanged record
|
|
3871
|
+
notFound: Ember.K
|
|
3270
3872
|
|
|
3271
3873
|
},
|
|
3272
3874
|
|
|
@@ -3293,9 +3895,7 @@ var RootState = {
|
|
|
3293
3895
|
|
|
3294
3896
|
// TRANSITIONS
|
|
3295
3897
|
setup: function(record) {
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
store.recordArrayManager.remove(record);
|
|
3898
|
+
record.updateRecordArrays();
|
|
3299
3899
|
},
|
|
3300
3900
|
|
|
3301
3901
|
// SUBSTATES
|
|
@@ -3410,9 +4010,9 @@ DS.RootState = RootState;
|
|
|
3410
4010
|
var get = Ember.get, set = Ember.set,
|
|
3411
4011
|
merge = Ember.merge, once = Ember.run.once;
|
|
3412
4012
|
|
|
3413
|
-
var retrieveFromCurrentState = Ember.computed(function(key, value) {
|
|
4013
|
+
var retrieveFromCurrentState = Ember.computed('currentState', function(key, value) {
|
|
3414
4014
|
return get(get(this, 'currentState'), key);
|
|
3415
|
-
}).
|
|
4015
|
+
}).readOnly();
|
|
3416
4016
|
|
|
3417
4017
|
/**
|
|
3418
4018
|
|
|
@@ -3424,35 +4024,284 @@ var retrieveFromCurrentState = Ember.computed(function(key, value) {
|
|
|
3424
4024
|
@uses Ember.Evented
|
|
3425
4025
|
*/
|
|
3426
4026
|
DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
4027
|
+
/**
|
|
4028
|
+
If this property is `true` the record is in the `empty`
|
|
4029
|
+
state. Empty is the first state all records enter after they have
|
|
4030
|
+
been created. Most records created by the store will quickly
|
|
4031
|
+
transition to the `loading` state if data needs to be fetched from
|
|
4032
|
+
the server or the `created` state if the record is created on the
|
|
4033
|
+
client. A record can also enter the empty state if the adapter is
|
|
4034
|
+
unable to locate the record.
|
|
4035
|
+
|
|
4036
|
+
@property isEmpty
|
|
4037
|
+
@type {Boolean}
|
|
4038
|
+
@readOnly
|
|
4039
|
+
*/
|
|
3427
4040
|
isEmpty: retrieveFromCurrentState,
|
|
4041
|
+
/**
|
|
4042
|
+
If this property is `true` the record is in the `loading` state. A
|
|
4043
|
+
record enters this state when the store askes the adapter for its
|
|
4044
|
+
data. It remains in this state until the adapter provides the
|
|
4045
|
+
requested data.
|
|
4046
|
+
|
|
4047
|
+
@property isLoading
|
|
4048
|
+
@type {Boolean}
|
|
4049
|
+
@readOnly
|
|
4050
|
+
*/
|
|
3428
4051
|
isLoading: retrieveFromCurrentState,
|
|
4052
|
+
/**
|
|
4053
|
+
If this property is `true` the record is in the `loaded` state. A
|
|
4054
|
+
record enters this state when its data is populated. Most of a
|
|
4055
|
+
record's lifecycle is spent inside substates of the `loaded`
|
|
4056
|
+
state.
|
|
4057
|
+
|
|
4058
|
+
Example
|
|
4059
|
+
|
|
4060
|
+
```javascript
|
|
4061
|
+
var record = store.createRecord(App.Model);
|
|
4062
|
+
record.get('isLoaded'); // true
|
|
4063
|
+
|
|
4064
|
+
store.find('model', 1).then(function(model) {
|
|
4065
|
+
model.get('isLoaded'); // true
|
|
4066
|
+
});
|
|
4067
|
+
```
|
|
4068
|
+
|
|
4069
|
+
@property isLoaded
|
|
4070
|
+
@type {Boolean}
|
|
4071
|
+
@readOnly
|
|
4072
|
+
*/
|
|
3429
4073
|
isLoaded: retrieveFromCurrentState,
|
|
4074
|
+
/**
|
|
4075
|
+
If this property is `true` the record is in the `dirty` state. The
|
|
4076
|
+
record has local changes that have not yet been saved by the
|
|
4077
|
+
adapter. This includes records that have been created (but not yet
|
|
4078
|
+
saved) or deleted.
|
|
4079
|
+
|
|
4080
|
+
Example
|
|
4081
|
+
|
|
4082
|
+
```javascript
|
|
4083
|
+
var record = store.createRecord(App.Model);
|
|
4084
|
+
record.get('isDirty'); // true
|
|
4085
|
+
|
|
4086
|
+
store.find('model', 1).then(function(model) {
|
|
4087
|
+
model.get('isDirty'); // false
|
|
4088
|
+
model.set('foo', 'some value');
|
|
4089
|
+
model.set('isDirty'); // true
|
|
4090
|
+
});
|
|
4091
|
+
```
|
|
4092
|
+
|
|
4093
|
+
@property isDirty
|
|
4094
|
+
@type {Boolean}
|
|
4095
|
+
@readOnly
|
|
4096
|
+
*/
|
|
3430
4097
|
isDirty: retrieveFromCurrentState,
|
|
4098
|
+
/**
|
|
4099
|
+
If this property is `true` the record is in the `saving` state. A
|
|
4100
|
+
record enters the saving state when `save` is called, but the
|
|
4101
|
+
adapter has not yet acknowledged that the changes have been
|
|
4102
|
+
persisted to the backend.
|
|
4103
|
+
|
|
4104
|
+
Example
|
|
4105
|
+
|
|
4106
|
+
```javascript
|
|
4107
|
+
var record = store.createRecord(App.Model);
|
|
4108
|
+
record.get('isSaving'); // false
|
|
4109
|
+
var promise = record.save();
|
|
4110
|
+
record.get('isSaving'); // true
|
|
4111
|
+
promise.then(function() {
|
|
4112
|
+
record.get('isSaving'); // false
|
|
4113
|
+
});
|
|
4114
|
+
```
|
|
4115
|
+
|
|
4116
|
+
@property isSaving
|
|
4117
|
+
@type {Boolean}
|
|
4118
|
+
@readOnly
|
|
4119
|
+
*/
|
|
3431
4120
|
isSaving: retrieveFromCurrentState,
|
|
4121
|
+
/**
|
|
4122
|
+
If this property is `true` the record is in the `deleted` state
|
|
4123
|
+
and has been marked for deletion. When `isDeleted` is true and
|
|
4124
|
+
`isDirty` is true, the record is deleted locally but the deletion
|
|
4125
|
+
was not yet persisted. When `isSaving` is true, the change is
|
|
4126
|
+
in-flight. When both `isDirty` and `isSaving` are false, the
|
|
4127
|
+
change has persisted.
|
|
4128
|
+
|
|
4129
|
+
Example
|
|
4130
|
+
|
|
4131
|
+
```javascript
|
|
4132
|
+
var record = store.createRecord(App.Model);
|
|
4133
|
+
record.get('isDeleted'); // false
|
|
4134
|
+
record.deleteRecord();
|
|
4135
|
+
record.get('isDeleted'); // true
|
|
4136
|
+
```
|
|
4137
|
+
|
|
4138
|
+
@property isDeleted
|
|
4139
|
+
@type {Boolean}
|
|
4140
|
+
@readOnly
|
|
4141
|
+
*/
|
|
3432
4142
|
isDeleted: retrieveFromCurrentState,
|
|
4143
|
+
/**
|
|
4144
|
+
If this property is `true` the record is in the `new` state. A
|
|
4145
|
+
record will be in the `new` state when it has been created on the
|
|
4146
|
+
client and the adapter has not yet report that it was successfully
|
|
4147
|
+
saved.
|
|
4148
|
+
|
|
4149
|
+
Example
|
|
4150
|
+
|
|
4151
|
+
```javascript
|
|
4152
|
+
var record = store.createRecord(App.Model);
|
|
4153
|
+
record.get('isNew'); // true
|
|
4154
|
+
|
|
4155
|
+
store.find('model', 1).then(function(model) {
|
|
4156
|
+
model.get('isNew'); // false
|
|
4157
|
+
});
|
|
4158
|
+
```
|
|
4159
|
+
|
|
4160
|
+
@property isNew
|
|
4161
|
+
@type {Boolean}
|
|
4162
|
+
@readOnly
|
|
4163
|
+
*/
|
|
3433
4164
|
isNew: retrieveFromCurrentState,
|
|
4165
|
+
/**
|
|
4166
|
+
If this property is `true` the record is in the `valid` state. A
|
|
4167
|
+
record will be in the `valid` state when no client-side
|
|
4168
|
+
validations have failed and the adapter did not report any
|
|
4169
|
+
server-side validation failures.
|
|
4170
|
+
|
|
4171
|
+
@property isValid
|
|
4172
|
+
@type {Boolean}
|
|
4173
|
+
@readOnly
|
|
4174
|
+
*/
|
|
3434
4175
|
isValid: retrieveFromCurrentState,
|
|
4176
|
+
/**
|
|
4177
|
+
If the record is in the dirty state this property will report what
|
|
4178
|
+
kind of change has caused it to move into the dirty
|
|
4179
|
+
state. Possible values are:
|
|
4180
|
+
|
|
4181
|
+
- `created` The record has been created by the client and not yet saved to the adapter.
|
|
4182
|
+
- `updated` The record has been updated by the client and not yet saved to the adapter.
|
|
4183
|
+
- `deleted` The record has been deleted by the client and not yet saved to the adapter.
|
|
4184
|
+
|
|
4185
|
+
Example
|
|
4186
|
+
|
|
4187
|
+
```javascript
|
|
4188
|
+
var record = store.createRecord(App.Model);
|
|
4189
|
+
record.get('dirtyType'); // 'created'
|
|
4190
|
+
```
|
|
4191
|
+
|
|
4192
|
+
@property dirtyType
|
|
4193
|
+
@type {String}
|
|
4194
|
+
@readOnly
|
|
4195
|
+
*/
|
|
3435
4196
|
dirtyType: retrieveFromCurrentState,
|
|
3436
4197
|
|
|
4198
|
+
/**
|
|
4199
|
+
If `true` the adapter reported that it was unable to save local
|
|
4200
|
+
changes to the backend. This may also result in the record having
|
|
4201
|
+
its `isValid` property become false if the adapter reported that
|
|
4202
|
+
server-side validations failed.
|
|
4203
|
+
|
|
4204
|
+
Example
|
|
4205
|
+
|
|
4206
|
+
```javascript
|
|
4207
|
+
record.get('isError'); // false
|
|
4208
|
+
record.set('foo', 'invalid value');
|
|
4209
|
+
record.save().then(null, function() {
|
|
4210
|
+
record.get('isError'); // true
|
|
4211
|
+
});
|
|
4212
|
+
```
|
|
4213
|
+
|
|
4214
|
+
@property isError
|
|
4215
|
+
@type {Boolean}
|
|
4216
|
+
@readOnly
|
|
4217
|
+
*/
|
|
3437
4218
|
isError: false,
|
|
4219
|
+
/**
|
|
4220
|
+
If `true` the store is attempting to reload the record form the adapter.
|
|
4221
|
+
|
|
4222
|
+
Example
|
|
4223
|
+
|
|
4224
|
+
```javascript
|
|
4225
|
+
record.get('isReloading'); // false
|
|
4226
|
+
record.reload();
|
|
4227
|
+
record.get('isReloading'); // true
|
|
4228
|
+
```
|
|
4229
|
+
|
|
4230
|
+
@property isReloading
|
|
4231
|
+
@type {Boolean}
|
|
4232
|
+
@readOnly
|
|
4233
|
+
*/
|
|
3438
4234
|
isReloading: false,
|
|
3439
4235
|
|
|
4236
|
+
/**
|
|
4237
|
+
The `clientId` property is a transient numerical identifier
|
|
4238
|
+
generated at runtime by the data store. It is important
|
|
4239
|
+
primarily because newly created objects may not yet have an
|
|
4240
|
+
externally generated id.
|
|
4241
|
+
|
|
4242
|
+
@property clientId
|
|
4243
|
+
@private
|
|
4244
|
+
@type {Number|String}
|
|
4245
|
+
*/
|
|
3440
4246
|
clientId: null,
|
|
4247
|
+
/**
|
|
4248
|
+
All ember models have an id property. This is an identifier
|
|
4249
|
+
managed by an external source. These are always coerced to be
|
|
4250
|
+
strings before being used internally. Note when declaring the
|
|
4251
|
+
attributes for a model it is an error to declare an id
|
|
4252
|
+
attribute.
|
|
4253
|
+
|
|
4254
|
+
```javascript
|
|
4255
|
+
var record = store.createRecord(App.Model);
|
|
4256
|
+
record.get('id'); // null
|
|
4257
|
+
|
|
4258
|
+
store.find('model', 1).then(function(model) {
|
|
4259
|
+
model.get('id'); // '1'
|
|
4260
|
+
});
|
|
4261
|
+
```
|
|
4262
|
+
|
|
4263
|
+
@property id
|
|
4264
|
+
@type {String}
|
|
4265
|
+
*/
|
|
3441
4266
|
id: null,
|
|
3442
4267
|
transaction: null,
|
|
4268
|
+
/**
|
|
4269
|
+
@property currentState
|
|
4270
|
+
@private
|
|
4271
|
+
@type {Object}
|
|
4272
|
+
*/
|
|
3443
4273
|
currentState: null,
|
|
4274
|
+
/**
|
|
4275
|
+
When the record is in the `invalid` state this object will contain
|
|
4276
|
+
any errors returned by the adapter. When present the errors hash
|
|
4277
|
+
typically contains keys coresponding to the invalid property names
|
|
4278
|
+
and values which are an array of error messages.
|
|
4279
|
+
|
|
4280
|
+
```javascript
|
|
4281
|
+
record.get('errors'); // null
|
|
4282
|
+
record.set('foo', 'invalid value');
|
|
4283
|
+
record.save().then(null, function() {
|
|
4284
|
+
record.get('errors'); // {foo: ['foo should be a number.']}
|
|
4285
|
+
});
|
|
4286
|
+
```
|
|
4287
|
+
|
|
4288
|
+
@property errors
|
|
4289
|
+
@type {Object}
|
|
4290
|
+
*/
|
|
3444
4291
|
errors: null,
|
|
3445
4292
|
|
|
3446
4293
|
/**
|
|
3447
4294
|
Create a JSON representation of the record, using the serialization
|
|
3448
4295
|
strategy of the store's adapter.
|
|
3449
4296
|
|
|
3450
|
-
|
|
3451
|
-
|
|
4297
|
+
`serialize` takes an optional hash as a parameter, currently
|
|
4298
|
+
supported options are:
|
|
3452
4299
|
|
|
3453
|
-
|
|
4300
|
+
- `includeId`: `true` if the record's ID should be included in the
|
|
3454
4301
|
JSON representation.
|
|
3455
4302
|
|
|
4303
|
+
@method serialize
|
|
4304
|
+
@param {Object} options
|
|
3456
4305
|
@returns {Object} an object whose values are primitive JSON values only
|
|
3457
4306
|
*/
|
|
3458
4307
|
serialize: function(options) {
|
|
@@ -3461,15 +4310,17 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3461
4310
|
},
|
|
3462
4311
|
|
|
3463
4312
|
/**
|
|
3464
|
-
Use
|
|
4313
|
+
Use [DS.JSONSerializer](DS.JSONSerializer.html) to
|
|
3465
4314
|
get the JSON representation of a record.
|
|
3466
4315
|
|
|
3467
|
-
|
|
3468
|
-
|
|
4316
|
+
`toJSON` takes an optional hash as a parameter, currently
|
|
4317
|
+
supported options are:
|
|
3469
4318
|
|
|
3470
|
-
|
|
4319
|
+
- `includeId`: `true` if the record's ID should be included in the
|
|
3471
4320
|
JSON representation.
|
|
3472
4321
|
|
|
4322
|
+
@method toJSON
|
|
4323
|
+
@param {Object} options
|
|
3473
4324
|
@returns {Object} A JSON representation of the object.
|
|
3474
4325
|
*/
|
|
3475
4326
|
toJSON: function(options) {
|
|
@@ -3485,13 +4336,6 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3485
4336
|
*/
|
|
3486
4337
|
didLoad: Ember.K,
|
|
3487
4338
|
|
|
3488
|
-
/**
|
|
3489
|
-
Fired when the record is reloaded from the server.
|
|
3490
|
-
|
|
3491
|
-
@event didReload
|
|
3492
|
-
*/
|
|
3493
|
-
didReload: Ember.K,
|
|
3494
|
-
|
|
3495
4339
|
/**
|
|
3496
4340
|
Fired when the record is updated.
|
|
3497
4341
|
|
|
@@ -3527,6 +4371,11 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3527
4371
|
*/
|
|
3528
4372
|
becameError: Ember.K,
|
|
3529
4373
|
|
|
4374
|
+
/**
|
|
4375
|
+
@property data
|
|
4376
|
+
@private
|
|
4377
|
+
@type {Object}
|
|
4378
|
+
*/
|
|
3530
4379
|
data: Ember.computed(function() {
|
|
3531
4380
|
this._data = this._data || {};
|
|
3532
4381
|
return this._data;
|
|
@@ -3549,6 +4398,12 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3549
4398
|
this._relationships = {};
|
|
3550
4399
|
},
|
|
3551
4400
|
|
|
4401
|
+
/**
|
|
4402
|
+
@method send
|
|
4403
|
+
@private
|
|
4404
|
+
@param {String} name
|
|
4405
|
+
@param {Object} context
|
|
4406
|
+
*/
|
|
3552
4407
|
send: function(name, context) {
|
|
3553
4408
|
var currentState = get(this, 'currentState');
|
|
3554
4409
|
|
|
@@ -3559,6 +4414,11 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3559
4414
|
return currentState[name](this, context);
|
|
3560
4415
|
},
|
|
3561
4416
|
|
|
4417
|
+
/**
|
|
4418
|
+
@method transitionTo
|
|
4419
|
+
@private
|
|
4420
|
+
@param {String} name
|
|
4421
|
+
*/
|
|
3562
4422
|
transitionTo: function(name) {
|
|
3563
4423
|
// POSSIBLE TODO: Remove this code and replace with
|
|
3564
4424
|
// always having direct references to state objects
|
|
@@ -3613,18 +4473,35 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3613
4473
|
if (transaction) { fn(transaction); }
|
|
3614
4474
|
},
|
|
3615
4475
|
|
|
4476
|
+
/**
|
|
4477
|
+
@method loadingData
|
|
4478
|
+
@private
|
|
4479
|
+
@param {Promise} promise
|
|
4480
|
+
*/
|
|
3616
4481
|
loadingData: function(promise) {
|
|
3617
4482
|
this.send('loadingData', promise);
|
|
3618
4483
|
},
|
|
3619
4484
|
|
|
4485
|
+
/**
|
|
4486
|
+
@method loadedData
|
|
4487
|
+
@private
|
|
4488
|
+
*/
|
|
3620
4489
|
loadedData: function() {
|
|
3621
4490
|
this.send('loadedData');
|
|
3622
4491
|
},
|
|
3623
4492
|
|
|
4493
|
+
/**
|
|
4494
|
+
@method notFound
|
|
4495
|
+
@private
|
|
4496
|
+
*/
|
|
3624
4497
|
notFound: function() {
|
|
3625
4498
|
this.send('notFound');
|
|
3626
4499
|
},
|
|
3627
4500
|
|
|
4501
|
+
/**
|
|
4502
|
+
@method pushedData
|
|
4503
|
+
@private
|
|
4504
|
+
*/
|
|
3628
4505
|
pushedData: function() {
|
|
3629
4506
|
this.send('pushedData');
|
|
3630
4507
|
},
|
|
@@ -3635,6 +4512,24 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3635
4512
|
method if you want to allow the user to still `rollback()` a
|
|
3636
4513
|
delete after it was made.
|
|
3637
4514
|
|
|
4515
|
+
Example
|
|
4516
|
+
|
|
4517
|
+
```javascript
|
|
4518
|
+
App.ModelDeleteRoute = Ember.Route.extend({
|
|
4519
|
+
actions: {
|
|
4520
|
+
softDelete: function() {
|
|
4521
|
+
this.get('model').deleteRecord();
|
|
4522
|
+
},
|
|
4523
|
+
confirm: function() {
|
|
4524
|
+
this.get('model').save();
|
|
4525
|
+
},
|
|
4526
|
+
undo: function() {
|
|
4527
|
+
this.get('model').rollback();
|
|
4528
|
+
}
|
|
4529
|
+
}
|
|
4530
|
+
});
|
|
4531
|
+
```
|
|
4532
|
+
|
|
3638
4533
|
@method deleteRecord
|
|
3639
4534
|
*/
|
|
3640
4535
|
deleteRecord: function() {
|
|
@@ -3644,20 +4539,44 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3644
4539
|
/**
|
|
3645
4540
|
Same as `deleteRecord`, but saves the record immediately.
|
|
3646
4541
|
|
|
4542
|
+
Example
|
|
4543
|
+
|
|
4544
|
+
```javascript
|
|
4545
|
+
App.ModelDeleteRoute = Ember.Route.extend({
|
|
4546
|
+
actions: {
|
|
4547
|
+
delete: function() {
|
|
4548
|
+
var controller = this.controller;
|
|
4549
|
+
this.get('model').destroyRecord().then(function() {
|
|
4550
|
+
controller.transitionToRoute('model.index');
|
|
4551
|
+
});
|
|
4552
|
+
}
|
|
4553
|
+
}
|
|
4554
|
+
});
|
|
4555
|
+
```
|
|
4556
|
+
|
|
3647
4557
|
@method destroyRecord
|
|
3648
|
-
@
|
|
4558
|
+
@return {Promise} a promise that will be resolved when the adapter returns
|
|
4559
|
+
successfully or rejected if the adapter returns with an error.
|
|
3649
4560
|
*/
|
|
3650
4561
|
destroyRecord: function() {
|
|
3651
4562
|
this.deleteRecord();
|
|
3652
4563
|
return this.save();
|
|
3653
4564
|
},
|
|
3654
4565
|
|
|
4566
|
+
/**
|
|
4567
|
+
@method unloadRecord
|
|
4568
|
+
@private
|
|
4569
|
+
*/
|
|
3655
4570
|
unloadRecord: function() {
|
|
3656
4571
|
|
|
3657
4572
|
|
|
3658
4573
|
this.send('unloadRecord');
|
|
3659
4574
|
},
|
|
3660
4575
|
|
|
4576
|
+
/**
|
|
4577
|
+
@method clearRelationships
|
|
4578
|
+
@private
|
|
4579
|
+
*/
|
|
3661
4580
|
clearRelationships: function() {
|
|
3662
4581
|
this.eachRelationship(function(name, relationship) {
|
|
3663
4582
|
if (relationship.kind === 'belongsTo') {
|
|
@@ -3669,19 +4588,33 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3669
4588
|
}, this);
|
|
3670
4589
|
},
|
|
3671
4590
|
|
|
4591
|
+
/**
|
|
4592
|
+
@method updateRecordArrays
|
|
4593
|
+
@private
|
|
4594
|
+
*/
|
|
3672
4595
|
updateRecordArrays: function() {
|
|
3673
|
-
|
|
3674
|
-
if (store) {
|
|
3675
|
-
store.dataWasUpdated(this.constructor, this);
|
|
3676
|
-
}
|
|
4596
|
+
get(this, 'store').dataWasUpdated(this.constructor, this);
|
|
3677
4597
|
},
|
|
3678
4598
|
|
|
3679
4599
|
/**
|
|
3680
|
-
|
|
4600
|
+
Returns an object, whose keys are changed properties, and value is
|
|
4601
|
+
an [oldProp, newProp] array.
|
|
3681
4602
|
|
|
3682
|
-
|
|
4603
|
+
Example
|
|
4604
|
+
|
|
4605
|
+
```javascript
|
|
4606
|
+
App.Mascot = DS.Model.extend({
|
|
4607
|
+
name: attr('string')
|
|
4608
|
+
});
|
|
3683
4609
|
|
|
3684
|
-
|
|
4610
|
+
var person = store.createRecord('person');
|
|
4611
|
+
person.changedAttributes(); // {}
|
|
4612
|
+
person.set('name', 'Tomster');
|
|
4613
|
+
person.changedAttributes(); // {name: [undefined, 'Tomster']}
|
|
4614
|
+
```
|
|
4615
|
+
|
|
4616
|
+
@method changedAttributes
|
|
4617
|
+
@return {Object} an object, whose keys are changed properties,
|
|
3685
4618
|
and value is an [oldProp, newProp] array.
|
|
3686
4619
|
*/
|
|
3687
4620
|
changedAttributes: function() {
|
|
@@ -3697,6 +4630,10 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3697
4630
|
return diffData;
|
|
3698
4631
|
},
|
|
3699
4632
|
|
|
4633
|
+
/**
|
|
4634
|
+
@method adapterWillCommit
|
|
4635
|
+
@private
|
|
4636
|
+
*/
|
|
3700
4637
|
adapterWillCommit: function() {
|
|
3701
4638
|
this.send('willCommit');
|
|
3702
4639
|
},
|
|
@@ -3729,6 +4666,10 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3729
4666
|
});
|
|
3730
4667
|
},
|
|
3731
4668
|
|
|
4669
|
+
/**
|
|
4670
|
+
@method adapterDidDirty
|
|
4671
|
+
@private
|
|
4672
|
+
*/
|
|
3732
4673
|
adapterDidDirty: function() {
|
|
3733
4674
|
this.send('becomeDirty');
|
|
3734
4675
|
this.updateRecordArraysLater();
|
|
@@ -3761,10 +4702,21 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3761
4702
|
}
|
|
3762
4703
|
},
|
|
3763
4704
|
|
|
4705
|
+
/**
|
|
4706
|
+
@method updateRecordArraysLater
|
|
4707
|
+
@private
|
|
4708
|
+
*/
|
|
3764
4709
|
updateRecordArraysLater: function() {
|
|
3765
4710
|
Ember.run.once(this, this.updateRecordArrays);
|
|
3766
4711
|
},
|
|
3767
4712
|
|
|
4713
|
+
/**
|
|
4714
|
+
@method setupData
|
|
4715
|
+
@private
|
|
4716
|
+
@param {Object} data
|
|
4717
|
+
@param {Boolean} partial the data should be merged into
|
|
4718
|
+
the existing data, not replace it.
|
|
4719
|
+
*/
|
|
3768
4720
|
setupData: function(data, partial) {
|
|
3769
4721
|
if (partial) {
|
|
3770
4722
|
Ember.merge(this._data, data);
|
|
@@ -3799,15 +4751,43 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3799
4751
|
this._data[name] = value;
|
|
3800
4752
|
},
|
|
3801
4753
|
|
|
4754
|
+
/**
|
|
4755
|
+
@method updateHasMany
|
|
4756
|
+
@private
|
|
4757
|
+
@param {String} name
|
|
4758
|
+
@param {Array} records
|
|
4759
|
+
*/
|
|
3802
4760
|
updateHasMany: function(name, records) {
|
|
3803
4761
|
this._data[name] = records;
|
|
3804
4762
|
this.hasManyDidChange(name);
|
|
3805
4763
|
},
|
|
3806
4764
|
|
|
4765
|
+
/**
|
|
4766
|
+
@method updateBelongsTo
|
|
4767
|
+
@private
|
|
4768
|
+
@param {String} name
|
|
4769
|
+
@param {DS.Model} record
|
|
4770
|
+
*/
|
|
3807
4771
|
updateBelongsTo: function(name, record) {
|
|
3808
4772
|
this._data[name] = record;
|
|
3809
4773
|
},
|
|
3810
4774
|
|
|
4775
|
+
/**
|
|
4776
|
+
If the model `isDirty` this function will which discard any unsaved
|
|
4777
|
+
changes
|
|
4778
|
+
|
|
4779
|
+
Example
|
|
4780
|
+
|
|
4781
|
+
```javascript
|
|
4782
|
+
record.get('name'); // 'Untitled Document'
|
|
4783
|
+
record.set('name', 'Doc 1');
|
|
4784
|
+
record.get('name'); // 'Doc 1'
|
|
4785
|
+
record.rollback();
|
|
4786
|
+
record.get('name'); // 'Untitled Document'
|
|
4787
|
+
```
|
|
4788
|
+
|
|
4789
|
+
@method rollback
|
|
4790
|
+
*/
|
|
3811
4791
|
rollback: function() {
|
|
3812
4792
|
this._attributes = {};
|
|
3813
4793
|
|
|
@@ -3815,7 +4795,12 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3815
4795
|
this._inFlightAttributes = {};
|
|
3816
4796
|
set(this, 'isError', false);
|
|
3817
4797
|
}
|
|
3818
|
-
|
|
4798
|
+
|
|
4799
|
+
if (!get(this, 'isValid')) {
|
|
4800
|
+
this._inFlightAttributes = {};
|
|
4801
|
+
this.send('becameValid');
|
|
4802
|
+
}
|
|
4803
|
+
|
|
3819
4804
|
this.send('rolledBack');
|
|
3820
4805
|
|
|
3821
4806
|
this.suspendRelationshipObservers(function() {
|
|
@@ -3861,12 +4846,26 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3861
4846
|
},
|
|
3862
4847
|
|
|
3863
4848
|
/**
|
|
3864
|
-
Save the record
|
|
4849
|
+
Save the record and persist any changes to the record to an
|
|
4850
|
+
extenal source via the adapter.
|
|
4851
|
+
|
|
4852
|
+
Example
|
|
3865
4853
|
|
|
4854
|
+
```javascript
|
|
4855
|
+
record.set('name', 'Tomster');
|
|
4856
|
+
record.save().then(function(){
|
|
4857
|
+
// Success callback
|
|
4858
|
+
}, function() {
|
|
4859
|
+
// Error callback
|
|
4860
|
+
});
|
|
4861
|
+
```
|
|
3866
4862
|
@method save
|
|
4863
|
+
@return {Promise} a promise that will be resolved when the adapter returns
|
|
4864
|
+
successfully or rejected if the adapter returns with an error.
|
|
3867
4865
|
*/
|
|
3868
4866
|
save: function() {
|
|
3869
|
-
var
|
|
4867
|
+
var promiseLabel = "DS: Model#save " + this;
|
|
4868
|
+
var resolver = Ember.RSVP.defer(promiseLabel);
|
|
3870
4869
|
|
|
3871
4870
|
this.get('store').scheduleSave(this, resolver);
|
|
3872
4871
|
this._inFlightAttributes = this._attributes;
|
|
@@ -3882,25 +4881,41 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3882
4881
|
and has not yet been modified (`isLoaded` but not `isDirty`,
|
|
3883
4882
|
or `isSaving`).
|
|
3884
4883
|
|
|
4884
|
+
Example
|
|
4885
|
+
|
|
4886
|
+
```javascript
|
|
4887
|
+
App.ModelViewRoute = Ember.Route.extend({
|
|
4888
|
+
actions: {
|
|
4889
|
+
reload: function() {
|
|
4890
|
+
this.get('model').reload();
|
|
4891
|
+
}
|
|
4892
|
+
}
|
|
4893
|
+
});
|
|
4894
|
+
```
|
|
4895
|
+
|
|
3885
4896
|
@method reload
|
|
4897
|
+
@return {Promise} a promise that will be resolved with the record when the
|
|
4898
|
+
adapter returns successfully or rejected if the adapter returns
|
|
4899
|
+
with an error.
|
|
3886
4900
|
*/
|
|
3887
4901
|
reload: function() {
|
|
3888
4902
|
set(this, 'isReloading', true);
|
|
3889
4903
|
|
|
3890
|
-
var
|
|
4904
|
+
var record = this;
|
|
3891
4905
|
|
|
3892
|
-
|
|
4906
|
+
var promiseLabel = "DS: Model#reload of " + this;
|
|
4907
|
+
var promise = new Ember.RSVP.Promise(function(resolve){
|
|
4908
|
+
record.send('reloadRecord', resolve);
|
|
4909
|
+
}, promiseLabel).then(function() {
|
|
3893
4910
|
record.set('isReloading', false);
|
|
3894
4911
|
record.set('isError', false);
|
|
3895
4912
|
return record;
|
|
3896
4913
|
}, function(reason) {
|
|
3897
4914
|
record.set('isError', true);
|
|
3898
4915
|
throw reason;
|
|
3899
|
-
});
|
|
3900
|
-
|
|
3901
|
-
this.send('reloadRecord', resolver);
|
|
4916
|
+
}, "DS: Model#reload complete, update flags");
|
|
3902
4917
|
|
|
3903
|
-
return DS.PromiseObject.create({ promise:
|
|
4918
|
+
return DS.PromiseObject.create({ promise: promise });
|
|
3904
4919
|
},
|
|
3905
4920
|
|
|
3906
4921
|
// FOR USE DURING COMMIT PROCESS
|
|
@@ -3921,10 +4936,18 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
|
3921
4936
|
this.updateRecordArraysLater();
|
|
3922
4937
|
},
|
|
3923
4938
|
|
|
4939
|
+
/**
|
|
4940
|
+
@method adapterDidInvalidate
|
|
4941
|
+
@private
|
|
4942
|
+
*/
|
|
3924
4943
|
adapterDidInvalidate: function(errors) {
|
|
3925
4944
|
this.send('becameInvalid', errors);
|
|
3926
4945
|
},
|
|
3927
4946
|
|
|
4947
|
+
/**
|
|
4948
|
+
@method adapterDidError
|
|
4949
|
+
@private
|
|
4950
|
+
*/
|
|
3928
4951
|
adapterDidError: function() {
|
|
3929
4952
|
this.send('becameError');
|
|
3930
4953
|
set(this, 'isError', true);
|
|
@@ -3971,9 +4994,11 @@ DS.Model.reopenClass({
|
|
|
3971
4994
|
_create: DS.Model.create,
|
|
3972
4995
|
|
|
3973
4996
|
/**
|
|
3974
|
-
Override the class' `create()` method to raise an error. This
|
|
3975
|
-
from inadvertently calling `create()` instead
|
|
3976
|
-
still able to create instances
|
|
4997
|
+
Override the class' `create()` method to raise an error. This
|
|
4998
|
+
prevents end users from inadvertently calling `create()` instead
|
|
4999
|
+
of `createRecord()`. The store is still able to create instances
|
|
5000
|
+
by calling the `_create()` method. To create an instance of a
|
|
5001
|
+
`DS.Model` use [store.createRecord](DS.Store.html#method_createRecord).
|
|
3977
5002
|
|
|
3978
5003
|
@method create
|
|
3979
5004
|
@private
|
|
@@ -4000,6 +5025,38 @@ var get = Ember.get;
|
|
|
4000
5025
|
@namespace DS
|
|
4001
5026
|
*/
|
|
4002
5027
|
DS.Model.reopenClass({
|
|
5028
|
+
/**
|
|
5029
|
+
A map whose keys are the attributes of the model (properties
|
|
5030
|
+
described by DS.attr) and whose values are the meta object for the
|
|
5031
|
+
property.
|
|
5032
|
+
|
|
5033
|
+
Example
|
|
5034
|
+
|
|
5035
|
+
```javascript
|
|
5036
|
+
|
|
5037
|
+
App.Person = DS.Model.extend({
|
|
5038
|
+
firstName: attr('string'),
|
|
5039
|
+
lastName: attr('string'),
|
|
5040
|
+
birthday: attr('date')
|
|
5041
|
+
});
|
|
5042
|
+
|
|
5043
|
+
var attributes = Ember.get(App.Person, 'attributes')
|
|
5044
|
+
|
|
5045
|
+
attributes.forEach(function(name, meta) {
|
|
5046
|
+
console.log(name, meta);
|
|
5047
|
+
});
|
|
5048
|
+
|
|
5049
|
+
// prints:
|
|
5050
|
+
// firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"}
|
|
5051
|
+
// lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"}
|
|
5052
|
+
// birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"}
|
|
5053
|
+
```
|
|
5054
|
+
|
|
5055
|
+
@property attributes
|
|
5056
|
+
@static
|
|
5057
|
+
@type {Ember.Map}
|
|
5058
|
+
@readOnly
|
|
5059
|
+
*/
|
|
4003
5060
|
attributes: Ember.computed(function() {
|
|
4004
5061
|
var map = Ember.Map.create();
|
|
4005
5062
|
|
|
@@ -4015,6 +5072,37 @@ DS.Model.reopenClass({
|
|
|
4015
5072
|
return map;
|
|
4016
5073
|
}),
|
|
4017
5074
|
|
|
5075
|
+
/**
|
|
5076
|
+
A map whose keys are the attributes of the model (properties
|
|
5077
|
+
described by DS.attr) and whose values are type of transformation
|
|
5078
|
+
applied to each attribute. This map does not include any
|
|
5079
|
+
attributes that do not have an transformation type.
|
|
5080
|
+
|
|
5081
|
+
Example
|
|
5082
|
+
|
|
5083
|
+
```javascript
|
|
5084
|
+
App.Person = DS.Model.extend({
|
|
5085
|
+
firstName: attr(),
|
|
5086
|
+
lastName: attr('string'),
|
|
5087
|
+
birthday: attr('date')
|
|
5088
|
+
});
|
|
5089
|
+
|
|
5090
|
+
var transformedAttributes = Ember.get(App.Person, 'transformedAttributes')
|
|
5091
|
+
|
|
5092
|
+
transformedAttributes.forEach(function(field, type) {
|
|
5093
|
+
console.log(field, type);
|
|
5094
|
+
});
|
|
5095
|
+
|
|
5096
|
+
// prints:
|
|
5097
|
+
// lastName string
|
|
5098
|
+
// birthday date
|
|
5099
|
+
```
|
|
5100
|
+
|
|
5101
|
+
@property transformedAttributes
|
|
5102
|
+
@static
|
|
5103
|
+
@type {Ember.Map}
|
|
5104
|
+
@readOnly
|
|
5105
|
+
*/
|
|
4018
5106
|
transformedAttributes: Ember.computed(function() {
|
|
4019
5107
|
var map = Ember.Map.create();
|
|
4020
5108
|
|
|
@@ -4027,12 +5115,95 @@ DS.Model.reopenClass({
|
|
|
4027
5115
|
return map;
|
|
4028
5116
|
}),
|
|
4029
5117
|
|
|
5118
|
+
/**
|
|
5119
|
+
Iterates through the attributes of the model, calling the passed function on each
|
|
5120
|
+
attribute.
|
|
5121
|
+
|
|
5122
|
+
The callback method you provide should have the following signature (all
|
|
5123
|
+
parameters are optional):
|
|
5124
|
+
|
|
5125
|
+
```javascript
|
|
5126
|
+
function(name, meta);
|
|
5127
|
+
```
|
|
5128
|
+
|
|
5129
|
+
- `name` the name of the current property in the iteration
|
|
5130
|
+
- `meta` the meta object for the attribute property in the iteration
|
|
5131
|
+
|
|
5132
|
+
Note that in addition to a callback, you can also pass an optional target
|
|
5133
|
+
object that will be set as `this` on the context.
|
|
5134
|
+
|
|
5135
|
+
Example
|
|
5136
|
+
|
|
5137
|
+
```javascript
|
|
5138
|
+
App.Person = DS.Model.extend({
|
|
5139
|
+
firstName: attr('string'),
|
|
5140
|
+
lastName: attr('string'),
|
|
5141
|
+
birthday: attr('date')
|
|
5142
|
+
});
|
|
5143
|
+
|
|
5144
|
+
App.Person.eachAttribute(function(name, meta) {
|
|
5145
|
+
console.log(name, meta);
|
|
5146
|
+
});
|
|
5147
|
+
|
|
5148
|
+
// prints:
|
|
5149
|
+
// firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"}
|
|
5150
|
+
// lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"}
|
|
5151
|
+
// birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"}
|
|
5152
|
+
```
|
|
5153
|
+
|
|
5154
|
+
@method eachAttribute
|
|
5155
|
+
@param {Function} callback The callback to execute
|
|
5156
|
+
@param {Object} [target] The target object to use
|
|
5157
|
+
@static
|
|
5158
|
+
*/
|
|
4030
5159
|
eachAttribute: function(callback, binding) {
|
|
4031
5160
|
get(this, 'attributes').forEach(function(name, meta) {
|
|
4032
5161
|
callback.call(binding, name, meta);
|
|
4033
5162
|
}, binding);
|
|
4034
5163
|
},
|
|
4035
5164
|
|
|
5165
|
+
/**
|
|
5166
|
+
Iterates through the transformedAttributes of the model, calling
|
|
5167
|
+
the passed function on each attribute. Note the callback will not be
|
|
5168
|
+
called for any attributes that do not have an transformation type.
|
|
5169
|
+
|
|
5170
|
+
The callback method you provide should have the following signature (all
|
|
5171
|
+
parameters are optional):
|
|
5172
|
+
|
|
5173
|
+
```javascript
|
|
5174
|
+
function(name, type);
|
|
5175
|
+
```
|
|
5176
|
+
|
|
5177
|
+
- `name` the name of the current property in the iteration
|
|
5178
|
+
- `type` a tring contrining the name of the type of transformed
|
|
5179
|
+
applied to the attribute
|
|
5180
|
+
|
|
5181
|
+
Note that in addition to a callback, you can also pass an optional target
|
|
5182
|
+
object that will be set as `this` on the context.
|
|
5183
|
+
|
|
5184
|
+
Example
|
|
5185
|
+
|
|
5186
|
+
```javascript
|
|
5187
|
+
App.Person = DS.Model.extend({
|
|
5188
|
+
firstName: attr(),
|
|
5189
|
+
lastName: attr('string'),
|
|
5190
|
+
birthday: attr('date')
|
|
5191
|
+
});
|
|
5192
|
+
|
|
5193
|
+
App.Person.eachTransformedAttribute(function(name, type) {
|
|
5194
|
+
console.log(name, type);
|
|
5195
|
+
});
|
|
5196
|
+
|
|
5197
|
+
// prints:
|
|
5198
|
+
// lastName string
|
|
5199
|
+
// birthday date
|
|
5200
|
+
```
|
|
5201
|
+
|
|
5202
|
+
@method eachTransformedAttribute
|
|
5203
|
+
@param {Function} callback The callback to execute
|
|
5204
|
+
@param {Object} [target] The target object to use
|
|
5205
|
+
@static
|
|
5206
|
+
*/
|
|
4036
5207
|
eachTransformedAttribute: function(callback, binding) {
|
|
4037
5208
|
get(this, 'transformedAttributes').forEach(function(name, type) {
|
|
4038
5209
|
callback.call(binding, name, type);
|
|
@@ -4072,21 +5243,37 @@ function getValue(record, key) {
|
|
|
4072
5243
|
}
|
|
4073
5244
|
|
|
4074
5245
|
/**
|
|
4075
|
-
`DS.attr` defines an attribute on a DS.Model.
|
|
5246
|
+
`DS.attr` defines an attribute on a [DS.Model](DS.Model.html).
|
|
4076
5247
|
By default, attributes are passed through as-is, however you can specify an
|
|
4077
5248
|
optional type to have the value automatically transformed.
|
|
4078
|
-
Ember Data ships with four basic transform types:
|
|
4079
|
-
|
|
4080
|
-
|
|
5249
|
+
Ember Data ships with four basic transform types: `string`, `number`,
|
|
5250
|
+
`boolean` and `date`. You can define your own transforms by subclassing
|
|
5251
|
+
[DS.Transform](DS.Transform.html).
|
|
4081
5252
|
|
|
4082
|
-
DS.attr takes an optional hash as a second parameter, currently
|
|
5253
|
+
`DS.attr` takes an optional hash as a second parameter, currently
|
|
4083
5254
|
supported options are:
|
|
4084
|
-
|
|
5255
|
+
|
|
5256
|
+
- `defaultValue`: Pass a string or a function to be called to set the attribute
|
|
4085
5257
|
to a default value if none is supplied.
|
|
4086
5258
|
|
|
5259
|
+
Example
|
|
5260
|
+
|
|
5261
|
+
```javascript
|
|
5262
|
+
var attr = DS.attr;
|
|
5263
|
+
|
|
5264
|
+
App.User = DS.Model.extend({
|
|
5265
|
+
username: attr('string'),
|
|
5266
|
+
email: attr('string'),
|
|
5267
|
+
verified: attr('boolean', {defaultValue: false})
|
|
5268
|
+
});
|
|
5269
|
+
```
|
|
5270
|
+
|
|
5271
|
+
@namespace
|
|
4087
5272
|
@method attr
|
|
5273
|
+
@for DS
|
|
4088
5274
|
@param {String} type the attribute type
|
|
4089
5275
|
@param {Object} options a hash of options
|
|
5276
|
+
@return {Attribute}
|
|
4090
5277
|
*/
|
|
4091
5278
|
|
|
4092
5279
|
DS.attr = function(type, options) {
|
|
@@ -4102,7 +5289,14 @@ DS.attr = function(type, options) {
|
|
|
4102
5289
|
if (arguments.length > 1) {
|
|
4103
5290
|
|
|
4104
5291
|
var oldValue = this._attributes[key] || this._inFlightAttributes[key] || this._data[key];
|
|
4105
|
-
|
|
5292
|
+
|
|
5293
|
+
this.send('didSetProperty', {
|
|
5294
|
+
name: key,
|
|
5295
|
+
oldValue: oldValue,
|
|
5296
|
+
originalValue: this._data[key],
|
|
5297
|
+
value: value
|
|
5298
|
+
});
|
|
5299
|
+
|
|
4106
5300
|
this._attributes[key] = value;
|
|
4107
5301
|
return value;
|
|
4108
5302
|
} else if (hasValue(this, key)) {
|
|
@@ -4655,21 +5849,22 @@ var get = Ember.get, set = Ember.set,
|
|
|
4655
5849
|
function asyncBelongsTo(type, options, meta) {
|
|
4656
5850
|
return Ember.computed(function(key, value) {
|
|
4657
5851
|
var data = get(this, 'data'),
|
|
4658
|
-
store = get(this, 'store')
|
|
5852
|
+
store = get(this, 'store'),
|
|
5853
|
+
promiseLabel = "DS: Async belongsTo " + this + " : " + key;
|
|
4659
5854
|
|
|
4660
5855
|
if (arguments.length === 2) {
|
|
4661
5856
|
|
|
4662
|
-
return value === undefined ? null : DS.PromiseObject.create({ promise: Ember.RSVP.resolve(value) });
|
|
5857
|
+
return value === undefined ? null : DS.PromiseObject.create({ promise: Ember.RSVP.resolve(value, promiseLabel) });
|
|
4663
5858
|
}
|
|
4664
5859
|
|
|
4665
5860
|
var link = data.links && data.links[key],
|
|
4666
5861
|
belongsTo = data[key];
|
|
4667
5862
|
|
|
4668
5863
|
if(!isNone(belongsTo)) {
|
|
4669
|
-
var promise = store.fetchRecord(belongsTo) || Ember.RSVP.resolve(belongsTo);
|
|
4670
|
-
return DS.PromiseObject.create({promise: promise});
|
|
5864
|
+
var promise = store.fetchRecord(belongsTo) || Ember.RSVP.resolve(belongsTo, promiseLabel);
|
|
5865
|
+
return DS.PromiseObject.create({ promise: promise});
|
|
4671
5866
|
} else if (link) {
|
|
4672
|
-
var resolver = Ember.RSVP.defer();
|
|
5867
|
+
var resolver = Ember.RSVP.defer("DS: Async belongsTo (link) " + this + " : " + key);
|
|
4673
5868
|
store.findBelongsTo(this, link, meta, resolver);
|
|
4674
5869
|
return DS.PromiseObject.create({ promise: resolver.promise });
|
|
4675
5870
|
} else {
|
|
@@ -4678,6 +5873,53 @@ function asyncBelongsTo(type, options, meta) {
|
|
|
4678
5873
|
}).property('data').meta(meta);
|
|
4679
5874
|
}
|
|
4680
5875
|
|
|
5876
|
+
/**
|
|
5877
|
+
`DS.belongsTo` is used to define One-To-One and One-To-Many
|
|
5878
|
+
relationships on a [DS.Model](DS.Model.html).
|
|
5879
|
+
|
|
5880
|
+
|
|
5881
|
+
`DS.belongsTo` takes an optional hash as a second parameter, currently
|
|
5882
|
+
supported options are:
|
|
5883
|
+
|
|
5884
|
+
- `async`: A boolean value used to explicitly declare this to be an async relationship.
|
|
5885
|
+
- `inverse`: A string used to identify the inverse property on a
|
|
5886
|
+
related model in a One-To-Many relationship. See [Explicit Inverses](#toc_explicit-inverses)
|
|
5887
|
+
|
|
5888
|
+
#### One-To-One
|
|
5889
|
+
To declare a one-to-one relationship between two models, use
|
|
5890
|
+
`DS.belongsTo`:
|
|
5891
|
+
|
|
5892
|
+
```javascript
|
|
5893
|
+
App.User = DS.Model.extend({
|
|
5894
|
+
profile: DS.belongsTo('profile')
|
|
5895
|
+
});
|
|
5896
|
+
|
|
5897
|
+
App.Profile = DS.Model.extend({
|
|
5898
|
+
user: DS.belongsTo('user')
|
|
5899
|
+
});
|
|
5900
|
+
```
|
|
5901
|
+
|
|
5902
|
+
#### One-To-Many
|
|
5903
|
+
To declare a one-to-many relationship between two models, use
|
|
5904
|
+
`DS.belongsTo` in combination with `DS.hasMany`, like this:
|
|
5905
|
+
|
|
5906
|
+
```javascript
|
|
5907
|
+
App.Post = DS.Model.extend({
|
|
5908
|
+
comments: DS.hasMany('comment')
|
|
5909
|
+
});
|
|
5910
|
+
|
|
5911
|
+
App.Comment = DS.Model.extend({
|
|
5912
|
+
post: DS.belongsTo('post')
|
|
5913
|
+
});
|
|
5914
|
+
```
|
|
5915
|
+
|
|
5916
|
+
@namespace
|
|
5917
|
+
@method belongsTo
|
|
5918
|
+
@for DS
|
|
5919
|
+
@param {String or DS.Model} type the model type of the relationship
|
|
5920
|
+
@param {Object} options a hash of options
|
|
5921
|
+
@return {Ember.computed} relationship
|
|
5922
|
+
*/
|
|
4681
5923
|
DS.belongsTo = function(type, options) {
|
|
4682
5924
|
if (typeof type === 'object') {
|
|
4683
5925
|
options = type;
|
|
@@ -4719,7 +5961,7 @@ DS.belongsTo = function(type, options) {
|
|
|
4719
5961
|
}).property('data').meta(meta);
|
|
4720
5962
|
};
|
|
4721
5963
|
|
|
4722
|
-
|
|
5964
|
+
/**
|
|
4723
5965
|
These observers observe all `belongsTo` relationships on the record. See
|
|
4724
5966
|
`relationships/ext` to see how these observers get their dependencies.
|
|
4725
5967
|
|
|
@@ -4785,23 +6027,30 @@ var get = Ember.get, set = Ember.set, setProperties = Ember.setProperties;
|
|
|
4785
6027
|
|
|
4786
6028
|
function asyncHasMany(type, options, meta) {
|
|
4787
6029
|
return Ember.computed(function(key, value) {
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
6030
|
+
var relationship = this._relationships[key],
|
|
6031
|
+
promiseLabel = "DS: Async hasMany " + this + " : " + key;
|
|
6032
|
+
|
|
6033
|
+
if (!relationship) {
|
|
6034
|
+
var resolver = Ember.RSVP.defer(promiseLabel);
|
|
6035
|
+
relationship = buildRelationship(this, key, options, function(store, data) {
|
|
6036
|
+
var link = data.links && data.links[key];
|
|
6037
|
+
var rel;
|
|
6038
|
+
if (link) {
|
|
6039
|
+
rel = store.findHasMany(this, link, meta, resolver);
|
|
6040
|
+
} else {
|
|
6041
|
+
rel = store.findMany(this, data[key], meta.type, resolver);
|
|
6042
|
+
}
|
|
6043
|
+
// cache the promise so we can use it
|
|
6044
|
+
// when we come back and don't need to rebuild
|
|
6045
|
+
// the relationship.
|
|
6046
|
+
set(rel, 'promise', resolver.promise);
|
|
6047
|
+
return rel;
|
|
6048
|
+
});
|
|
6049
|
+
}
|
|
4801
6050
|
|
|
4802
|
-
var promise =
|
|
6051
|
+
var promise = relationship.get('promise').then(function() {
|
|
4803
6052
|
return relationship;
|
|
4804
|
-
});
|
|
6053
|
+
}, null, "DS: Async hasMany records received");
|
|
4805
6054
|
|
|
4806
6055
|
return DS.PromiseArray.create({ promise: promise });
|
|
4807
6056
|
}).property('data').meta(meta);
|
|
@@ -4817,29 +6066,107 @@ function buildRelationship(record, key, options, callback) {
|
|
|
4817
6066
|
|
|
4818
6067
|
var relationship = rels[key] = callback.call(record, store, data);
|
|
4819
6068
|
|
|
4820
|
-
return setProperties(relationship, {
|
|
4821
|
-
owner: record, name: key, isPolymorphic: options.polymorphic
|
|
6069
|
+
return setProperties(relationship, {
|
|
6070
|
+
owner: record, name: key, isPolymorphic: options.polymorphic
|
|
6071
|
+
});
|
|
6072
|
+
}
|
|
6073
|
+
|
|
6074
|
+
function hasRelationship(type, options) {
|
|
6075
|
+
options = options || {};
|
|
6076
|
+
|
|
6077
|
+
var meta = { type: type, isRelationship: true, options: options, kind: 'hasMany' };
|
|
6078
|
+
|
|
6079
|
+
if (options.async) {
|
|
6080
|
+
return asyncHasMany(type, options, meta);
|
|
6081
|
+
}
|
|
6082
|
+
|
|
6083
|
+
return Ember.computed(function(key, value) {
|
|
6084
|
+
return buildRelationship(this, key, options, function(store, data) {
|
|
6085
|
+
var records = data[key];
|
|
6086
|
+
|
|
6087
|
+
return store.findMany(this, data[key], meta.type);
|
|
6088
|
+
});
|
|
6089
|
+
}).property('data').meta(meta);
|
|
6090
|
+
}
|
|
6091
|
+
|
|
6092
|
+
/**
|
|
6093
|
+
`DS.hasMany` is used to define One-To-Many and Many-To-Many
|
|
6094
|
+
relationships on a [DS.Model](DS.Model.html).
|
|
6095
|
+
|
|
6096
|
+
`DS.hasMany` takes an optional hash as a second parameter, currently
|
|
6097
|
+
supported options are:
|
|
6098
|
+
|
|
6099
|
+
- `async`: A boolean value used to explicitly declare this to be an async relationship.
|
|
6100
|
+
- `inverse`: A string used to identify the inverse property on a related model.
|
|
6101
|
+
|
|
6102
|
+
#### One-To-Many
|
|
6103
|
+
To declare a one-to-many relationship between two models, use
|
|
6104
|
+
`DS.belongsTo` in combination with `DS.hasMany`, like this:
|
|
6105
|
+
|
|
6106
|
+
```javascript
|
|
6107
|
+
App.Post = DS.Model.extend({
|
|
6108
|
+
comments: DS.hasMany('comment')
|
|
6109
|
+
});
|
|
6110
|
+
|
|
6111
|
+
App.Comment = DS.Model.extend({
|
|
6112
|
+
post: DS.belongsTo('post')
|
|
6113
|
+
});
|
|
6114
|
+
```
|
|
6115
|
+
|
|
6116
|
+
#### Many-To-Many
|
|
6117
|
+
To declare a many-to-many relationship between two models, use
|
|
6118
|
+
`DS.hasMany`:
|
|
6119
|
+
|
|
6120
|
+
```javascript
|
|
6121
|
+
App.Post = DS.Model.extend({
|
|
6122
|
+
tags: DS.hasMany('tag')
|
|
6123
|
+
});
|
|
6124
|
+
|
|
6125
|
+
App.Tag = DS.Model.extend({
|
|
6126
|
+
posts: DS.hasMany('post')
|
|
4822
6127
|
});
|
|
4823
|
-
|
|
6128
|
+
```
|
|
4824
6129
|
|
|
4825
|
-
|
|
4826
|
-
options = options || {};
|
|
6130
|
+
#### Explicit Inverses
|
|
4827
6131
|
|
|
4828
|
-
|
|
6132
|
+
Ember Data will do its best to discover which relationships map to
|
|
6133
|
+
one another. In the one-to-many code above, for example, Ember Data
|
|
6134
|
+
can figure out that changing the `comments` relationship should update
|
|
6135
|
+
the `post` relationship on the inverse because post is the only
|
|
6136
|
+
relationship to that model.
|
|
4829
6137
|
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
6138
|
+
However, sometimes you may have multiple `belongsTo`/`hasManys` for the
|
|
6139
|
+
same type. You can specify which property on the related model is
|
|
6140
|
+
the inverse using `DS.hasMany`'s `inverse` option:
|
|
4833
6141
|
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
6142
|
+
```javascript
|
|
6143
|
+
var belongsTo = DS.belongsTo,
|
|
6144
|
+
hasMany = DS.hasMany;
|
|
6145
|
+
|
|
6146
|
+
App.Comment = DS.Model.extend({
|
|
6147
|
+
onePost: belongsTo('post'),
|
|
6148
|
+
twoPost: belongsTo('post'),
|
|
6149
|
+
redPost: belongsTo('post'),
|
|
6150
|
+
bluePost: belongsTo('post')
|
|
6151
|
+
});
|
|
4837
6152
|
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
}
|
|
6153
|
+
App.Post = DS.Model.extend({
|
|
6154
|
+
comments: hasMany('comment', {
|
|
6155
|
+
inverse: 'redPost'
|
|
6156
|
+
})
|
|
6157
|
+
});
|
|
6158
|
+
```
|
|
4842
6159
|
|
|
6160
|
+
You can also specify an inverse on a `belongsTo`, which works how
|
|
6161
|
+
you'd expect.
|
|
6162
|
+
|
|
6163
|
+
@namespace
|
|
6164
|
+
@method hasMany
|
|
6165
|
+
@for DS
|
|
6166
|
+
@param {String or DS.Model} type the model type of the relationship
|
|
6167
|
+
@param {Object} options a hash of options
|
|
6168
|
+
@return {Ember.computed} relationship
|
|
6169
|
+
*/
|
|
4843
6170
|
DS.hasMany = function(type, options) {
|
|
4844
6171
|
if (typeof type === 'object') {
|
|
4845
6172
|
options = type;
|
|
@@ -4882,9 +6209,11 @@ DS.Model.reopen({
|
|
|
4882
6209
|
This hook passes the class being set up, as well as the key and value
|
|
4883
6210
|
being defined. So, for example, when the user does this:
|
|
4884
6211
|
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
6212
|
+
```javascript
|
|
6213
|
+
DS.Model.extend({
|
|
6214
|
+
parent: DS.belongsTo('user')
|
|
6215
|
+
});
|
|
6216
|
+
```
|
|
4888
6217
|
|
|
4889
6218
|
This hook would be called with "parent" as the key and the computed
|
|
4890
6219
|
property returned by `DS.belongsTo` as the value.
|
|
@@ -4936,9 +6265,11 @@ DS.Model.reopenClass({
|
|
|
4936
6265
|
|
|
4937
6266
|
For example, if you define a model like this:
|
|
4938
6267
|
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
6268
|
+
```javascript
|
|
6269
|
+
App.Post = DS.Model.extend({
|
|
6270
|
+
comments: DS.hasMany('comment')
|
|
6271
|
+
});
|
|
6272
|
+
```
|
|
4942
6273
|
|
|
4943
6274
|
Calling `App.Post.typeForRelationship('comments')` will return `App.Comment`.
|
|
4944
6275
|
|
|
@@ -5009,21 +6340,25 @@ DS.Model.reopenClass({
|
|
|
5009
6340
|
|
|
5010
6341
|
For example, given the following model definition:
|
|
5011
6342
|
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
6343
|
+
```javascript
|
|
6344
|
+
App.Blog = DS.Model.extend({
|
|
6345
|
+
users: DS.hasMany('user'),
|
|
6346
|
+
owner: DS.belongsTo('user'),
|
|
6347
|
+
posts: DS.hasMany('post')
|
|
6348
|
+
});
|
|
6349
|
+
```
|
|
5017
6350
|
|
|
5018
6351
|
This computed property would return a map describing these
|
|
5019
6352
|
relationships, like this:
|
|
5020
6353
|
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
6354
|
+
```javascript
|
|
6355
|
+
var relationships = Ember.get(App.Blog, 'relationships');
|
|
6356
|
+
relationships.get(App.User);
|
|
6357
|
+
//=> [ { name: 'users', kind: 'hasMany' },
|
|
6358
|
+
// { name: 'owner', kind: 'belongsTo' } ]
|
|
6359
|
+
relationships.get(App.Post);
|
|
6360
|
+
//=> [ { name: 'posts', kind: 'hasMany' } ]
|
|
6361
|
+
```
|
|
5027
6362
|
|
|
5028
6363
|
@property relationships
|
|
5029
6364
|
@static
|
|
@@ -5059,20 +6394,24 @@ DS.Model.reopenClass({
|
|
|
5059
6394
|
by the relationship kind. For example, given a model with this
|
|
5060
6395
|
definition:
|
|
5061
6396
|
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
6397
|
+
```javascript
|
|
6398
|
+
App.Blog = DS.Model.extend({
|
|
6399
|
+
users: DS.hasMany('user'),
|
|
6400
|
+
owner: DS.belongsTo('user'),
|
|
5065
6401
|
|
|
5066
|
-
|
|
5067
|
-
|
|
6402
|
+
posts: DS.hasMany('post')
|
|
6403
|
+
});
|
|
6404
|
+
```
|
|
5068
6405
|
|
|
5069
6406
|
This property would contain the following:
|
|
5070
6407
|
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
6408
|
+
```javascript
|
|
6409
|
+
var relationshipNames = Ember.get(App.Blog, 'relationshipNames');
|
|
6410
|
+
relationshipNames.hasMany;
|
|
6411
|
+
//=> ['users', 'posts']
|
|
6412
|
+
relationshipNames.belongsTo;
|
|
6413
|
+
//=> ['owner']
|
|
6414
|
+
```
|
|
5076
6415
|
|
|
5077
6416
|
@property relationshipNames
|
|
5078
6417
|
@static
|
|
@@ -5098,17 +6437,21 @@ DS.Model.reopenClass({
|
|
|
5098
6437
|
|
|
5099
6438
|
For example, given a model with this definition:
|
|
5100
6439
|
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
6440
|
+
```javascript
|
|
6441
|
+
App.Blog = DS.Model.extend({
|
|
6442
|
+
users: DS.hasMany('user'),
|
|
6443
|
+
owner: DS.belongsTo('user'),
|
|
6444
|
+
|
|
6445
|
+
posts: DS.hasMany('post')
|
|
6446
|
+
});
|
|
6447
|
+
```
|
|
5107
6448
|
|
|
5108
6449
|
This property would contain the following:
|
|
5109
6450
|
|
|
5110
|
-
|
|
5111
|
-
|
|
6451
|
+
```javascript
|
|
6452
|
+
var relatedTypes = Ember.get(App.Blog, 'relatedTypes');
|
|
6453
|
+
//=> [ App.User, App.Post ]
|
|
6454
|
+
```
|
|
5112
6455
|
|
|
5113
6456
|
@property relatedTypes
|
|
5114
6457
|
@static
|
|
@@ -5148,20 +6491,24 @@ DS.Model.reopenClass({
|
|
|
5148
6491
|
For example, given a model with this
|
|
5149
6492
|
definition:
|
|
5150
6493
|
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
6494
|
+
```javascript
|
|
6495
|
+
App.Blog = DS.Model.extend({
|
|
6496
|
+
users: DS.hasMany('user'),
|
|
6497
|
+
owner: DS.belongsTo('user'),
|
|
5154
6498
|
|
|
5155
|
-
|
|
5156
|
-
|
|
6499
|
+
posts: DS.hasMany('post')
|
|
6500
|
+
});
|
|
6501
|
+
```
|
|
5157
6502
|
|
|
5158
6503
|
This property would contain the following:
|
|
5159
6504
|
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
6505
|
+
```javascript
|
|
6506
|
+
var relationshipsByName = Ember.get(App.Blog, 'relationshipsByName');
|
|
6507
|
+
relationshipsByName.get('users');
|
|
6508
|
+
//=> { key: 'users', kind: 'hasMany', type: App.User }
|
|
6509
|
+
relationshipsByName.get('owner');
|
|
6510
|
+
//=> { key: 'owner', kind: 'belongsTo', type: App.User }
|
|
6511
|
+
```
|
|
5165
6512
|
|
|
5166
6513
|
@property relationshipsByName
|
|
5167
6514
|
@static
|
|
@@ -5200,25 +6547,28 @@ DS.Model.reopenClass({
|
|
|
5200
6547
|
|
|
5201
6548
|
For example:
|
|
5202
6549
|
|
|
5203
|
-
|
|
5204
|
-
users: DS.hasMany('user'),
|
|
5205
|
-
owner: DS.belongsTo('user'),
|
|
6550
|
+
```javascript
|
|
5206
6551
|
|
|
5207
|
-
|
|
6552
|
+
App.Blog = DS.Model.extend({
|
|
6553
|
+
users: DS.hasMany('user'),
|
|
6554
|
+
owner: DS.belongsTo('user'),
|
|
5208
6555
|
|
|
5209
|
-
|
|
5210
|
-
});
|
|
6556
|
+
posts: DS.hasMany('post'),
|
|
5211
6557
|
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
6558
|
+
title: DS.attr('string')
|
|
6559
|
+
});
|
|
6560
|
+
|
|
6561
|
+
var fields = Ember.get(App.Blog, 'fields');
|
|
6562
|
+
fields.forEach(function(field, kind) {
|
|
6563
|
+
console.log(field, kind);
|
|
6564
|
+
});
|
|
5216
6565
|
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
6566
|
+
// prints:
|
|
6567
|
+
// users, hasMany
|
|
6568
|
+
// owner, belongsTo
|
|
6569
|
+
// posts, hasMany
|
|
6570
|
+
// title, attribute
|
|
6571
|
+
```
|
|
5222
6572
|
|
|
5223
6573
|
@property fields
|
|
5224
6574
|
@static
|
|
@@ -5336,13 +6686,12 @@ DS.RecordArrayManager = Ember.Object.extend({
|
|
|
5336
6686
|
},
|
|
5337
6687
|
|
|
5338
6688
|
/**
|
|
5339
|
-
This method is invoked whenever data is loaded into the store
|
|
5340
|
-
|
|
5341
|
-
changes on a record.
|
|
6689
|
+
This method is invoked whenever data is loaded into the store by the
|
|
6690
|
+
adapter or updated by the adapter, or when a record has changed.
|
|
5342
6691
|
|
|
5343
|
-
It updates all
|
|
6692
|
+
It updates all record arrays that a record belongs to.
|
|
5344
6693
|
|
|
5345
|
-
To avoid thrashing, it only runs once per run loop
|
|
6694
|
+
To avoid thrashing, it only runs at most once per run loop.
|
|
5346
6695
|
|
|
5347
6696
|
@method updateRecordArrays
|
|
5348
6697
|
@param {Class} type
|
|
@@ -5350,29 +6699,47 @@ DS.RecordArrayManager = Ember.Object.extend({
|
|
|
5350
6699
|
*/
|
|
5351
6700
|
updateRecordArrays: function() {
|
|
5352
6701
|
forEach(this.changedRecords, function(record) {
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
6702
|
+
if (get(record, 'isDeleted')) {
|
|
6703
|
+
this._recordWasDeleted(record);
|
|
6704
|
+
} else {
|
|
6705
|
+
this._recordWasChanged(record);
|
|
6706
|
+
}
|
|
6707
|
+
}, this);
|
|
5356
6708
|
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
this.updateRecordArray(array, filter, type, record);
|
|
5360
|
-
}, this);
|
|
6709
|
+
this.changedRecords = [];
|
|
6710
|
+
},
|
|
5361
6711
|
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
var manyArrays = record._loadingRecordArrays;
|
|
6712
|
+
_recordWasDeleted: function (record) {
|
|
6713
|
+
var recordArrays = record._recordArrays;
|
|
5365
6714
|
|
|
5366
|
-
|
|
5367
|
-
for (var i=0, l=manyArrays.length; i<l; i++) {
|
|
5368
|
-
manyArrays[i].loadedRecord();
|
|
5369
|
-
}
|
|
6715
|
+
if (!recordArrays) { return; }
|
|
5370
6716
|
|
|
5371
|
-
|
|
5372
|
-
|
|
6717
|
+
forEach(recordArrays, function(array) {
|
|
6718
|
+
array.removeRecord(record);
|
|
6719
|
+
});
|
|
6720
|
+
},
|
|
6721
|
+
|
|
6722
|
+
_recordWasChanged: function (record) {
|
|
6723
|
+
var type = record.constructor,
|
|
6724
|
+
recordArrays = this.filteredRecordArrays.get(type),
|
|
6725
|
+
filter;
|
|
6726
|
+
|
|
6727
|
+
forEach(recordArrays, function(array) {
|
|
6728
|
+
filter = get(array, 'filterFunction');
|
|
6729
|
+
this.updateRecordArray(array, filter, type, record);
|
|
5373
6730
|
}, this);
|
|
5374
6731
|
|
|
5375
|
-
|
|
6732
|
+
// loop through all manyArrays containing an unloaded copy of this
|
|
6733
|
+
// clientId and notify them that the record was loaded.
|
|
6734
|
+
var manyArrays = record._loadingRecordArrays;
|
|
6735
|
+
|
|
6736
|
+
if (manyArrays) {
|
|
6737
|
+
for (var i=0, l=manyArrays.length; i<l; i++) {
|
|
6738
|
+
manyArrays[i].loadedRecord();
|
|
6739
|
+
}
|
|
6740
|
+
|
|
6741
|
+
record._loadingRecordArrays = [];
|
|
6742
|
+
}
|
|
5376
6743
|
},
|
|
5377
6744
|
|
|
5378
6745
|
/**
|
|
@@ -5404,23 +6771,6 @@ DS.RecordArrayManager = Ember.Object.extend({
|
|
|
5404
6771
|
}
|
|
5405
6772
|
},
|
|
5406
6773
|
|
|
5407
|
-
/**
|
|
5408
|
-
When a record is deleted, it is removed from all its
|
|
5409
|
-
record arrays.
|
|
5410
|
-
|
|
5411
|
-
@method remove
|
|
5412
|
-
@param {DS.Model} record
|
|
5413
|
-
*/
|
|
5414
|
-
remove: function(record) {
|
|
5415
|
-
var recordArrays = record._recordArrays;
|
|
5416
|
-
|
|
5417
|
-
if (!recordArrays) { return; }
|
|
5418
|
-
|
|
5419
|
-
forEach(recordArrays, function(array) {
|
|
5420
|
-
array.removeRecord(record);
|
|
5421
|
-
});
|
|
5422
|
-
},
|
|
5423
|
-
|
|
5424
6774
|
/**
|
|
5425
6775
|
This method is invoked if the `filterFunction` property is
|
|
5426
6776
|
changed on a `DS.FilteredRecordArray`.
|
|
@@ -5535,15 +6885,19 @@ DS.InvalidError.prototype = Ember.create(Error.prototype);
|
|
|
5535
6885
|
|
|
5536
6886
|
First, create a new subclass of `DS.Adapter`:
|
|
5537
6887
|
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
6888
|
+
```javascript
|
|
6889
|
+
App.MyAdapter = DS.Adapter.extend({
|
|
6890
|
+
// ...your code here
|
|
6891
|
+
});
|
|
6892
|
+
```
|
|
5541
6893
|
|
|
5542
6894
|
To tell your store which adapter to use, set its `adapter` property:
|
|
5543
6895
|
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
6896
|
+
```javascript
|
|
6897
|
+
App.store = DS.Store.create({
|
|
6898
|
+
adapter: App.MyAdapter.create()
|
|
6899
|
+
});
|
|
6900
|
+
```
|
|
5547
6901
|
|
|
5548
6902
|
`DS.Adapter` is an abstract base class that you should override in your
|
|
5549
6903
|
application to customize it for your backend. The minimum set of methods
|
|
@@ -5569,10 +6923,9 @@ DS.InvalidError.prototype = Ember.create(Error.prototype);
|
|
|
5569
6923
|
@class Adapter
|
|
5570
6924
|
@namespace DS
|
|
5571
6925
|
@extends Ember.Object
|
|
5572
|
-
@uses DS._Mappable
|
|
5573
6926
|
*/
|
|
5574
6927
|
|
|
5575
|
-
DS.Adapter = Ember.Object.extend(
|
|
6928
|
+
DS.Adapter = Ember.Object.extend({
|
|
5576
6929
|
|
|
5577
6930
|
/**
|
|
5578
6931
|
The `find()` method is invoked when the store is asked for a record that
|
|
@@ -5583,25 +6936,27 @@ DS.Adapter = Ember.Object.extend(DS._Mappable, {
|
|
|
5583
6936
|
|
|
5584
6937
|
Here is an example `find` implementation:
|
|
5585
6938
|
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
6939
|
+
```javascript
|
|
6940
|
+
find: function(store, type, id) {
|
|
6941
|
+
var url = type.url;
|
|
6942
|
+
url = url.fmt(id);
|
|
5589
6943
|
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
6944
|
+
jQuery.getJSON(url, function(data) {
|
|
6945
|
+
// data is a hash of key/value pairs. If your server returns a
|
|
6946
|
+
// root, simply do something like:
|
|
6947
|
+
// store.push(type, id, data.person)
|
|
6948
|
+
store.push(type, id, data);
|
|
6949
|
+
});
|
|
6950
|
+
}
|
|
6951
|
+
```
|
|
5597
6952
|
|
|
5598
6953
|
@method find
|
|
5599
6954
|
*/
|
|
5600
6955
|
find: Ember.required(Function),
|
|
5601
6956
|
|
|
5602
6957
|
/**
|
|
5603
|
-
Optional
|
|
5604
6958
|
|
|
6959
|
+
@private
|
|
5605
6960
|
@method findAll
|
|
5606
6961
|
@param store
|
|
5607
6962
|
@param type
|
|
@@ -5610,8 +6965,8 @@ DS.Adapter = Ember.Object.extend(DS._Mappable, {
|
|
|
5610
6965
|
findAll: null,
|
|
5611
6966
|
|
|
5612
6967
|
/**
|
|
5613
|
-
Optional
|
|
5614
6968
|
|
|
6969
|
+
@private
|
|
5615
6970
|
@method findQuery
|
|
5616
6971
|
@param store
|
|
5617
6972
|
@param type
|
|
@@ -5634,10 +6989,12 @@ DS.Adapter = Ember.Object.extend(DS._Mappable, {
|
|
|
5634
6989
|
The `generateIdForRecord()` method will be invoked with the requesting store as
|
|
5635
6990
|
the first parameter and the newly created record as the second parameter:
|
|
5636
6991
|
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
6992
|
+
```javascript
|
|
6993
|
+
generateIdForRecord: function(store, record) {
|
|
6994
|
+
var uuid = App.generateUUIDWithStatisticallyLowOddsOfCollision();
|
|
6995
|
+
return uuid;
|
|
6996
|
+
}
|
|
6997
|
+
```
|
|
5641
6998
|
|
|
5642
6999
|
@method generateIdForRecord
|
|
5643
7000
|
@param {DS.Store} store
|
|
@@ -5870,6 +7227,7 @@ DS.FixtureAdapter = DS.Adapter.extend({
|
|
|
5870
7227
|
},
|
|
5871
7228
|
|
|
5872
7229
|
/**
|
|
7230
|
+
@private
|
|
5873
7231
|
@method findAll
|
|
5874
7232
|
@param store
|
|
5875
7233
|
@param type
|
|
@@ -5884,6 +7242,7 @@ DS.FixtureAdapter = DS.Adapter.extend({
|
|
|
5884
7242
|
},
|
|
5885
7243
|
|
|
5886
7244
|
/**
|
|
7245
|
+
@private
|
|
5887
7246
|
@method findQuery
|
|
5888
7247
|
@param store
|
|
5889
7248
|
@param type
|
|
@@ -6014,11 +7373,11 @@ DS.FixtureAdapter = DS.Adapter.extend({
|
|
|
6014
7373
|
}, get(adapter, 'latency'));
|
|
6015
7374
|
} else {
|
|
6016
7375
|
// Asynchronous, but at the of the runloop with zero latency
|
|
6017
|
-
Ember.run.
|
|
7376
|
+
Ember.run.schedule('actions', null, function() {
|
|
6018
7377
|
resolve(callback.call(context));
|
|
6019
7378
|
});
|
|
6020
7379
|
}
|
|
6021
|
-
});
|
|
7380
|
+
}, "DS: FixtureAdapter#simulateRemoteCall");
|
|
6022
7381
|
}
|
|
6023
7382
|
});
|
|
6024
7383
|
|
|
@@ -6140,9 +7499,9 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
|
6140
7499
|
|
|
6141
7500
|
@method normalize
|
|
6142
7501
|
@param {subclass of DS.Model} type
|
|
6143
|
-
@param {String} prop
|
|
6144
7502
|
@param {Object} hash
|
|
6145
|
-
@
|
|
7503
|
+
@param {String} prop
|
|
7504
|
+
@returns {Object}
|
|
6146
7505
|
*/
|
|
6147
7506
|
normalize: function(type, hash, prop) {
|
|
6148
7507
|
this.normalizeId(hash);
|
|
@@ -6151,7 +7510,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
|
6151
7510
|
this.normalizeRelationships(type, hash);
|
|
6152
7511
|
|
|
6153
7512
|
if (this.normalizeHash && this.normalizeHash[prop]) {
|
|
6154
|
-
|
|
7513
|
+
this.normalizeHash[prop](hash);
|
|
6155
7514
|
}
|
|
6156
7515
|
|
|
6157
7516
|
return this._super(type, hash, prop);
|
|
@@ -6176,7 +7535,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
|
6176
7535
|
@method normalizePayload
|
|
6177
7536
|
@param {subclass of DS.Model} type
|
|
6178
7537
|
@param {Object} hash
|
|
6179
|
-
@returns Object the normalized payload
|
|
7538
|
+
@returns {Object} the normalized payload
|
|
6180
7539
|
*/
|
|
6181
7540
|
normalizePayload: function(type, payload) {
|
|
6182
7541
|
return payload;
|
|
@@ -6323,7 +7682,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
|
6323
7682
|
@param {Object} payload
|
|
6324
7683
|
@param {String} id
|
|
6325
7684
|
@param {'find'|'createRecord'|'updateRecord'|'deleteRecord'} requestType
|
|
6326
|
-
@returns Object the primary response to the original request
|
|
7685
|
+
@returns {Object} the primary response to the original request
|
|
6327
7686
|
*/
|
|
6328
7687
|
extractSingle: function(store, primaryType, payload, recordId, requestType) {
|
|
6329
7688
|
payload = this.normalizePayload(primaryType, payload);
|
|
@@ -6469,7 +7828,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
|
6469
7828
|
@param {subclass of DS.Model} type
|
|
6470
7829
|
@param {Object} payload
|
|
6471
7830
|
@param {'findAll'|'findMany'|'findHasMany'|'findQuery'} requestType
|
|
6472
|
-
@returns {Array
|
|
7831
|
+
@returns {Array} The primary array that was returned in response
|
|
6473
7832
|
to the original query.
|
|
6474
7833
|
*/
|
|
6475
7834
|
extractArray: function(store, primaryType, payload) {
|
|
@@ -6521,7 +7880,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
|
6521
7880
|
}],
|
|
6522
7881
|
"comments": [{
|
|
6523
7882
|
"id": "1",
|
|
6524
|
-
"body": "FIRST
|
|
7883
|
+
"body": "FIRST"
|
|
6525
7884
|
}],
|
|
6526
7885
|
"users": [{
|
|
6527
7886
|
"id": "1",
|
|
@@ -6572,7 +7931,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
|
6572
7931
|
|
|
6573
7932
|
@method typeForRoot
|
|
6574
7933
|
@param {String} root
|
|
6575
|
-
@returns String the model's typeKey
|
|
7934
|
+
@returns {String} the model's typeKey
|
|
6576
7935
|
*/
|
|
6577
7936
|
typeForRoot: function(root) {
|
|
6578
7937
|
return Ember.String.singularize(root);
|
|
@@ -6758,7 +8117,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
|
6758
8117
|
@method serializePolymorphicType
|
|
6759
8118
|
@param {DS.Model} record
|
|
6760
8119
|
@param {Object} json
|
|
6761
|
-
@param relationship
|
|
8120
|
+
@param {Object} relationship
|
|
6762
8121
|
*/
|
|
6763
8122
|
serializePolymorphicType: function(record, json, relationship) {
|
|
6764
8123
|
var key = relationship.key,
|
|
@@ -6810,7 +8169,7 @@ var forEach = Ember.ArrayPolyfills.forEach;
|
|
|
6810
8169
|
|
|
6811
8170
|
### Conventional Names
|
|
6812
8171
|
|
|
6813
|
-
Attribute names in your JSON payload should be the
|
|
8172
|
+
Attribute names in your JSON payload should be the camelCased versions of
|
|
6814
8173
|
the attributes in your Ember.js models.
|
|
6815
8174
|
|
|
6816
8175
|
For example, if you have a `Person` model:
|
|
@@ -6861,14 +8220,14 @@ var forEach = Ember.ArrayPolyfills.forEach;
|
|
|
6861
8220
|
|
|
6862
8221
|
### Headers customization
|
|
6863
8222
|
|
|
6864
|
-
Some APIs require HTTP headers,
|
|
8223
|
+
Some APIs require HTTP headers, e.g. to provide an API key. An array of
|
|
6865
8224
|
headers can be added to the adapter which are passed with every request:
|
|
6866
8225
|
|
|
6867
8226
|
```js
|
|
6868
8227
|
DS.RESTAdapter.reopen({
|
|
6869
8228
|
headers: {
|
|
6870
8229
|
"API_KEY": "secret key",
|
|
6871
|
-
"ANOTHER_HEADER": "
|
|
8230
|
+
"ANOTHER_HEADER": "Some header value"
|
|
6872
8231
|
}
|
|
6873
8232
|
});
|
|
6874
8233
|
```
|
|
@@ -6885,9 +8244,11 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
|
6885
8244
|
Called by the store in order to fetch the JSON for a given
|
|
6886
8245
|
type and ID.
|
|
6887
8246
|
|
|
6888
|
-
|
|
8247
|
+
The `find` method makes an Ajax request to a URL computed by `buildURL`, and returns a
|
|
6889
8248
|
promise for the resulting payload.
|
|
6890
8249
|
|
|
8250
|
+
This method performs an HTTP `GET` request with the id provided as part of the querystring.
|
|
8251
|
+
|
|
6891
8252
|
@method find
|
|
6892
8253
|
@see RESTAdapter/buildURL
|
|
6893
8254
|
@see RESTAdapter/ajax
|
|
@@ -6904,9 +8265,10 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
|
6904
8265
|
Called by the store in order to fetch a JSON array for all
|
|
6905
8266
|
of the records for a given type.
|
|
6906
8267
|
|
|
6907
|
-
|
|
8268
|
+
The `findAll` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a
|
|
6908
8269
|
promise for the resulting payload.
|
|
6909
8270
|
|
|
8271
|
+
@private
|
|
6910
8272
|
@method findAll
|
|
6911
8273
|
@see RESTAdapter/buildURL
|
|
6912
8274
|
@see RESTAdapter/ajax
|
|
@@ -6929,12 +8291,13 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
|
6929
8291
|
Called by the store in order to fetch a JSON array for
|
|
6930
8292
|
the records that match a particular query.
|
|
6931
8293
|
|
|
6932
|
-
The
|
|
6933
|
-
to the server as parameters.
|
|
6934
|
-
|
|
6935
|
-
It makes an Ajax request to a URL computed by `buildURL`, and returns a
|
|
8294
|
+
The `findQuery` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a
|
|
6936
8295
|
promise for the resulting payload.
|
|
6937
8296
|
|
|
8297
|
+
The `query` argument is a simple JavaScript object that will be passed directly
|
|
8298
|
+
to the server as parameters.
|
|
8299
|
+
|
|
8300
|
+
@private
|
|
6938
8301
|
@method findQuery
|
|
6939
8302
|
@see RESTAdapter/buildURL
|
|
6940
8303
|
@see RESTAdapter/ajax
|
|
@@ -6968,11 +8331,11 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
|
6968
8331
|
ids[]=1&ids[]=2&ids[]=3
|
|
6969
8332
|
```
|
|
6970
8333
|
|
|
6971
|
-
Many servers, such as Rails and PHP, will automatically convert this
|
|
8334
|
+
Many servers, such as Rails and PHP, will automatically convert this URL-encoded array
|
|
6972
8335
|
into an Array for you on the server-side. If you want to encode the
|
|
6973
8336
|
IDs, differently, just override this (one-line) method.
|
|
6974
8337
|
|
|
6975
|
-
|
|
8338
|
+
The `findMany` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a
|
|
6976
8339
|
promise for the resulting payload.
|
|
6977
8340
|
|
|
6978
8341
|
@method findMany
|
|
@@ -7006,7 +8369,7 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
|
7006
8369
|
|
|
7007
8370
|
This method will be called with the parent record and `/posts/1/comments`.
|
|
7008
8371
|
|
|
7009
|
-
|
|
8372
|
+
The `findHasMany` method will make an Ajax (HTTP GET) request to the originally specified URL.
|
|
7010
8373
|
If the URL is host-relative (starting with a single slash), the
|
|
7011
8374
|
request will use the host specified on the adapter (if any).
|
|
7012
8375
|
|
|
@@ -7049,7 +8412,7 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
|
7049
8412
|
|
|
7050
8413
|
This method will be called with the parent record and `/people/1/group`.
|
|
7051
8414
|
|
|
7052
|
-
|
|
8415
|
+
The `findBelongsTo` method will make an Ajax (HTTP GET) request to the originally specified URL.
|
|
7053
8416
|
|
|
7054
8417
|
@method findBelongsTo
|
|
7055
8418
|
@see RESTAdapter/buildURL
|
|
@@ -7068,9 +8431,10 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
|
7068
8431
|
|
|
7069
8432
|
/**
|
|
7070
8433
|
Called by the store when a newly created record is
|
|
7071
|
-
`save`
|
|
8434
|
+
saved via the `save` method on a model record instance.
|
|
7072
8435
|
|
|
7073
|
-
|
|
8436
|
+
The `createRecord` method serializes the record and makes an Ajax (HTTP POST) request
|
|
8437
|
+
to a URL computed by `buildURL`.
|
|
7074
8438
|
|
|
7075
8439
|
See `serialize` for information on how to customize the serialized form
|
|
7076
8440
|
of a record.
|
|
@@ -7094,9 +8458,11 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
|
7094
8458
|
},
|
|
7095
8459
|
|
|
7096
8460
|
/**
|
|
7097
|
-
Called by the store when an existing record is
|
|
8461
|
+
Called by the store when an existing record is saved
|
|
8462
|
+
via the `save` method on a model record instance.
|
|
7098
8463
|
|
|
7099
|
-
|
|
8464
|
+
The `updateRecord` method serializes the record and makes an Ajax (HTTP PUT) request
|
|
8465
|
+
to a URL computed by `buildURL`.
|
|
7100
8466
|
|
|
7101
8467
|
See `serialize` for information on how to customize the serialized form
|
|
7102
8468
|
of a record.
|
|
@@ -7122,9 +8488,9 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
|
7122
8488
|
},
|
|
7123
8489
|
|
|
7124
8490
|
/**
|
|
7125
|
-
Called by the store when
|
|
8491
|
+
Called by the store when a record is deleted.
|
|
7126
8492
|
|
|
7127
|
-
|
|
8493
|
+
The `deleteRecord` method makes an Ajax (HTTP DELETE) request to a URL computed by `buildURL`.
|
|
7128
8494
|
|
|
7129
8495
|
@method deleteRecord
|
|
7130
8496
|
@see RESTAdapter/buildURL
|
|
@@ -7230,9 +8596,9 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
|
7230
8596
|
/**
|
|
7231
8597
|
Takes an ajax response, and returns a relavant error.
|
|
7232
8598
|
|
|
7233
|
-
By default,
|
|
8599
|
+
By default, the `ajaxError` method has the following behavior:
|
|
7234
8600
|
|
|
7235
|
-
* It simply returns the ajax response.
|
|
8601
|
+
* It simply returns the ajax response (jqXHR).
|
|
7236
8602
|
|
|
7237
8603
|
@method ajaxError
|
|
7238
8604
|
@param jqXHR
|
|
@@ -7253,7 +8619,7 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
|
7253
8619
|
or `extractArray` (depending on whether the original query was for one record or
|
|
7254
8620
|
many records).
|
|
7255
8621
|
|
|
7256
|
-
By default,
|
|
8622
|
+
By default, `ajax` method has the following behavior:
|
|
7257
8623
|
|
|
7258
8624
|
* It sets the response `dataType` to `"json"`
|
|
7259
8625
|
* If the HTTP method is not `"GET"`, it sets the `Content-Type` to be
|
|
@@ -7283,7 +8649,7 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
|
7283
8649
|
};
|
|
7284
8650
|
|
|
7285
8651
|
Ember.$.ajax(hash);
|
|
7286
|
-
});
|
|
8652
|
+
}, "DS: RestAdapter#ajax " + type + " to " + url);
|
|
7287
8653
|
},
|
|
7288
8654
|
|
|
7289
8655
|
ajaxOptions: function(url, type, hash) {
|
|
@@ -7435,7 +8801,7 @@ var BLANK_REGEX = /^\s*$/;
|
|
|
7435
8801
|
|
|
7436
8802
|
function loadUncountable(rules, uncountable) {
|
|
7437
8803
|
for (var i = 0, length = uncountable.length; i < length; i++) {
|
|
7438
|
-
rules.uncountable[uncountable[i]] = true;
|
|
8804
|
+
rules.uncountable[uncountable[i].toLowerCase()] = true;
|
|
7439
8805
|
}
|
|
7440
8806
|
}
|
|
7441
8807
|
|
|
@@ -7445,8 +8811,8 @@ function loadIrregular(rules, irregularPairs) {
|
|
|
7445
8811
|
for (var i = 0, length = irregularPairs.length; i < length; i++) {
|
|
7446
8812
|
pair = irregularPairs[i];
|
|
7447
8813
|
|
|
7448
|
-
rules.irregular[pair[0]] = pair[1];
|
|
7449
|
-
rules.irregularInverse[pair[1]] = pair[0];
|
|
8814
|
+
rules.irregular[pair[0].toLowerCase()] = pair[1];
|
|
8815
|
+
rules.irregularInverse[pair[1].toLowerCase()] = pair[0];
|
|
7450
8816
|
}
|
|
7451
8817
|
}
|
|
7452
8818
|
|
|
@@ -7511,7 +8877,7 @@ function loadIrregular(rules, irregularPairs) {
|
|
|
7511
8877
|
function Inflector(ruleSet) {
|
|
7512
8878
|
ruleSet = ruleSet || {};
|
|
7513
8879
|
ruleSet.uncountable = ruleSet.uncountable || {};
|
|
7514
|
-
ruleSet.irregularPairs= ruleSet.irregularPairs|| {};
|
|
8880
|
+
ruleSet.irregularPairs = ruleSet.irregularPairs || {};
|
|
7515
8881
|
|
|
7516
8882
|
var rules = this.rules = {
|
|
7517
8883
|
plurals: ruleSet.plurals || [],
|
|
@@ -7532,7 +8898,7 @@ Inflector.prototype = {
|
|
|
7532
8898
|
@param {String} string
|
|
7533
8899
|
*/
|
|
7534
8900
|
plural: function(regex, string) {
|
|
7535
|
-
this.rules.plurals.push([regex, string]);
|
|
8901
|
+
this.rules.plurals.push([regex, string.toLowerCase()]);
|
|
7536
8902
|
},
|
|
7537
8903
|
|
|
7538
8904
|
/**
|
|
@@ -7541,7 +8907,7 @@ Inflector.prototype = {
|
|
|
7541
8907
|
@param {String} string
|
|
7542
8908
|
*/
|
|
7543
8909
|
singular: function(regex, string) {
|
|
7544
|
-
this.rules.singular.push([regex, string]);
|
|
8910
|
+
this.rules.singular.push([regex, string.toLowerCase()]);
|
|
7545
8911
|
},
|
|
7546
8912
|
|
|
7547
8913
|
/**
|
|
@@ -7549,7 +8915,7 @@ Inflector.prototype = {
|
|
|
7549
8915
|
@param {String} regex
|
|
7550
8916
|
*/
|
|
7551
8917
|
uncountable: function(string) {
|
|
7552
|
-
loadUncountable(this.rules, [string]);
|
|
8918
|
+
loadUncountable(this.rules, [string.toLowerCase()]);
|
|
7553
8919
|
},
|
|
7554
8920
|
|
|
7555
8921
|
/**
|
|
@@ -7720,27 +9086,27 @@ Ember.Inflector.defaultRules = {
|
|
|
7720
9086
|
|
|
7721
9087
|
|
|
7722
9088
|
(function() {
|
|
7723
|
-
if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) {
|
|
7724
|
-
/**
|
|
7725
|
-
See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}}
|
|
7726
|
-
|
|
7727
|
-
@method pluralize
|
|
7728
|
-
@for String
|
|
7729
|
-
*/
|
|
7730
|
-
String.prototype.pluralize = function() {
|
|
7731
|
-
return Ember.String.pluralize(this);
|
|
7732
|
-
};
|
|
7733
|
-
|
|
7734
|
-
/**
|
|
7735
|
-
See {{#crossLink "Ember.String/singularize"}}{{/crossLink}}
|
|
7736
|
-
|
|
7737
|
-
@method singularize
|
|
7738
|
-
@for String
|
|
7739
|
-
*/
|
|
7740
|
-
String.prototype.singularize = function() {
|
|
7741
|
-
return Ember.String.singularize(this);
|
|
7742
|
-
};
|
|
7743
|
-
}
|
|
9089
|
+
if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) {
|
|
9090
|
+
/**
|
|
9091
|
+
See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}}
|
|
9092
|
+
|
|
9093
|
+
@method pluralize
|
|
9094
|
+
@for String
|
|
9095
|
+
*/
|
|
9096
|
+
String.prototype.pluralize = function() {
|
|
9097
|
+
return Ember.String.pluralize(this);
|
|
9098
|
+
};
|
|
9099
|
+
|
|
9100
|
+
/**
|
|
9101
|
+
See {{#crossLink "Ember.String/singularize"}}{{/crossLink}}
|
|
9102
|
+
|
|
9103
|
+
@method singularize
|
|
9104
|
+
@for String
|
|
9105
|
+
*/
|
|
9106
|
+
String.prototype.singularize = function() {
|
|
9107
|
+
return Ember.String.singularize(this);
|
|
9108
|
+
};
|
|
9109
|
+
}
|
|
7744
9110
|
|
|
7745
9111
|
})();
|
|
7746
9112
|
|
|
@@ -7800,26 +9166,9 @@ DS.ActiveModelSerializer = DS.RESTSerializer.extend({
|
|
|
7800
9166
|
},
|
|
7801
9167
|
|
|
7802
9168
|
/**
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
@method serializeHasMany
|
|
9169
|
+
Does not serialize hasMany relationships by default.
|
|
7806
9170
|
*/
|
|
7807
|
-
serializeHasMany:
|
|
7808
|
-
var key = relationship.key,
|
|
7809
|
-
attrs = get(this, 'attrs'),
|
|
7810
|
-
embed = attrs && attrs[key] && attrs[key].embedded === 'always';
|
|
7811
|
-
|
|
7812
|
-
if (embed) {
|
|
7813
|
-
json[this.keyForAttribute(key)] = get(record, key).map(function(relation) {
|
|
7814
|
-
var data = relation.serialize(),
|
|
7815
|
-
primaryKey = get(this, 'primaryKey');
|
|
7816
|
-
|
|
7817
|
-
data[primaryKey] = get(relation, primaryKey);
|
|
7818
|
-
|
|
7819
|
-
return data;
|
|
7820
|
-
}, this);
|
|
7821
|
-
}
|
|
7822
|
-
},
|
|
9171
|
+
serializeHasMany: Ember.K,
|
|
7823
9172
|
|
|
7824
9173
|
/**
|
|
7825
9174
|
Underscores the JSON root keys when serializing.
|
|
@@ -7864,6 +9213,68 @@ DS.ActiveModelSerializer = DS.RESTSerializer.extend({
|
|
|
7864
9213
|
return Ember.String.singularize(camelized);
|
|
7865
9214
|
},
|
|
7866
9215
|
|
|
9216
|
+
/**
|
|
9217
|
+
Add extra step to `DS.RESTSerializer.normalize` so links are
|
|
9218
|
+
normalized.
|
|
9219
|
+
|
|
9220
|
+
If your payload looks like this
|
|
9221
|
+
|
|
9222
|
+
```js
|
|
9223
|
+
{
|
|
9224
|
+
"post": {
|
|
9225
|
+
"id": 1,
|
|
9226
|
+
"title": "Rails is omakase",
|
|
9227
|
+
"links": { "flagged_comments": "api/comments/flagged" }
|
|
9228
|
+
}
|
|
9229
|
+
}
|
|
9230
|
+
```
|
|
9231
|
+
The normalized version would look like this
|
|
9232
|
+
|
|
9233
|
+
```js
|
|
9234
|
+
{
|
|
9235
|
+
"post": {
|
|
9236
|
+
"id": 1,
|
|
9237
|
+
"title": "Rails is omakase",
|
|
9238
|
+
"links": { "flaggedComments": "api/comments/flagged" }
|
|
9239
|
+
}
|
|
9240
|
+
}
|
|
9241
|
+
```
|
|
9242
|
+
|
|
9243
|
+
@method normalize
|
|
9244
|
+
@param {subclass of DS.Model} type
|
|
9245
|
+
@param {Object} hash
|
|
9246
|
+
@param {String} prop
|
|
9247
|
+
@returns Object
|
|
9248
|
+
*/
|
|
9249
|
+
|
|
9250
|
+
normalize: function(type, hash, prop) {
|
|
9251
|
+
this.normalizeLinks(hash);
|
|
9252
|
+
|
|
9253
|
+
return this._super(type, hash, prop);
|
|
9254
|
+
},
|
|
9255
|
+
|
|
9256
|
+
/**
|
|
9257
|
+
Convert `snake_cased` links to `camelCase`
|
|
9258
|
+
|
|
9259
|
+
@method normalizeLinks
|
|
9260
|
+
@param {Object} hash
|
|
9261
|
+
*/
|
|
9262
|
+
|
|
9263
|
+
normalizeLinks: function(data){
|
|
9264
|
+
if (data.links) {
|
|
9265
|
+
var links = data.links;
|
|
9266
|
+
|
|
9267
|
+
for (var link in links) {
|
|
9268
|
+
var camelizedLink = Ember.String.camelize(link);
|
|
9269
|
+
|
|
9270
|
+
if (camelizedLink !== link) {
|
|
9271
|
+
links[camelizedLink] = links[link];
|
|
9272
|
+
delete links[link];
|
|
9273
|
+
}
|
|
9274
|
+
}
|
|
9275
|
+
}
|
|
9276
|
+
},
|
|
9277
|
+
|
|
7867
9278
|
/**
|
|
7868
9279
|
Normalize the polymorphic type from the JSON.
|
|
7869
9280
|
|
|
@@ -7914,8 +9325,66 @@ DS.ActiveModelSerializer = DS.RESTSerializer.extend({
|
|
|
7914
9325
|
}
|
|
7915
9326
|
}, this);
|
|
7916
9327
|
}
|
|
9328
|
+
}
|
|
9329
|
+
});
|
|
9330
|
+
|
|
9331
|
+
})();
|
|
9332
|
+
|
|
9333
|
+
|
|
9334
|
+
|
|
9335
|
+
(function() {
|
|
9336
|
+
var get = Ember.get;
|
|
9337
|
+
var forEach = Ember.EnumerableUtils.forEach;
|
|
9338
|
+
|
|
9339
|
+
/**
|
|
9340
|
+
The EmbeddedRecordsMixin allows you to add embedded record support to your
|
|
9341
|
+
serializers.
|
|
9342
|
+
To set up embedded records, you include the mixin into the serializer and then
|
|
9343
|
+
define your embedded relations.
|
|
9344
|
+
|
|
9345
|
+
```js
|
|
9346
|
+
App.PostSerializer = DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, {
|
|
9347
|
+
attrs: {
|
|
9348
|
+
comments: {embedded: 'always'}
|
|
9349
|
+
}
|
|
9350
|
+
})
|
|
9351
|
+
```
|
|
9352
|
+
|
|
9353
|
+
Currently only `{embedded: 'always'}` records are supported.
|
|
9354
|
+
|
|
9355
|
+
@class EmbeddedRecordsMixin
|
|
9356
|
+
@namespace DS
|
|
9357
|
+
*/
|
|
9358
|
+
DS.EmbeddedRecordsMixin = Ember.Mixin.create({
|
|
9359
|
+
|
|
9360
|
+
/**
|
|
9361
|
+
Serialize has-may relationship when it is configured as embedded objects.
|
|
9362
|
+
|
|
9363
|
+
@method serializeHasMany
|
|
9364
|
+
*/
|
|
9365
|
+
serializeHasMany: function(record, json, relationship) {
|
|
9366
|
+
var key = relationship.key,
|
|
9367
|
+
attrs = get(this, 'attrs'),
|
|
9368
|
+
embed = attrs && attrs[key] && attrs[key].embedded === 'always';
|
|
9369
|
+
|
|
9370
|
+
if (embed) {
|
|
9371
|
+
json[this.keyForAttribute(key)] = get(record, key).map(function(relation) {
|
|
9372
|
+
var data = relation.serialize(),
|
|
9373
|
+
primaryKey = get(this, 'primaryKey');
|
|
9374
|
+
|
|
9375
|
+
data[primaryKey] = get(relation, primaryKey);
|
|
9376
|
+
|
|
9377
|
+
return data;
|
|
9378
|
+
}, this);
|
|
9379
|
+
}
|
|
7917
9380
|
},
|
|
7918
9381
|
|
|
9382
|
+
/**
|
|
9383
|
+
Extract embedded objects out of the payload for a single object
|
|
9384
|
+
and add them as sideloaded objects instead.
|
|
9385
|
+
|
|
9386
|
+
@method extractSingle
|
|
9387
|
+
*/
|
|
7919
9388
|
extractSingle: function(store, primaryType, payload, recordId, requestType) {
|
|
7920
9389
|
var root = this.keyForAttribute(primaryType.typeKey),
|
|
7921
9390
|
partial = payload[root];
|
|
@@ -7925,6 +9394,12 @@ DS.ActiveModelSerializer = DS.RESTSerializer.extend({
|
|
|
7925
9394
|
return this._super(store, primaryType, payload, recordId, requestType);
|
|
7926
9395
|
},
|
|
7927
9396
|
|
|
9397
|
+
/**
|
|
9398
|
+
Extract embedded objects out of a standard payload
|
|
9399
|
+
and add them as sideloaded objects instead.
|
|
9400
|
+
|
|
9401
|
+
@method extractArray
|
|
9402
|
+
*/
|
|
7928
9403
|
extractArray: function(store, type, payload) {
|
|
7929
9404
|
var root = this.keyForAttribute(type.typeKey),
|
|
7930
9405
|
partials = payload[Ember.String.pluralize(root)];
|
|
@@ -7980,7 +9455,6 @@ function updatePayloadWithEmbedded(store, serializer, type, partial, payload) {
|
|
|
7980
9455
|
}
|
|
7981
9456
|
}, serializer);
|
|
7982
9457
|
}
|
|
7983
|
-
|
|
7984
9458
|
})();
|
|
7985
9459
|
|
|
7986
9460
|
|
|
@@ -7999,6 +9473,10 @@ var forEach = Ember.EnumerableUtils.forEach;
|
|
|
7999
9473
|
[active_model_serializers](http://github.com/rails-api/active_model_serializers)
|
|
8000
9474
|
Ruby gem.
|
|
8001
9475
|
|
|
9476
|
+
This adapter extends the DS.RESTAdapter by making consistent use of the camelization,
|
|
9477
|
+
decamelization and pluralization methods to normalize the serialized JSON into a
|
|
9478
|
+
format that is compatible with a conventional Rails backend and Ember Data.
|
|
9479
|
+
|
|
8002
9480
|
## JSON Structure
|
|
8003
9481
|
|
|
8004
9482
|
The ActiveModelAdapter expects the JSON returned from your server to follow
|
|
@@ -8040,8 +9518,8 @@ var forEach = Ember.EnumerableUtils.forEach;
|
|
|
8040
9518
|
DS.ActiveModelAdapter = DS.RESTAdapter.extend({
|
|
8041
9519
|
defaultSerializer: '_ams',
|
|
8042
9520
|
/**
|
|
8043
|
-
The ActiveModelAdapter overrides the `pathForType` method
|
|
8044
|
-
|
|
9521
|
+
The ActiveModelAdapter overrides the `pathForType` method to build
|
|
9522
|
+
underscored URLs by decamelizing and pluralizing the object type name.
|
|
8045
9523
|
|
|
8046
9524
|
```js
|
|
8047
9525
|
this.pathForType("famousPerson");
|
|
@@ -8062,6 +9540,13 @@ DS.ActiveModelAdapter = DS.RESTAdapter.extend({
|
|
|
8062
9540
|
to return a DS.InvalidError for all 422 Unprocessable Entity
|
|
8063
9541
|
responses.
|
|
8064
9542
|
|
|
9543
|
+
A 422 HTTP response from the server generally implies that the request
|
|
9544
|
+
was well formed but the API was unable to process it because the
|
|
9545
|
+
content was not semantically correct or meaningful per the API.
|
|
9546
|
+
|
|
9547
|
+
For more information on 422 HTTP Error code see 11.2 WebDAV RFC 4918
|
|
9548
|
+
https://tools.ietf.org/html/rfc4918#section-11.2
|
|
9549
|
+
|
|
8065
9550
|
@method ajaxError
|
|
8066
9551
|
@param jqXHR
|
|
8067
9552
|
@returns error
|