ember-data-source 1.0.0.beta.2 → 1.0.0.beta.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/dist/ember-data.js +1216 -286
- data/dist/ember-data.min.js +8 -6
- data/dist/ember-data.prod.js +1208 -279
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 795cc179a07951267a58b778b774cc94d20337e7
|
4
|
+
data.tar.gz: a29df0c6cab5e428cfe02e0f2c170aef0a277c4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ad91411d815db80f3311bbb917bfd7de5fc2423e9bd0f5d5531f2babdfac8798d3855edeb46ad4bfc695d7da7202c73a49c349d8f2d48f10bffcf46a11111a7
|
7
|
+
data.tar.gz: 447131c2a03505bf4c087b86d5aba7c7f55390b2ccd698cc89c51abadebaf940f06f7e136b86e8c2198f59558366094d6691ef914dd6e58948f2c30b9da9a962
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.0-beta.
|
1
|
+
1.0.0-beta.3
|
data/dist/ember-data.js
CHANGED
@@ -1,5 +1,14 @@
|
|
1
|
-
//
|
2
|
-
//
|
1
|
+
// ==========================================================================
|
2
|
+
// Project: 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
|
+
|
8
|
+
|
9
|
+
|
10
|
+
// Version: v1.0.0-beta.3-48-gb47afef
|
11
|
+
// Last commit: b47afef (2013-10-08 19:07:59 -0700)
|
3
12
|
|
4
13
|
|
5
14
|
(function() {
|
@@ -55,12 +64,16 @@ var define, requireModule;
|
|
55
64
|
|
56
65
|
if ('undefined' === typeof DS) {
|
57
66
|
DS = Ember.Namespace.create({
|
58
|
-
VERSION: '1.0.0-beta.
|
67
|
+
VERSION: '1.0.0-beta.2'
|
59
68
|
});
|
60
69
|
|
61
70
|
if ('undefined' !== typeof window) {
|
62
71
|
window.DS = DS;
|
63
72
|
}
|
73
|
+
|
74
|
+
if (Ember.libraries) {
|
75
|
+
Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION);
|
76
|
+
}
|
64
77
|
}
|
65
78
|
})();
|
66
79
|
|
@@ -99,8 +112,6 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
99
112
|
// SERIALIZE
|
100
113
|
|
101
114
|
serialize: function(record, options) {
|
102
|
-
var store = get(this, 'store');
|
103
|
-
|
104
115
|
var json = {};
|
105
116
|
|
106
117
|
if (options && options.includeId) {
|
@@ -137,7 +148,7 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
137
148
|
|
138
149
|
// if provided, use the mapping provided by `attrs` in
|
139
150
|
// the serializer
|
140
|
-
key = attrs && attrs[key] || key;
|
151
|
+
key = attrs && attrs[key] || (this.keyForAttribute ? this.keyForAttribute(key) : key);
|
141
152
|
|
142
153
|
json[key] = value;
|
143
154
|
},
|
@@ -147,12 +158,16 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
147
158
|
|
148
159
|
var belongsTo = get(record, key);
|
149
160
|
|
150
|
-
|
161
|
+
key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo") : key;
|
151
162
|
|
152
|
-
|
163
|
+
if (isNone(belongsTo)) {
|
164
|
+
json[key] = belongsTo;
|
165
|
+
} else {
|
166
|
+
json[key] = get(belongsTo, 'id');
|
167
|
+
}
|
153
168
|
|
154
169
|
if (relationship.options.polymorphic) {
|
155
|
-
json
|
170
|
+
this.serializePolymorphicType(record, json, relationship);
|
156
171
|
}
|
157
172
|
},
|
158
173
|
|
@@ -167,6 +182,11 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
167
182
|
}
|
168
183
|
},
|
169
184
|
|
185
|
+
/**
|
186
|
+
You can use this method to customize how polymorphic objects are serialized.
|
187
|
+
*/
|
188
|
+
serializePolymorphicType: Ember.K,
|
189
|
+
|
170
190
|
// EXTRACT
|
171
191
|
|
172
192
|
extract: function(store, type, payload, id, requestType) {
|
@@ -186,6 +206,7 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
186
206
|
extractDeleteRecord: aliasMethod('extractSave'),
|
187
207
|
|
188
208
|
extractFind: aliasMethod('extractSingle'),
|
209
|
+
extractFindBelongsTo: aliasMethod('extractSingle'),
|
189
210
|
extractSave: aliasMethod('extractSingle'),
|
190
211
|
|
191
212
|
extractSingle: function(store, type, payload) {
|
@@ -205,16 +226,10 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
205
226
|
|
206
227
|
// HELPERS
|
207
228
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
return relationship.type;
|
213
|
-
}
|
214
|
-
},
|
215
|
-
|
216
|
-
transformFor: function(attributeType) {
|
217
|
-
return this.container.lookup('transform:' + attributeType);
|
229
|
+
transformFor: function(attributeType, skipAssertion) {
|
230
|
+
var transform = this.container.lookup('transform:' + attributeType);
|
231
|
+
Ember.assert("Unable to find transform for '" + attributeType + "'", skipAssertion || !!transform);
|
232
|
+
return transform;
|
218
233
|
}
|
219
234
|
});
|
220
235
|
|
@@ -230,6 +245,11 @@ var get = Ember.get, capitalize = Ember.String.capitalize, underscore = Ember.St
|
|
230
245
|
|
231
246
|
/**
|
232
247
|
Extend `Ember.DataAdapter` with ED specific code.
|
248
|
+
|
249
|
+
@class DebugAdapter
|
250
|
+
@namespace DS
|
251
|
+
@extends Ember.DataAdapter
|
252
|
+
@private
|
233
253
|
*/
|
234
254
|
DS.DebugAdapter = Ember.DataAdapter.extend({
|
235
255
|
getFilters: function() {
|
@@ -246,7 +266,7 @@ DS.DebugAdapter = Ember.DataAdapter.extend({
|
|
246
266
|
|
247
267
|
columnsForType: function(type) {
|
248
268
|
var columns = [{ name: 'id', desc: 'Id' }], count = 0, self = this;
|
249
|
-
|
269
|
+
get(type, 'attributes').forEach(function(name, meta) {
|
250
270
|
if (count++ > self.attributeLimit) { return false; }
|
251
271
|
var desc = capitalize(underscore(name).replace('_', ' '));
|
252
272
|
columns.push({ name: name, desc: desc });
|
@@ -442,7 +462,7 @@ DS.NumberTransform = DS.Transform.extend({
|
|
442
462
|
|
443
463
|
|
444
464
|
(function() {
|
445
|
-
var none = Ember.isNone
|
465
|
+
var none = Ember.isNone;
|
446
466
|
|
447
467
|
DS.StringTransform = DS.Transform.extend({
|
448
468
|
|
@@ -455,6 +475,7 @@ DS.StringTransform = DS.Transform.extend({
|
|
455
475
|
}
|
456
476
|
|
457
477
|
});
|
478
|
+
|
458
479
|
})();
|
459
480
|
|
460
481
|
|
@@ -688,6 +709,14 @@ DS.RecordArray = Ember.ArrayProxy.extend(Ember.Evented, {
|
|
688
709
|
|
689
710
|
removeRecord: function(record) {
|
690
711
|
get(this, 'content').removeObject(record);
|
712
|
+
},
|
713
|
+
|
714
|
+
save: function() {
|
715
|
+
var promise = Ember.RSVP.all(this.invoke("save")).then(function(array) {
|
716
|
+
return Ember.A(array);
|
717
|
+
});
|
718
|
+
|
719
|
+
return DS.PromiseArray.create({ promise: promise });
|
691
720
|
}
|
692
721
|
});
|
693
722
|
|
@@ -749,11 +778,13 @@ DS.AdapterPopulatedRecordArray = DS.RecordArray.extend({
|
|
749
778
|
load: function(data) {
|
750
779
|
var store = get(this, 'store'),
|
751
780
|
type = get(this, 'type'),
|
752
|
-
records = store.pushMany(type, data)
|
781
|
+
records = store.pushMany(type, data),
|
782
|
+
meta = store.metadataFor(type);
|
753
783
|
|
754
784
|
this.setProperties({
|
755
785
|
content: Ember.A(records),
|
756
|
-
isLoaded: true
|
786
|
+
isLoaded: true,
|
787
|
+
meta: meta
|
757
788
|
});
|
758
789
|
|
759
790
|
// TODO: does triggering didLoad event should be the last action of the runLoop?
|
@@ -787,11 +818,11 @@ var map = Ember.EnumerableUtils.map;
|
|
787
818
|
defined:
|
788
819
|
|
789
820
|
App.Post = DS.Model.extend({
|
790
|
-
comments: DS.hasMany('
|
821
|
+
comments: DS.hasMany('comment')
|
791
822
|
});
|
792
823
|
|
793
824
|
App.Comment = DS.Model.extend({
|
794
|
-
post: DS.belongsTo('
|
825
|
+
post: DS.belongsTo('post')
|
795
826
|
});
|
796
827
|
|
797
828
|
If you created a new instance of `App.Post` and added
|
@@ -848,10 +879,11 @@ DS.ManyArray = DS.RecordArray.extend({
|
|
848
879
|
fetch: function() {
|
849
880
|
var records = get(this, 'content'),
|
850
881
|
store = get(this, 'store'),
|
851
|
-
owner = get(this, 'owner')
|
882
|
+
owner = get(this, 'owner'),
|
883
|
+
resolver = Ember.RSVP.defer();
|
852
884
|
|
853
885
|
var unloadedRecords = records.filterProperty('isEmpty', true);
|
854
|
-
store.fetchMany(unloadedRecords, owner);
|
886
|
+
store.fetchMany(unloadedRecords, owner, resolver);
|
855
887
|
},
|
856
888
|
|
857
889
|
// Overrides Ember.Array's replace method to implement
|
@@ -866,7 +898,7 @@ DS.ManyArray = DS.RecordArray.extend({
|
|
866
898
|
},
|
867
899
|
|
868
900
|
arrangedContentDidChange: function() {
|
869
|
-
this
|
901
|
+
Ember.run.once(this, 'fetch');
|
870
902
|
},
|
871
903
|
|
872
904
|
arrayContentWillChange: function(index, removed, added) {
|
@@ -1136,7 +1168,6 @@ var isNone = Ember.isNone;
|
|
1136
1168
|
var forEach = Ember.EnumerableUtils.forEach;
|
1137
1169
|
var indexOf = Ember.EnumerableUtils.indexOf;
|
1138
1170
|
var map = Ember.EnumerableUtils.map;
|
1139
|
-
var OrderedSet = Ember.OrderedSet;
|
1140
1171
|
var resolve = Ember.RSVP.resolve;
|
1141
1172
|
|
1142
1173
|
// Implementors Note:
|
@@ -1347,7 +1378,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1347
1378
|
@returns String if the adapter can generate one, an ID
|
1348
1379
|
*/
|
1349
1380
|
_generateId: function(type) {
|
1350
|
-
var adapter = this.
|
1381
|
+
var adapter = this.adapterFor(type);
|
1351
1382
|
|
1352
1383
|
if (adapter && adapter.generateIdForRecord) {
|
1353
1384
|
return adapter.generateIdForRecord(this);
|
@@ -1451,12 +1482,10 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1451
1482
|
findById: function(type, id) {
|
1452
1483
|
type = this.modelFor(type);
|
1453
1484
|
|
1454
|
-
var record = this.
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
return promiseObject(resolve(record));
|
1459
|
-
}
|
1485
|
+
var record = this.recordForId(type, id);
|
1486
|
+
|
1487
|
+
var promise = this.fetchRecord(record) || resolve(record);
|
1488
|
+
return promiseObject(promise);
|
1460
1489
|
},
|
1461
1490
|
|
1462
1491
|
/**
|
@@ -1489,13 +1518,17 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1489
1518
|
@returns Promise
|
1490
1519
|
*/
|
1491
1520
|
fetchRecord: function(record) {
|
1521
|
+
if (isNone(record)) { return null; }
|
1522
|
+
if (record._loadingPromise) { return record._loadingPromise; }
|
1523
|
+
if (!get(record, 'isEmpty')) { return null; }
|
1524
|
+
|
1492
1525
|
var type = record.constructor,
|
1493
1526
|
id = get(record, 'id'),
|
1494
1527
|
resolver = Ember.RSVP.defer();
|
1495
1528
|
|
1496
|
-
record.loadingData();
|
1529
|
+
record.loadingData(resolver.promise);
|
1497
1530
|
|
1498
|
-
var adapter = this.
|
1531
|
+
var adapter = this.adapterFor(type);
|
1499
1532
|
|
1500
1533
|
Ember.assert("You tried to find a record but you have no adapter (for " + type + ")", adapter);
|
1501
1534
|
Ember.assert("You tried to find a record but your adapter (for " + type + ") does not implement 'find'", adapter.find);
|
@@ -1509,7 +1542,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1509
1542
|
Get a record by a given type and ID without triggering a fetch.
|
1510
1543
|
|
1511
1544
|
This method will synchronously return the record if it's available.
|
1512
|
-
Otherwise, it will return
|
1545
|
+
Otherwise, it will return null.
|
1513
1546
|
|
1514
1547
|
```js
|
1515
1548
|
var post = store.getById('post', 1);
|
@@ -1525,7 +1558,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1525
1558
|
if (this.hasRecordForId(type, id)) {
|
1526
1559
|
return this.recordForId(type, id);
|
1527
1560
|
} else {
|
1528
|
-
return
|
1561
|
+
return null;
|
1529
1562
|
}
|
1530
1563
|
},
|
1531
1564
|
|
@@ -1544,8 +1577,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1544
1577
|
*/
|
1545
1578
|
reloadRecord: function(record, resolver) {
|
1546
1579
|
var type = record.constructor,
|
1547
|
-
adapter = this.
|
1548
|
-
store = this,
|
1580
|
+
adapter = this.adapterFor(type),
|
1549
1581
|
id = get(record, 'id');
|
1550
1582
|
|
1551
1583
|
Ember.assert("You cannot reload a record without an ID", id);
|
@@ -1586,7 +1618,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1586
1618
|
|
1587
1619
|
forEach(recordsByTypeMap, function(type, records) {
|
1588
1620
|
var ids = records.mapProperty('id'),
|
1589
|
-
adapter = this.
|
1621
|
+
adapter = this.adapterFor(type);
|
1590
1622
|
|
1591
1623
|
Ember.assert("You tried to load many records but you have no adapter (for " + type + ")", adapter);
|
1592
1624
|
Ember.assert("You tried to load many records but your adapter does not implement `findMany`", adapter.findMany);
|
@@ -1598,7 +1630,8 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1598
1630
|
/**
|
1599
1631
|
Returns true if a record for a given type and ID is already loaded.
|
1600
1632
|
|
1601
|
-
@
|
1633
|
+
@method hasRecordForId
|
1634
|
+
@param {DS.Model} type
|
1602
1635
|
@param {String|Integer} id
|
1603
1636
|
@returns Boolean
|
1604
1637
|
*/
|
@@ -1612,6 +1645,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1612
1645
|
Returns id record for a given type and ID. If one isn't already loaded,
|
1613
1646
|
it builds a new record and leaves it in the `empty` state.
|
1614
1647
|
|
1648
|
+
@method recordForId
|
1615
1649
|
@param {String} type
|
1616
1650
|
@param {String|Integer} id
|
1617
1651
|
@returns DS.Model
|
@@ -1679,6 +1713,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1679
1713
|
The usual use-case is for the server to register a URL as a link, and
|
1680
1714
|
then use that URL in the future to make a request for the relationship.
|
1681
1715
|
|
1716
|
+
@method findHasMany
|
1682
1717
|
@private
|
1683
1718
|
@param {DS.Model} owner
|
1684
1719
|
@param {any} link
|
@@ -1687,7 +1722,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1687
1722
|
@return DS.ManyArray
|
1688
1723
|
*/
|
1689
1724
|
findHasMany: function(owner, link, relationship, resolver) {
|
1690
|
-
var adapter = this.
|
1725
|
+
var adapter = this.adapterFor(owner.constructor);
|
1691
1726
|
|
1692
1727
|
Ember.assert("You tried to load a hasMany relationship but you have no adapter (for " + owner.constructor + ")", adapter);
|
1693
1728
|
Ember.assert("You tried to load a hasMany relationship from a specified `link` in the original payload but your adapter does not implement `findHasMany`", adapter.findHasMany);
|
@@ -1697,6 +1732,15 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1697
1732
|
return records;
|
1698
1733
|
},
|
1699
1734
|
|
1735
|
+
findBelongsTo: function(owner, link, relationship, resolver) {
|
1736
|
+
var adapter = this.adapterFor(owner.constructor);
|
1737
|
+
|
1738
|
+
Ember.assert("You tried to load a belongsTo relationship but you have no adapter (for " + owner.constructor + ")", adapter);
|
1739
|
+
Ember.assert("You tried to load a belongsTo relationship from a specified `link` in the original payload but your adapter does not implement `findBelongsTo`", adapter.findBelongsTo);
|
1740
|
+
|
1741
|
+
_findBelongsTo(adapter, this, owner, link, relationship, resolver);
|
1742
|
+
},
|
1743
|
+
|
1700
1744
|
/**
|
1701
1745
|
This method delegates a query to the adapter. This is the one place where
|
1702
1746
|
adapter-level semantics are exposed to the application.
|
@@ -1724,7 +1768,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1724
1768
|
store: this
|
1725
1769
|
});
|
1726
1770
|
|
1727
|
-
var adapter = this.
|
1771
|
+
var adapter = this.adapterFor(type),
|
1728
1772
|
resolver = Ember.RSVP.defer();
|
1729
1773
|
|
1730
1774
|
Ember.assert("You tried to load a query but you have no adapter (for " + type + ")", adapter);
|
@@ -1759,7 +1803,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1759
1803
|
@returns Promise
|
1760
1804
|
*/
|
1761
1805
|
fetchAll: function(type, array) {
|
1762
|
-
var adapter = this.
|
1806
|
+
var adapter = this.adapterFor(type),
|
1763
1807
|
sinceToken = this.typeMapFor(type).metadata.since,
|
1764
1808
|
resolver = Ember.RSVP.defer();
|
1765
1809
|
|
@@ -1817,6 +1861,24 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1817
1861
|
return array;
|
1818
1862
|
},
|
1819
1863
|
|
1864
|
+
|
1865
|
+
/**
|
1866
|
+
This method unloads all of the known records for a given type.
|
1867
|
+
|
1868
|
+
@method unloadAll
|
1869
|
+
@param {Class} type
|
1870
|
+
*/
|
1871
|
+
unloadAll: function(type) {
|
1872
|
+
type = this.modelFor(type);
|
1873
|
+
|
1874
|
+
var typeMap = this.typeMapFor(type),
|
1875
|
+
records = typeMap.records, record;
|
1876
|
+
|
1877
|
+
while(record = records.pop()) {
|
1878
|
+
record.unloadRecord();
|
1879
|
+
}
|
1880
|
+
},
|
1881
|
+
|
1820
1882
|
/**
|
1821
1883
|
Takes a type and filter function, and returns a live RecordArray that
|
1822
1884
|
remains up to date as new records are loaded into the store or created
|
@@ -1833,14 +1895,6 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1833
1895
|
filter function will be invoked again to determine whether it should
|
1834
1896
|
still be in the array.
|
1835
1897
|
|
1836
|
-
Note that the existence of a filter on a type will trigger immediate
|
1837
|
-
materialization of all loaded data for a given type, so you might
|
1838
|
-
not want to use filters for a type if you are loading many records
|
1839
|
-
into the store, many of which are not active at any given time.
|
1840
|
-
|
1841
|
-
In this scenario, you might want to consider filtering the raw
|
1842
|
-
data before loading it into the store.
|
1843
|
-
|
1844
1898
|
@method filter
|
1845
1899
|
@param {Class} type
|
1846
1900
|
@param {Function} filter
|
@@ -1890,6 +1944,18 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1890
1944
|
return !get(this.recordForId(type, id), 'isEmpty');
|
1891
1945
|
},
|
1892
1946
|
|
1947
|
+
/**
|
1948
|
+
This method returns the metadata for a specific type.
|
1949
|
+
|
1950
|
+
@method metadataFor
|
1951
|
+
@param {string} type
|
1952
|
+
@return {object}
|
1953
|
+
*/
|
1954
|
+
metadataFor: function(type) {
|
1955
|
+
type = this.modelFor(type);
|
1956
|
+
return this.typeMapFor(type).metadata;
|
1957
|
+
},
|
1958
|
+
|
1893
1959
|
// ............
|
1894
1960
|
// . UPDATING .
|
1895
1961
|
// ............
|
@@ -1959,7 +2025,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1959
2025
|
|
1960
2026
|
forEach(pending, function(tuple) {
|
1961
2027
|
var record = tuple[0], resolver = tuple[1],
|
1962
|
-
adapter = this.
|
2028
|
+
adapter = this.adapterFor(record.constructor),
|
1963
2029
|
operation;
|
1964
2030
|
|
1965
2031
|
if (get(record, 'isNew')) {
|
@@ -1989,6 +2055,9 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1989
2055
|
*/
|
1990
2056
|
didSaveRecord: function(record, data) {
|
1991
2057
|
if (data) {
|
2058
|
+
// normalize relationship IDs into records
|
2059
|
+
data = normalizeRelationships(this, record.constructor, data, record);
|
2060
|
+
|
1992
2061
|
this.updateId(record, data);
|
1993
2062
|
}
|
1994
2063
|
|
@@ -2082,7 +2151,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
2082
2151
|
@param {DS.Model} type
|
2083
2152
|
@param {Object} data
|
2084
2153
|
@param {Boolean} partial the data should be merged into
|
2085
|
-
the existing
|
2154
|
+
the existing data, not replace it.
|
2086
2155
|
*/
|
2087
2156
|
_load: function(type, data, partial) {
|
2088
2157
|
var id = coerceId(data.id),
|
@@ -2099,21 +2168,23 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
2099
2168
|
methods that take a type key (like `find`, `createRecord`,
|
2100
2169
|
etc.)
|
2101
2170
|
|
2102
|
-
@
|
2171
|
+
@method modelFor
|
2172
|
+
@param {String or subclass of DS.Model} key
|
2103
2173
|
@returns {subclass of DS.Model}
|
2104
2174
|
*/
|
2105
2175
|
modelFor: function(key) {
|
2106
|
-
|
2107
|
-
return key;
|
2108
|
-
}
|
2109
|
-
|
2110
|
-
var factory = this.container.lookupFactory('model:'+key);
|
2176
|
+
var factory;
|
2111
2177
|
|
2112
|
-
|
2178
|
+
if (typeof key === 'string') {
|
2179
|
+
factory = this.container.lookupFactory('model:' + key);
|
2180
|
+
Ember.assert("No model was found for '" + key + "'", factory);
|
2181
|
+
factory.typeKey = key;
|
2182
|
+
} else {
|
2183
|
+
// A factory already supplied.
|
2184
|
+
factory = key;
|
2185
|
+
}
|
2113
2186
|
|
2114
2187
|
factory.store = this;
|
2115
|
-
factory.typeKey = key;
|
2116
|
-
|
2117
2188
|
return factory;
|
2118
2189
|
},
|
2119
2190
|
|
@@ -2183,7 +2254,8 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
2183
2254
|
// If passed, it means that the data should be
|
2184
2255
|
// merged into the existing data, not replace it.
|
2185
2256
|
|
2186
|
-
|
2257
|
+
Ember.assert("You must include an `id` in a hash passed to `push`", data.id != null);
|
2258
|
+
|
2187
2259
|
type = this.modelFor(type);
|
2188
2260
|
|
2189
2261
|
// normalize relationship IDs into records
|
@@ -2194,7 +2266,47 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
2194
2266
|
return this.recordForId(type, data.id);
|
2195
2267
|
},
|
2196
2268
|
|
2269
|
+
/**
|
2270
|
+
Push some raw data into the store.
|
2271
|
+
|
2272
|
+
The data will be automatically deserialized using the
|
2273
|
+
serializer for the `type` param.
|
2274
|
+
|
2275
|
+
This method can be used both to push in brand new
|
2276
|
+
records, as well as to update existing records.
|
2277
|
+
|
2278
|
+
You can push in more than one type of object at once.
|
2279
|
+
All objects should be in the format expected by the
|
2280
|
+
serializer.
|
2281
|
+
|
2282
|
+
```js
|
2283
|
+
App.ApplicationSerializer = DS.ActiveModelSerializer;
|
2284
|
+
|
2285
|
+
var pushData = {
|
2286
|
+
posts: [
|
2287
|
+
{id: 1, post_title: "Great post", comment_ids: [2]}
|
2288
|
+
],
|
2289
|
+
comments: [
|
2290
|
+
{id: 2, comment_body: "Insightful comment"}
|
2291
|
+
]
|
2292
|
+
}
|
2293
|
+
|
2294
|
+
store.pushPayload('post', pushData);
|
2295
|
+
```
|
2296
|
+
|
2297
|
+
@method push
|
2298
|
+
@param {String} type
|
2299
|
+
@param {Object} payload
|
2300
|
+
*/
|
2301
|
+
|
2302
|
+
pushPayload: function (type, payload) {
|
2303
|
+
var serializer = this.serializerFor(type);
|
2304
|
+
serializer.pushPayload(this, payload);
|
2305
|
+
},
|
2306
|
+
|
2197
2307
|
update: function(type, data) {
|
2308
|
+
Ember.assert("You must include an `id` in a hash passed to `update`", data.id != null);
|
2309
|
+
|
2198
2310
|
return this.push(type, data, true);
|
2199
2311
|
},
|
2200
2312
|
|
@@ -2245,9 +2357,12 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
2245
2357
|
|
2246
2358
|
Ember.assert('The id ' + id + ' has already been used with another record of type ' + type.toString() + '.', !id || !idToRecord[id]);
|
2247
2359
|
|
2360
|
+
// lookupFactory should really return an object that creates
|
2361
|
+
// instances with the injections applied
|
2248
2362
|
var record = type._create({
|
2249
2363
|
id: id,
|
2250
2364
|
store: this,
|
2365
|
+
container: this.container
|
2251
2366
|
});
|
2252
2367
|
|
2253
2368
|
if (data) {
|
@@ -2350,12 +2465,12 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
2350
2465
|
/**
|
2351
2466
|
Returns the adapter for a given type.
|
2352
2467
|
|
2353
|
-
@method
|
2468
|
+
@method adapterFor
|
2354
2469
|
@private
|
2355
2470
|
@param {subclass of DS.Model} type
|
2356
2471
|
@returns DS.Adapter
|
2357
2472
|
*/
|
2358
|
-
|
2473
|
+
adapterFor: function(type) {
|
2359
2474
|
var container = this.container, adapter;
|
2360
2475
|
|
2361
2476
|
if (container) {
|
@@ -2387,29 +2502,31 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
2387
2502
|
*/
|
2388
2503
|
serializerFor: function(type) {
|
2389
2504
|
type = this.modelFor(type);
|
2390
|
-
var adapter = this.
|
2505
|
+
var adapter = this.adapterFor(type);
|
2391
2506
|
|
2392
2507
|
return serializerFor(this.container, type.typeKey, adapter && adapter.defaultSerializer);
|
2393
2508
|
}
|
2394
2509
|
});
|
2395
2510
|
|
2396
|
-
function normalizeRelationships(store, type, data) {
|
2511
|
+
function normalizeRelationships(store, type, data, record) {
|
2397
2512
|
type.eachRelationship(function(key, relationship) {
|
2398
2513
|
// A link (usually a URL) was already provided in
|
2399
2514
|
// normalized form
|
2400
2515
|
if (data.links && data.links[key]) {
|
2516
|
+
if (record && relationship.options.async) { record._relationships[key] = null; }
|
2401
2517
|
return;
|
2402
2518
|
}
|
2403
2519
|
|
2404
|
-
var
|
2520
|
+
var kind = relationship.kind,
|
2405
2521
|
value = data[key];
|
2406
2522
|
|
2407
2523
|
if (value == null) { return; }
|
2408
2524
|
|
2409
|
-
if (
|
2525
|
+
if (kind === 'belongsTo') {
|
2410
2526
|
deserializeRecordId(store, data, key, relationship, value);
|
2411
|
-
} else if (
|
2527
|
+
} else if (kind === 'hasMany') {
|
2412
2528
|
deserializeRecordIds(store, data, key, relationship, value);
|
2529
|
+
addUnsavedRecords(record, key, value);
|
2413
2530
|
}
|
2414
2531
|
});
|
2415
2532
|
|
@@ -2434,7 +2551,7 @@ function deserializeRecordId(store, data, key, relationship, id) {
|
|
2434
2551
|
|
2435
2552
|
function typeFor(relationship, key, data) {
|
2436
2553
|
if (relationship.options.polymorphic) {
|
2437
|
-
return data[key + "
|
2554
|
+
return data[key + "Type"];
|
2438
2555
|
} else {
|
2439
2556
|
return relationship.type;
|
2440
2557
|
}
|
@@ -2446,6 +2563,14 @@ function deserializeRecordIds(store, data, key, relationship, ids) {
|
|
2446
2563
|
}
|
2447
2564
|
}
|
2448
2565
|
|
2566
|
+
// If there are any unsaved records that are in a hasMany they won't be
|
2567
|
+
// in the payload, so add them back in manually.
|
2568
|
+
function addUnsavedRecords(record, key, data) {
|
2569
|
+
if(record) {
|
2570
|
+
data.pushObjects(record.get(key).filterBy('isNew'));
|
2571
|
+
}
|
2572
|
+
}
|
2573
|
+
|
2449
2574
|
// Delegation to the adapter and promise management
|
2450
2575
|
|
2451
2576
|
DS.PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin);
|
@@ -2497,6 +2622,10 @@ function _find(adapter, store, type, id, resolver) {
|
|
2497
2622
|
payload = serializer.extract(store, type, payload, id, 'find');
|
2498
2623
|
|
2499
2624
|
return store.push(type, payload);
|
2625
|
+
}, function(error) {
|
2626
|
+
var record = store.getById(type, id);
|
2627
|
+
record.notFound();
|
2628
|
+
throw error;
|
2500
2629
|
}).then(resolver.resolve, resolver.reject);
|
2501
2630
|
}
|
2502
2631
|
|
@@ -2507,6 +2636,8 @@ function _findMany(adapter, store, type, ids, owner, resolver) {
|
|
2507
2636
|
return resolve(promise).then(function(payload) {
|
2508
2637
|
payload = serializer.extract(store, type, payload, null, 'findMany');
|
2509
2638
|
|
2639
|
+
Ember.assert("The response from a findMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array');
|
2640
|
+
|
2510
2641
|
store.pushMany(type, payload);
|
2511
2642
|
}).then(resolver.resolve, resolver.reject);
|
2512
2643
|
}
|
@@ -2518,11 +2649,26 @@ function _findHasMany(adapter, store, record, link, relationship, resolver) {
|
|
2518
2649
|
return resolve(promise).then(function(payload) {
|
2519
2650
|
payload = serializer.extract(store, relationship.type, payload, null, 'findHasMany');
|
2520
2651
|
|
2652
|
+
Ember.assert("The response from a findHasMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array');
|
2653
|
+
|
2521
2654
|
var records = store.pushMany(relationship.type, payload);
|
2522
2655
|
record.updateHasMany(relationship.key, records);
|
2523
2656
|
}).then(resolver.resolve, resolver.reject);
|
2524
2657
|
}
|
2525
2658
|
|
2659
|
+
function _findBelongsTo(adapter, store, record, link, relationship, resolver) {
|
2660
|
+
var promise = adapter.findBelongsTo(store, record, link, relationship),
|
2661
|
+
serializer = serializerForAdapter(adapter, relationship.type);
|
2662
|
+
|
2663
|
+
return resolve(promise).then(function(payload) {
|
2664
|
+
payload = serializer.extract(store, relationship.type, payload, null, 'findBelongsTo');
|
2665
|
+
|
2666
|
+
var record = store.push(relationship.type, payload);
|
2667
|
+
record.updateBelongsTo(relationship.key, record);
|
2668
|
+
return record;
|
2669
|
+
}).then(resolver.resolve, resolver.reject);
|
2670
|
+
}
|
2671
|
+
|
2526
2672
|
function _findAll(adapter, store, type, sinceToken, resolver) {
|
2527
2673
|
var promise = adapter.findAll(store, type, sinceToken),
|
2528
2674
|
serializer = serializerForAdapter(adapter, type);
|
@@ -2530,6 +2676,8 @@ function _findAll(adapter, store, type, sinceToken, resolver) {
|
|
2530
2676
|
return resolve(promise).then(function(payload) {
|
2531
2677
|
payload = serializer.extract(store, type, payload, null, 'findAll');
|
2532
2678
|
|
2679
|
+
Ember.assert("The response from a findAll must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array');
|
2680
|
+
|
2533
2681
|
store.pushMany(type, payload);
|
2534
2682
|
store.didUpdateAll(type);
|
2535
2683
|
return store.all(type);
|
@@ -2543,6 +2691,8 @@ function _findQuery(adapter, store, type, query, recordArray, resolver) {
|
|
2543
2691
|
return resolve(promise).then(function(payload) {
|
2544
2692
|
payload = serializer.extract(store, type, payload, null, 'findAll');
|
2545
2693
|
|
2694
|
+
Ember.assert("The response from a findQuery must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array');
|
2695
|
+
|
2546
2696
|
recordArray.load(payload);
|
2547
2697
|
return recordArray;
|
2548
2698
|
}).then(resolver.resolve, resolver.reject);
|
@@ -2556,7 +2706,7 @@ function _commit(adapter, store, operation, record, resolver) {
|
|
2556
2706
|
Ember.assert("Your adapter's '" + operation + "' method must return a promise, but it returned " + promise, isThenable(promise));
|
2557
2707
|
|
2558
2708
|
return promise.then(function(payload) {
|
2559
|
-
payload = serializer.extract(store, type, payload, get(record, 'id'), operation);
|
2709
|
+
if (payload) { payload = serializer.extract(store, type, payload, get(record, 'id'), operation); }
|
2560
2710
|
store.didSaveRecord(record, payload);
|
2561
2711
|
return record;
|
2562
2712
|
}, function(reason) {
|
@@ -2579,8 +2729,7 @@ function _commit(adapter, store, operation, record, resolver) {
|
|
2579
2729
|
@module ember-data
|
2580
2730
|
*/
|
2581
2731
|
|
2582
|
-
var get = Ember.get, set = Ember.set
|
2583
|
-
once = Ember.run.once, arrayMap = Ember.ArrayPolyfills.map;
|
2732
|
+
var get = Ember.get, set = Ember.set;
|
2584
2733
|
|
2585
2734
|
/*
|
2586
2735
|
WARNING: Much of these docs are inaccurate as of bf8497.
|
@@ -2748,10 +2897,14 @@ var hasDefinedProperties = function(object) {
|
|
2748
2897
|
};
|
2749
2898
|
|
2750
2899
|
var didSetProperty = function(record, context) {
|
2751
|
-
if (context.value
|
2900
|
+
if (context.value === context.originalValue) {
|
2901
|
+
delete record._attributes[context.name];
|
2902
|
+
record.send('propertyWasReset', context.name);
|
2903
|
+
} else if (context.value !== context.oldValue) {
|
2752
2904
|
record.send('becomeDirty');
|
2753
|
-
record.updateRecordArraysLater();
|
2754
2905
|
}
|
2906
|
+
|
2907
|
+
record.updateRecordArraysLater();
|
2755
2908
|
};
|
2756
2909
|
|
2757
2910
|
// Implementation notes:
|
@@ -2809,10 +2962,20 @@ var DirtyState = {
|
|
2809
2962
|
// This means that there are local pending changes, but they
|
2810
2963
|
// have not yet begun to be saved, and are not invalid.
|
2811
2964
|
uncommitted: {
|
2812
|
-
|
2813
2965
|
// EVENTS
|
2814
2966
|
didSetProperty: didSetProperty,
|
2815
2967
|
|
2968
|
+
propertyWasReset: function(record, name) {
|
2969
|
+
var stillDirty = false;
|
2970
|
+
|
2971
|
+
for (var prop in record._attributes) {
|
2972
|
+
stillDirty = true;
|
2973
|
+
break;
|
2974
|
+
}
|
2975
|
+
|
2976
|
+
if (!stillDirty) { record.send('rolledBack'); }
|
2977
|
+
},
|
2978
|
+
|
2816
2979
|
pushedData: Ember.K,
|
2817
2980
|
|
2818
2981
|
becomeDirty: Ember.K,
|
@@ -2997,6 +3160,8 @@ var RootState = {
|
|
2997
3160
|
// you out of the in-flight state.
|
2998
3161
|
rolledBack: Ember.K,
|
2999
3162
|
|
3163
|
+
propertyWasReset: Ember.K,
|
3164
|
+
|
3000
3165
|
// SUBSTATES
|
3001
3166
|
|
3002
3167
|
// A record begins its lifecycle in the `empty` state.
|
@@ -3008,7 +3173,8 @@ var RootState = {
|
|
3008
3173
|
isEmpty: true,
|
3009
3174
|
|
3010
3175
|
// EVENTS
|
3011
|
-
loadingData: function(record) {
|
3176
|
+
loadingData: function(record, promise) {
|
3177
|
+
record._loadingPromise = promise;
|
3012
3178
|
record.transitionTo('loading');
|
3013
3179
|
},
|
3014
3180
|
|
@@ -3022,6 +3188,7 @@ var RootState = {
|
|
3022
3188
|
|
3023
3189
|
pushedData: function(record) {
|
3024
3190
|
record.transitionTo('loaded.saved');
|
3191
|
+
record.triggerLater('didLoad');
|
3025
3192
|
}
|
3026
3193
|
},
|
3027
3194
|
|
@@ -3035,6 +3202,10 @@ var RootState = {
|
|
3035
3202
|
// FLAGS
|
3036
3203
|
isLoading: true,
|
3037
3204
|
|
3205
|
+
exit: function(record) {
|
3206
|
+
record._loadingPromise = null;
|
3207
|
+
},
|
3208
|
+
|
3038
3209
|
// EVENTS
|
3039
3210
|
pushedData: function(record) {
|
3040
3211
|
record.transitionTo('loaded.saved');
|
@@ -3044,6 +3215,10 @@ var RootState = {
|
|
3044
3215
|
|
3045
3216
|
becameError: function(record) {
|
3046
3217
|
record.triggerLater('becameError', record);
|
3218
|
+
},
|
3219
|
+
|
3220
|
+
notFound: function(record) {
|
3221
|
+
record.transitionTo('empty');
|
3047
3222
|
}
|
3048
3223
|
},
|
3049
3224
|
|
@@ -3108,7 +3283,7 @@ var RootState = {
|
|
3108
3283
|
|
3109
3284
|
didCommit: function(record) {
|
3110
3285
|
record.send('invokeLifecycleCallbacks', get(record, 'lastDirtyType'));
|
3111
|
-
}
|
3286
|
+
}
|
3112
3287
|
|
3113
3288
|
},
|
3114
3289
|
|
@@ -3219,8 +3394,6 @@ var RootState = {
|
|
3219
3394
|
}
|
3220
3395
|
};
|
3221
3396
|
|
3222
|
-
var hasOwnProp = {}.hasOwnProperty;
|
3223
|
-
|
3224
3397
|
function wireState(object, parent, name) {
|
3225
3398
|
/*jshint proto:true*/
|
3226
3399
|
// TODO: Use Object.create and copy instead
|
@@ -3251,11 +3424,9 @@ DS.RootState = RootState;
|
|
3251
3424
|
@module ember-data
|
3252
3425
|
*/
|
3253
3426
|
|
3254
|
-
var get = Ember.get, set = Ember.set,
|
3427
|
+
var get = Ember.get, set = Ember.set,
|
3255
3428
|
merge = Ember.merge, once = Ember.run.once;
|
3256
3429
|
|
3257
|
-
var arrayMap = Ember.ArrayPolyfills.map;
|
3258
|
-
|
3259
3430
|
var retrieveFromCurrentState = Ember.computed(function(key, value) {
|
3260
3431
|
return get(get(this, 'currentState'), key);
|
3261
3432
|
}).property('currentState').readOnly();
|
@@ -3319,7 +3490,8 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
3319
3490
|
@returns {Object} A JSON representation of the object.
|
3320
3491
|
*/
|
3321
3492
|
toJSON: function(options) {
|
3322
|
-
|
3493
|
+
// container is for lazy transform lookups
|
3494
|
+
var serializer = DS.JSONSerializer.create({ container: this.container });
|
3323
3495
|
return serializer.serialize(this, options);
|
3324
3496
|
},
|
3325
3497
|
|
@@ -3437,6 +3609,8 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
3437
3609
|
for (i=0, l=setups.length; i<l; i++) {
|
3438
3610
|
setups[i].setup(this);
|
3439
3611
|
}
|
3612
|
+
|
3613
|
+
this.updateRecordArraysLater();
|
3440
3614
|
},
|
3441
3615
|
|
3442
3616
|
_unhandledEvent: function(state, name, context) {
|
@@ -3456,22 +3630,45 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
3456
3630
|
if (transaction) { fn(transaction); }
|
3457
3631
|
},
|
3458
3632
|
|
3459
|
-
loadingData: function() {
|
3460
|
-
this.send('loadingData');
|
3633
|
+
loadingData: function(promise) {
|
3634
|
+
this.send('loadingData', promise);
|
3461
3635
|
},
|
3462
3636
|
|
3463
3637
|
loadedData: function() {
|
3464
3638
|
this.send('loadedData');
|
3465
3639
|
},
|
3466
3640
|
|
3641
|
+
notFound: function() {
|
3642
|
+
this.send('notFound');
|
3643
|
+
},
|
3644
|
+
|
3467
3645
|
pushedData: function() {
|
3468
3646
|
this.send('pushedData');
|
3469
3647
|
},
|
3470
3648
|
|
3649
|
+
/**
|
3650
|
+
Marks the record as deleted but does not save it. You must call
|
3651
|
+
`save` afterwards if you want to persist it. You might use this
|
3652
|
+
method if you want to allow the user to still `rollback()` a
|
3653
|
+
delete after it was made.
|
3654
|
+
|
3655
|
+
@method deleteRecord
|
3656
|
+
*/
|
3471
3657
|
deleteRecord: function() {
|
3472
3658
|
this.send('deleteRecord');
|
3473
3659
|
},
|
3474
3660
|
|
3661
|
+
/**
|
3662
|
+
Same as `deleteRecord`, but saves the record immediately.
|
3663
|
+
|
3664
|
+
@method destroyRecord
|
3665
|
+
@returns Promise
|
3666
|
+
*/
|
3667
|
+
destroyRecord: function() {
|
3668
|
+
this.deleteRecord();
|
3669
|
+
return this.save();
|
3670
|
+
},
|
3671
|
+
|
3475
3672
|
unloadRecord: function() {
|
3476
3673
|
Ember.assert("You can only unload a loaded, non-dirty record.", !get(this, 'isDirty'));
|
3477
3674
|
|
@@ -3496,6 +3693,27 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
3496
3693
|
}
|
3497
3694
|
},
|
3498
3695
|
|
3696
|
+
/**
|
3697
|
+
Gets the diff for the current model.
|
3698
|
+
|
3699
|
+
@method changedAttributes
|
3700
|
+
|
3701
|
+
@returns {Object} an object, whose keys are changed properties,
|
3702
|
+
and value is an [oldProp, newProp] array.
|
3703
|
+
*/
|
3704
|
+
changedAttributes: function() {
|
3705
|
+
var oldData = get(this, '_data'),
|
3706
|
+
newData = get(this, '_attributes'),
|
3707
|
+
diffData = {},
|
3708
|
+
prop;
|
3709
|
+
|
3710
|
+
for (prop in newData) {
|
3711
|
+
diffData[prop] = [oldData[prop], newData[prop]];
|
3712
|
+
}
|
3713
|
+
|
3714
|
+
return diffData;
|
3715
|
+
},
|
3716
|
+
|
3499
3717
|
adapterWillCommit: function() {
|
3500
3718
|
this.send('willCommit');
|
3501
3719
|
},
|
@@ -3541,6 +3759,7 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
3541
3759
|
var relationships = get(this.constructor, 'relationshipsByName');
|
3542
3760
|
this.updateRecordArraysLater();
|
3543
3761
|
relationships.forEach(function(name, relationship) {
|
3762
|
+
if (this._data.links && this._data.links[name]) { return; }
|
3544
3763
|
if (relationship.kind === 'hasMany') {
|
3545
3764
|
this.hasManyDidChange(relationship.key);
|
3546
3765
|
}
|
@@ -3551,8 +3770,6 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
3551
3770
|
var hasMany = this._relationships[key];
|
3552
3771
|
|
3553
3772
|
if (hasMany) {
|
3554
|
-
var type = get(this.constructor, 'relationshipsByName').get(key).type;
|
3555
|
-
var store = get(this, 'store');
|
3556
3773
|
var records = this._data[key] || [];
|
3557
3774
|
|
3558
3775
|
set(hasMany, 'content', Ember.A(records));
|
@@ -3575,6 +3792,7 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
3575
3792
|
var relationships = this._relationships;
|
3576
3793
|
|
3577
3794
|
this.eachRelationship(function(name, rel) {
|
3795
|
+
if (data.links && data.links[name]) { return; }
|
3578
3796
|
if (rel.options.async) { relationships[name] = null; }
|
3579
3797
|
});
|
3580
3798
|
|
@@ -3603,8 +3821,18 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
3603
3821
|
this.hasManyDidChange(name);
|
3604
3822
|
},
|
3605
3823
|
|
3824
|
+
updateBelongsTo: function(name, record) {
|
3825
|
+
this._data[name] = record;
|
3826
|
+
},
|
3827
|
+
|
3606
3828
|
rollback: function() {
|
3607
3829
|
this._attributes = {};
|
3830
|
+
|
3831
|
+
if (get(this, 'isError')) {
|
3832
|
+
this._inFlightAttributes = {};
|
3833
|
+
set(this, 'isError', false);
|
3834
|
+
}
|
3835
|
+
|
3608
3836
|
this.send('rolledBack');
|
3609
3837
|
|
3610
3838
|
this.suspendRelationshipObservers(function() {
|
@@ -3655,7 +3883,7 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
3655
3883
|
@method save
|
3656
3884
|
*/
|
3657
3885
|
save: function() {
|
3658
|
-
var resolver = Ember.RSVP.defer()
|
3886
|
+
var resolver = Ember.RSVP.defer();
|
3659
3887
|
|
3660
3888
|
this.get('store').scheduleSave(this, resolver);
|
3661
3889
|
this._inFlightAttributes = this._attributes;
|
@@ -3887,12 +4115,11 @@ DS.attr = function(type, options) {
|
|
3887
4115
|
options: options
|
3888
4116
|
};
|
3889
4117
|
|
3890
|
-
return Ember.computed(function(key, value
|
3891
|
-
var currentValue;
|
3892
|
-
|
4118
|
+
return Ember.computed(function(key, value) {
|
3893
4119
|
if (arguments.length > 1) {
|
3894
4120
|
Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('<type>')` from " + this.constructor.toString(), key !== 'id');
|
3895
|
-
|
4121
|
+
var oldValue = this._attributes[key] || this._inFlightAttributes[key] || this._data[key];
|
4122
|
+
this.send('didSetProperty', { name: key, oldValue: oldValue, originalValue: this._data[key], value: value });
|
3896
4123
|
this._attributes[key] = value;
|
3897
4124
|
return value;
|
3898
4125
|
} else if (hasValue(this, key)) {
|
@@ -4445,18 +4672,23 @@ var get = Ember.get, set = Ember.set,
|
|
4445
4672
|
function asyncBelongsTo(type, options, meta) {
|
4446
4673
|
return Ember.computed(function(key, value) {
|
4447
4674
|
var data = get(this, 'data'),
|
4448
|
-
store = get(this, 'store')
|
4449
|
-
belongsTo;
|
4675
|
+
store = get(this, 'store');
|
4450
4676
|
|
4451
4677
|
if (arguments.length === 2) {
|
4452
4678
|
Ember.assert("You can only add a '" + type + "' record to this relationship", !value || value instanceof store.modelFor(type));
|
4453
|
-
return value === undefined ? null : value;
|
4679
|
+
return value === undefined ? null : DS.PromiseObject.create({ promise: Ember.RSVP.resolve(value) });
|
4454
4680
|
}
|
4455
4681
|
|
4456
|
-
|
4682
|
+
var link = data.links && data.links[key],
|
4683
|
+
belongsTo = data[key];
|
4457
4684
|
|
4458
|
-
if(!isNone(belongsTo)
|
4459
|
-
|
4685
|
+
if(!isNone(belongsTo)) {
|
4686
|
+
var promise = store.fetchRecord(belongsTo) || Ember.RSVP.resolve(belongsTo);
|
4687
|
+
return DS.PromiseObject.create({promise: promise});
|
4688
|
+
} else if (link) {
|
4689
|
+
var resolver = Ember.RSVP.defer();
|
4690
|
+
store.findBelongsTo(this, link, meta, resolver);
|
4691
|
+
return DS.PromiseObject.create({ promise: resolver.promise });
|
4460
4692
|
} else {
|
4461
4693
|
return null;
|
4462
4694
|
}
|
@@ -4464,7 +4696,12 @@ function asyncBelongsTo(type, options, meta) {
|
|
4464
4696
|
}
|
4465
4697
|
|
4466
4698
|
DS.belongsTo = function(type, options) {
|
4467
|
-
|
4699
|
+
if (typeof type === 'object') {
|
4700
|
+
options = type;
|
4701
|
+
type = undefined;
|
4702
|
+
} else {
|
4703
|
+
Ember.assert("The first argument DS.belongsTo must be a model type or string, like DS.belongsTo(App.Person)", !!type && (typeof type === 'string' || DS.Model.detect(type)));
|
4704
|
+
}
|
4468
4705
|
|
4469
4706
|
options = options || {};
|
4470
4707
|
|
@@ -4479,11 +4716,7 @@ DS.belongsTo = function(type, options) {
|
|
4479
4716
|
store = get(this, 'store'), belongsTo, typeClass;
|
4480
4717
|
|
4481
4718
|
if (typeof type === 'string') {
|
4482
|
-
|
4483
|
-
typeClass = store.modelFor(type);
|
4484
|
-
} else {
|
4485
|
-
typeClass = get(Ember.lookup, type);
|
4486
|
-
}
|
4719
|
+
typeClass = store.modelFor(type);
|
4487
4720
|
} else {
|
4488
4721
|
typeClass = type;
|
4489
4722
|
}
|
@@ -4497,9 +4730,7 @@ DS.belongsTo = function(type, options) {
|
|
4497
4730
|
|
4498
4731
|
if (isNone(belongsTo)) { return null; }
|
4499
4732
|
|
4500
|
-
|
4501
|
-
store.fetchRecord(belongsTo);
|
4502
|
-
}
|
4733
|
+
store.fetchRecord(belongsTo);
|
4503
4734
|
|
4504
4735
|
return belongsTo;
|
4505
4736
|
}).property('data').meta(meta);
|
@@ -4523,11 +4754,12 @@ DS.Model.reopen({
|
|
4523
4754
|
*/
|
4524
4755
|
belongsToWillChange: Ember.beforeObserver(function(record, key) {
|
4525
4756
|
if (get(record, 'isLoaded')) {
|
4526
|
-
var oldParent = get(record, key)
|
4527
|
-
|
4757
|
+
var oldParent = get(record, key);
|
4758
|
+
|
4759
|
+
if (oldParent) {
|
4760
|
+
var store = get(record, 'store'),
|
4761
|
+
change = DS.RelationshipChange.createChange(record, oldParent, store, { key: key, kind: "belongsTo", changeType: "remove" });
|
4528
4762
|
|
4529
|
-
if (oldParent){
|
4530
|
-
var change = DS.RelationshipChange.createChange(record, oldParent, store, { key: key, kind: "belongsTo", changeType: "remove" });
|
4531
4763
|
change.sync();
|
4532
4764
|
this._changesToSync[key] = change;
|
4533
4765
|
}
|
@@ -4544,7 +4776,8 @@ DS.Model.reopen({
|
|
4544
4776
|
belongsToDidChange: Ember.immediateObserver(function(record, key) {
|
4545
4777
|
if (get(record, 'isLoaded')) {
|
4546
4778
|
var newParent = get(record, key);
|
4547
|
-
|
4779
|
+
|
4780
|
+
if (newParent) {
|
4548
4781
|
var store = get(record, 'store'),
|
4549
4782
|
change = DS.RelationshipChange.createChange(record, newParent, store, { key: key, kind: "belongsTo", changeType: "add" });
|
4550
4783
|
|
@@ -4566,10 +4799,11 @@ DS.Model.reopen({
|
|
4566
4799
|
*/
|
4567
4800
|
|
4568
4801
|
var get = Ember.get, set = Ember.set, setProperties = Ember.setProperties;
|
4569
|
-
var forEach = Ember.EnumerableUtils.forEach;
|
4570
4802
|
|
4571
4803
|
function asyncHasMany(type, options, meta) {
|
4572
4804
|
return Ember.computed(function(key, value) {
|
4805
|
+
if (this._relationships[key]) { return this._relationships[key]; }
|
4806
|
+
|
4573
4807
|
var resolver = Ember.RSVP.defer();
|
4574
4808
|
|
4575
4809
|
var relationship = buildRelationship(this, key, options, function(store, data) {
|
@@ -4617,14 +4851,17 @@ function hasRelationship(type, options) {
|
|
4617
4851
|
return Ember.computed(function(key, value) {
|
4618
4852
|
return buildRelationship(this, key, options, function(store, data) {
|
4619
4853
|
var records = data[key];
|
4620
|
-
Ember.assert("You looked up the '" + key + "' relationship on '" + this + "' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.
|
4854
|
+
Ember.assert("You looked up the '" + key + "' relationship on '" + this + "' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", Ember.A(records).everyProperty('isEmpty', false));
|
4621
4855
|
return store.findMany(this, data[key], meta.type);
|
4622
4856
|
});
|
4623
4857
|
}).property('data').meta(meta);
|
4624
4858
|
}
|
4625
4859
|
|
4626
4860
|
DS.hasMany = function(type, options) {
|
4627
|
-
|
4861
|
+
if (typeof type === 'object') {
|
4862
|
+
options = type;
|
4863
|
+
type = undefined;
|
4864
|
+
}
|
4628
4865
|
return hasRelationship(type, options);
|
4629
4866
|
};
|
4630
4867
|
|
@@ -4663,7 +4900,7 @@ DS.Model.reopen({
|
|
4663
4900
|
being defined. So, for example, when the user does this:
|
4664
4901
|
|
4665
4902
|
DS.Model.extend({
|
4666
|
-
parent: DS.belongsTo(
|
4903
|
+
parent: DS.belongsTo('user')
|
4667
4904
|
});
|
4668
4905
|
|
4669
4906
|
This hook would be called with "parent" as the key and the computed
|
@@ -4717,7 +4954,7 @@ DS.Model.reopenClass({
|
|
4717
4954
|
For example, if you define a model like this:
|
4718
4955
|
|
4719
4956
|
App.Post = DS.Model.extend({
|
4720
|
-
comments: DS.hasMany(
|
4957
|
+
comments: DS.hasMany('comment')
|
4721
4958
|
});
|
4722
4959
|
|
4723
4960
|
Calling `App.Post.typeForRelationship('comments')` will return `App.Comment`.
|
@@ -4791,9 +5028,9 @@ DS.Model.reopenClass({
|
|
4791
5028
|
For example, given the following model definition:
|
4792
5029
|
|
4793
5030
|
App.Blog = DS.Model.extend({
|
4794
|
-
users: DS.hasMany(
|
4795
|
-
owner: DS.belongsTo(
|
4796
|
-
posts: DS.hasMany(
|
5031
|
+
users: DS.hasMany('user'),
|
5032
|
+
owner: DS.belongsTo('user'),
|
5033
|
+
posts: DS.hasMany('post')
|
4797
5034
|
});
|
4798
5035
|
|
4799
5036
|
This computed property would return a map describing these
|
@@ -4823,7 +5060,7 @@ DS.Model.reopenClass({
|
|
4823
5060
|
// it to the map.
|
4824
5061
|
if (meta.isRelationship) {
|
4825
5062
|
if (typeof meta.type === 'string') {
|
4826
|
-
meta.type =
|
5063
|
+
meta.type = this.store.modelFor(meta.type);
|
4827
5064
|
}
|
4828
5065
|
|
4829
5066
|
var relationshipsForType = map.get(meta.type);
|
@@ -4841,10 +5078,10 @@ DS.Model.reopenClass({
|
|
4841
5078
|
definition:
|
4842
5079
|
|
4843
5080
|
App.Blog = DS.Model.extend({
|
4844
|
-
users: DS.hasMany(
|
4845
|
-
owner: DS.belongsTo(
|
5081
|
+
users: DS.hasMany('user'),
|
5082
|
+
owner: DS.belongsTo('user'),
|
4846
5083
|
|
4847
|
-
posts: DS.hasMany(
|
5084
|
+
posts: DS.hasMany('post')
|
4848
5085
|
});
|
4849
5086
|
|
4850
5087
|
This property would contain the following:
|
@@ -4880,9 +5117,10 @@ DS.Model.reopenClass({
|
|
4880
5117
|
For example, given a model with this definition:
|
4881
5118
|
|
4882
5119
|
App.Blog = DS.Model.extend({
|
4883
|
-
users: DS.hasMany(
|
4884
|
-
owner: DS.belongsTo(
|
4885
|
-
|
5120
|
+
users: DS.hasMany('user'),
|
5121
|
+
owner: DS.belongsTo('user'),
|
5122
|
+
|
5123
|
+
posts: DS.hasMany('post')
|
4886
5124
|
});
|
4887
5125
|
|
4888
5126
|
This property would contain the following:
|
@@ -4907,7 +5145,7 @@ DS.Model.reopenClass({
|
|
4907
5145
|
type = meta.type;
|
4908
5146
|
|
4909
5147
|
if (typeof type === 'string') {
|
4910
|
-
type = get(this, type, false) ||
|
5148
|
+
type = get(this, type, false) || this.store.modelFor(type);
|
4911
5149
|
}
|
4912
5150
|
|
4913
5151
|
Ember.assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", type);
|
@@ -4930,10 +5168,10 @@ DS.Model.reopenClass({
|
|
4930
5168
|
definition:
|
4931
5169
|
|
4932
5170
|
App.Blog = DS.Model.extend({
|
4933
|
-
users: DS.hasMany(
|
4934
|
-
owner: DS.belongsTo(
|
5171
|
+
users: DS.hasMany('user'),
|
5172
|
+
owner: DS.belongsTo('user'),
|
4935
5173
|
|
4936
|
-
posts: DS.hasMany(
|
5174
|
+
posts: DS.hasMany('post')
|
4937
5175
|
});
|
4938
5176
|
|
4939
5177
|
This property would contain the following:
|
@@ -4957,6 +5195,12 @@ DS.Model.reopenClass({
|
|
4957
5195
|
meta.key = name;
|
4958
5196
|
type = meta.type;
|
4959
5197
|
|
5198
|
+
if (!type && meta.kind === 'hasMany') {
|
5199
|
+
type = Ember.String.singularize(name);
|
5200
|
+
} else if (!type) {
|
5201
|
+
type = name;
|
5202
|
+
}
|
5203
|
+
|
4960
5204
|
if (typeof type === 'string') {
|
4961
5205
|
meta.type = this.store.modelFor(type);
|
4962
5206
|
}
|
@@ -4976,10 +5220,10 @@ DS.Model.reopenClass({
|
|
4976
5220
|
For example:
|
4977
5221
|
|
4978
5222
|
App.Blog = DS.Model.extend({
|
4979
|
-
users: DS.hasMany(
|
4980
|
-
owner: DS.belongsTo(
|
5223
|
+
users: DS.hasMany('user'),
|
5224
|
+
owner: DS.belongsTo('user'),
|
4981
5225
|
|
4982
|
-
posts: DS.hasMany(
|
5226
|
+
posts: DS.hasMany('post'),
|
4983
5227
|
|
4984
5228
|
title: DS.attr('string')
|
4985
5229
|
});
|
@@ -5285,9 +5529,8 @@ DS.RecordArrayManager = Ember.Object.extend({
|
|
5285
5529
|
@module ember-data
|
5286
5530
|
*/
|
5287
5531
|
|
5288
|
-
var get = Ember.get, set = Ember.set
|
5532
|
+
var get = Ember.get, set = Ember.set;
|
5289
5533
|
var map = Ember.ArrayPolyfills.map;
|
5290
|
-
var resolve = Ember.RSVP.resolve;
|
5291
5534
|
|
5292
5535
|
var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
|
5293
5536
|
|
@@ -5301,18 +5544,6 @@ DS.InvalidError = function(errors) {
|
|
5301
5544
|
};
|
5302
5545
|
DS.InvalidError.prototype = Ember.create(Error.prototype);
|
5303
5546
|
|
5304
|
-
function isThenable(object) {
|
5305
|
-
return object && typeof object.then === 'function';
|
5306
|
-
}
|
5307
|
-
|
5308
|
-
// Simple dispatcher to support overriding the aliased
|
5309
|
-
// method in subclasses.
|
5310
|
-
function aliasMethod(methodName) {
|
5311
|
-
return function() {
|
5312
|
-
return this[methodName].apply(this, arguments);
|
5313
|
-
};
|
5314
|
-
}
|
5315
|
-
|
5316
5547
|
/**
|
5317
5548
|
An adapter is an object that receives requests from a store and
|
5318
5549
|
translates them into the appropriate action to take against your
|
@@ -5366,8 +5597,8 @@ DS.Adapter = Ember.Object.extend(DS._Mappable, {
|
|
5366
5597
|
The `find()` method is invoked when the store is asked for a record that
|
5367
5598
|
has not previously been loaded. In response to `find()` being called, you
|
5368
5599
|
should query your persistence layer for a record with the given ID. Once
|
5369
|
-
found, you can asynchronously call the store's `
|
5370
|
-
the record.
|
5600
|
+
found, you can asynchronously call the store's `push()` method to push
|
5601
|
+
the record into the store.
|
5371
5602
|
|
5372
5603
|
Here is an example `find` implementation:
|
5373
5604
|
|
@@ -5378,8 +5609,8 @@ DS.Adapter = Ember.Object.extend(DS._Mappable, {
|
|
5378
5609
|
jQuery.getJSON(url, function(data) {
|
5379
5610
|
// data is a hash of key/value pairs. If your server returns a
|
5380
5611
|
// root, simply do something like:
|
5381
|
-
// store.
|
5382
|
-
store.
|
5612
|
+
// store.push(type, id, data.person)
|
5613
|
+
store.push(type, id, data);
|
5383
5614
|
});
|
5384
5615
|
}
|
5385
5616
|
|
@@ -5454,9 +5685,9 @@ DS.Adapter = Ember.Object.extend(DS._Mappable, {
|
|
5454
5685
|
method on success or `didError` method on failure.
|
5455
5686
|
|
5456
5687
|
@method createRecord
|
5457
|
-
@
|
5458
|
-
@
|
5459
|
-
@
|
5688
|
+
@param {DS.Store} store
|
5689
|
+
@param {subclass of DS.Model} type the DS.Model class of the record
|
5690
|
+
@param {DS.Model} record
|
5460
5691
|
*/
|
5461
5692
|
createRecord: Ember.required(Function),
|
5462
5693
|
|
@@ -5467,9 +5698,9 @@ DS.Adapter = Ember.Object.extend(DS._Mappable, {
|
|
5467
5698
|
Serializes the record update and send it to the server.
|
5468
5699
|
|
5469
5700
|
@method updateRecord
|
5470
|
-
@
|
5471
|
-
@
|
5472
|
-
@
|
5701
|
+
@param {DS.Store} store
|
5702
|
+
@param {subclass of DS.Model} type the DS.Model class of the record
|
5703
|
+
@param {DS.Model} record
|
5473
5704
|
*/
|
5474
5705
|
updateRecord: Ember.required(Function),
|
5475
5706
|
|
@@ -5480,9 +5711,9 @@ DS.Adapter = Ember.Object.extend(DS._Mappable, {
|
|
5480
5711
|
Sends a delete request for the record to the server.
|
5481
5712
|
|
5482
5713
|
@method deleteRecord
|
5483
|
-
@
|
5484
|
-
@
|
5485
|
-
@
|
5714
|
+
@param {DS.Store} store
|
5715
|
+
@param {subclass of DS.Model} type the DS.Model class of the record
|
5716
|
+
@param {DS.Model} record
|
5486
5717
|
*/
|
5487
5718
|
deleteRecord: Ember.required(Function),
|
5488
5719
|
|
@@ -5494,9 +5725,9 @@ DS.Adapter = Ember.Object.extend(DS._Mappable, {
|
|
5494
5725
|
server requests.
|
5495
5726
|
|
5496
5727
|
@method findMany
|
5497
|
-
@
|
5498
|
-
@
|
5499
|
-
@
|
5728
|
+
@param {DS.Store} store
|
5729
|
+
@param {subclass of DS.Model} type the DS.Model class of the records
|
5730
|
+
@param {Array} ids
|
5500
5731
|
*/
|
5501
5732
|
findMany: function(store, type, ids) {
|
5502
5733
|
var promises = map.call(ids, function(id) {
|
@@ -5593,7 +5824,7 @@ DS.FixtureAdapter = DS.Adapter.extend({
|
|
5593
5824
|
},
|
5594
5825
|
|
5595
5826
|
/**
|
5596
|
-
Implement this method in order to provide
|
5827
|
+
Implement this method in order to provide json for CRUD methods
|
5597
5828
|
|
5598
5829
|
@method mockJSON
|
5599
5830
|
@param type
|
@@ -5609,7 +5840,7 @@ DS.FixtureAdapter = DS.Adapter.extend({
|
|
5609
5840
|
@param record
|
5610
5841
|
*/
|
5611
5842
|
generateIdForRecord: function(store) {
|
5612
|
-
return counter++;
|
5843
|
+
return "fixture-" + counter++;
|
5613
5844
|
},
|
5614
5845
|
|
5615
5846
|
/**
|
@@ -5825,6 +6056,7 @@ DS.FixtureAdapter = DS.Adapter.extend({
|
|
5825
6056
|
|
5826
6057
|
var get = Ember.get, set = Ember.set;
|
5827
6058
|
var forEach = Ember.ArrayPolyfills.forEach;
|
6059
|
+
var map = Ember.ArrayPolyfills.map;
|
5828
6060
|
|
5829
6061
|
function coerceId(id) {
|
5830
6062
|
return id == null ? null : id+'';
|
@@ -5865,6 +6097,10 @@ function coerceId(id) {
|
|
5865
6097
|
You can also implement `keyForRelationship`, which takes the name
|
5866
6098
|
of the relationship as the first parameter, and the kind of
|
5867
6099
|
relationship (`hasMany` or `belongsTo`) as the second parameter.
|
6100
|
+
|
6101
|
+
@class RESTSerializer
|
6102
|
+
@namespace DS
|
6103
|
+
@extends DS.JSONSerializer
|
5868
6104
|
*/
|
5869
6105
|
DS.RESTSerializer = DS.JSONSerializer.extend({
|
5870
6106
|
/**
|
@@ -5944,6 +6180,31 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
5944
6180
|
return this._super(type, hash, prop);
|
5945
6181
|
},
|
5946
6182
|
|
6183
|
+
/**
|
6184
|
+
You can use this method to normalize all payloads, regardless of whether they
|
6185
|
+
represent single records or an array.
|
6186
|
+
|
6187
|
+
For example, you might want to remove some extraneous data from the payload:
|
6188
|
+
|
6189
|
+
```js
|
6190
|
+
App.ApplicationSerializer = DS.RESTSerializer.extend({
|
6191
|
+
normalizePayload: function(type, payload) {
|
6192
|
+
delete payload.version;
|
6193
|
+
delete payload.status;
|
6194
|
+
return payload;
|
6195
|
+
}
|
6196
|
+
});
|
6197
|
+
```
|
6198
|
+
|
6199
|
+
@method normalizePayload
|
6200
|
+
@param {subclass of DS.Model} type
|
6201
|
+
@param {Object} hash
|
6202
|
+
@returns Object the normalized payload
|
6203
|
+
*/
|
6204
|
+
normalizePayload: function(type, payload) {
|
6205
|
+
return payload;
|
6206
|
+
},
|
6207
|
+
|
5947
6208
|
/**
|
5948
6209
|
@method normalizeId
|
5949
6210
|
@private
|
@@ -6079,6 +6340,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
6079
6340
|
for the first time or updated (`createRecord` or `updateRecord`). In
|
6080
6341
|
particular, it will update the properties of the record that was saved.
|
6081
6342
|
|
6343
|
+
@method extractSingle
|
6082
6344
|
@param {DS.Store} store
|
6083
6345
|
@param {subclass of DS.Model} type
|
6084
6346
|
@param {Object} payload
|
@@ -6087,25 +6349,33 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
6087
6349
|
@returns Object the primary response to the original request
|
6088
6350
|
*/
|
6089
6351
|
extractSingle: function(store, primaryType, payload, recordId, requestType) {
|
6352
|
+
payload = this.normalizePayload(primaryType, payload);
|
6353
|
+
|
6090
6354
|
var primaryTypeName = primaryType.typeKey,
|
6091
6355
|
primaryRecord;
|
6092
6356
|
|
6093
6357
|
for (var prop in payload) {
|
6094
|
-
|
6095
|
-
|
6358
|
+
var typeName = this.typeForRoot(prop),
|
6359
|
+
isPrimary = typeName === primaryTypeName;
|
6360
|
+
|
6361
|
+
// legacy support for singular resources
|
6362
|
+
if (isPrimary && Ember.typeOf(payload[prop]) !== "array" ) {
|
6096
6363
|
primaryRecord = this.normalize(primaryType, payload[prop], prop);
|
6097
6364
|
continue;
|
6098
6365
|
}
|
6099
6366
|
|
6100
|
-
var
|
6101
|
-
type = store.modelFor(typeName);
|
6367
|
+
var type = store.modelFor(typeName);
|
6102
6368
|
|
6103
6369
|
/*jshint loopfunc:true*/
|
6104
6370
|
forEach.call(payload[prop], function(hash) {
|
6105
|
-
|
6371
|
+
var typeName = this.typeForRoot(prop),
|
6372
|
+
type = store.modelFor(typeName),
|
6373
|
+
typeSerializer = store.serializerFor(type);
|
6374
|
+
|
6375
|
+
hash = typeSerializer.normalize(type, hash, prop);
|
6106
6376
|
|
6107
|
-
var isFirstCreatedRecord =
|
6108
|
-
isUpdatedRecord =
|
6377
|
+
var isFirstCreatedRecord = isPrimary && !recordId && !primaryRecord,
|
6378
|
+
isUpdatedRecord = isPrimary && coerceId(hash.id) === recordId;
|
6109
6379
|
|
6110
6380
|
// find the primary record.
|
6111
6381
|
//
|
@@ -6212,6 +6482,12 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
6212
6482
|
or `findHasMany`. In particular, the primary array will become the
|
6213
6483
|
list of records in the record array that kicked off the request.
|
6214
6484
|
|
6485
|
+
If your primary array contains secondary (embedded) records of the same type,
|
6486
|
+
you cannot place these into the primary array `posts`. Instead, place the
|
6487
|
+
secondary items into an underscore prefixed property `_posts`, which will
|
6488
|
+
push these items into the store and will not affect the resulting query.
|
6489
|
+
|
6490
|
+
@method extractArray
|
6215
6491
|
@param {DS.Store} store
|
6216
6492
|
@param {subclass of DS.Model} type
|
6217
6493
|
@param {Object} payload
|
@@ -6220,17 +6496,28 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
6220
6496
|
to the original query.
|
6221
6497
|
*/
|
6222
6498
|
extractArray: function(store, primaryType, payload) {
|
6499
|
+
payload = this.normalizePayload(primaryType, payload);
|
6500
|
+
|
6223
6501
|
var primaryTypeName = primaryType.typeKey,
|
6224
6502
|
primaryArray;
|
6225
6503
|
|
6226
6504
|
for (var prop in payload) {
|
6227
|
-
var
|
6505
|
+
var typeKey = prop,
|
6506
|
+
forcedSecondary = false;
|
6507
|
+
|
6508
|
+
if (prop.charAt(0) === '_') {
|
6509
|
+
forcedSecondary = true;
|
6510
|
+
typeKey = prop.substr(1);
|
6511
|
+
}
|
6512
|
+
|
6513
|
+
var typeName = this.typeForRoot(typeKey),
|
6228
6514
|
type = store.modelFor(typeName),
|
6229
|
-
|
6515
|
+
typeSerializer = store.serializerFor(type),
|
6516
|
+
isPrimary = (!forcedSecondary && (typeName === primaryTypeName));
|
6230
6517
|
|
6231
6518
|
/*jshint loopfunc:true*/
|
6232
|
-
var normalizedArray = payload[prop]
|
6233
|
-
return
|
6519
|
+
var normalizedArray = map.call(payload[prop], function(hash) {
|
6520
|
+
return typeSerializer.normalize(type, hash, prop);
|
6234
6521
|
}, this);
|
6235
6522
|
|
6236
6523
|
if (isPrimary) {
|
@@ -6244,28 +6531,81 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
6244
6531
|
},
|
6245
6532
|
|
6246
6533
|
/**
|
6247
|
-
|
6248
|
-
|
6249
|
-
@param {String} key
|
6250
|
-
*/
|
6251
|
-
pluralize: function(key) {
|
6252
|
-
return Ember.String.pluralize(key);
|
6253
|
-
},
|
6534
|
+
This method allows you to push a payload containing top-level
|
6535
|
+
collections of records organized per type.
|
6254
6536
|
|
6255
|
-
|
6256
|
-
|
6257
|
-
|
6258
|
-
|
6259
|
-
|
6260
|
-
|
6261
|
-
|
6262
|
-
|
6537
|
+
```js
|
6538
|
+
{
|
6539
|
+
"posts": [{
|
6540
|
+
"id": "1",
|
6541
|
+
"title": "Rails is omakase",
|
6542
|
+
"author", "1",
|
6543
|
+
"comments": [ "1" ]
|
6544
|
+
}],
|
6545
|
+
"comments": [{
|
6546
|
+
"id": "1",
|
6547
|
+
"body": "FIRST
|
6548
|
+
}],
|
6549
|
+
"users": [{
|
6550
|
+
"id": "1",
|
6551
|
+
"name": "@d2h"
|
6552
|
+
}]
|
6553
|
+
}
|
6554
|
+
```
|
6263
6555
|
|
6264
|
-
|
6556
|
+
It will first normalize the payload, so you can use this to push
|
6557
|
+
in data streaming in from your server structured the same way
|
6558
|
+
that fetches and saves are structured.
|
6265
6559
|
|
6266
|
-
|
6267
|
-
|
6268
|
-
|
6560
|
+
@method pushPayload
|
6561
|
+
@param {DS.Store} store
|
6562
|
+
@param {Object} payload
|
6563
|
+
*/
|
6564
|
+
pushPayload: function(store, payload) {
|
6565
|
+
payload = this.normalizePayload(null, payload);
|
6566
|
+
|
6567
|
+
for (var prop in payload) {
|
6568
|
+
var typeName = this.typeForRoot(prop),
|
6569
|
+
type = store.modelFor(typeName);
|
6570
|
+
|
6571
|
+
/*jshint loopfunc:true*/
|
6572
|
+
var normalizedArray = map.call(payload[prop], function(hash) {
|
6573
|
+
return this.normalize(type, hash, prop);
|
6574
|
+
}, this);
|
6575
|
+
|
6576
|
+
store.pushMany(typeName, normalizedArray);
|
6577
|
+
}
|
6578
|
+
},
|
6579
|
+
|
6580
|
+
/**
|
6581
|
+
You can use this method to normalize the JSON root keys returned
|
6582
|
+
into the model type expected by your store.
|
6583
|
+
|
6584
|
+
For example, your server may return underscored root keys rather than
|
6585
|
+
the expected camelcased versions.
|
6586
|
+
|
6587
|
+
```js
|
6588
|
+
App.ApplicationSerializer = DS.RESTSerializer.extend({
|
6589
|
+
typeForRoot: function(root) {
|
6590
|
+
var camelized = Ember.String.camelize(root);
|
6591
|
+
return Ember.String.singularize(camelized);
|
6592
|
+
}
|
6593
|
+
});
|
6594
|
+
```
|
6595
|
+
|
6596
|
+
@method typeForRoot
|
6597
|
+
@param {String} root
|
6598
|
+
@returns String the model's typeKey
|
6599
|
+
*/
|
6600
|
+
typeForRoot: function(root) {
|
6601
|
+
return Ember.String.singularize(root);
|
6602
|
+
},
|
6603
|
+
|
6604
|
+
// SERIALIZE
|
6605
|
+
|
6606
|
+
/**
|
6607
|
+
Called when a record is saved in order to convert the
|
6608
|
+
record into JSON.
|
6269
6609
|
|
6270
6610
|
By default, it creates a JSON object with a key for
|
6271
6611
|
each attribute and belongsTo relationship.
|
@@ -6400,9 +6740,54 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
6400
6740
|
}
|
6401
6741
|
});
|
6402
6742
|
```
|
6743
|
+
|
6744
|
+
@method serialize
|
6745
|
+
@param record
|
6746
|
+
@param options
|
6403
6747
|
*/
|
6404
6748
|
serialize: function(record, options) {
|
6405
6749
|
return this._super.apply(this, arguments);
|
6750
|
+
},
|
6751
|
+
|
6752
|
+
/**
|
6753
|
+
You can use this method to customize the root keys serialized into the JSON.
|
6754
|
+
By default the REST Serializer sends camelized root keys.
|
6755
|
+
For example, your server may expect underscored root objects.
|
6756
|
+
|
6757
|
+
```js
|
6758
|
+
App.ApplicationSerializer = DS.RESTSerializer.extend({
|
6759
|
+
serializeIntoHash: function(data, type, record, options) {
|
6760
|
+
var root = Ember.String.decamelize(type.typeKey);
|
6761
|
+
data[root] = this.serialize(record, options);
|
6762
|
+
}
|
6763
|
+
});
|
6764
|
+
```
|
6765
|
+
|
6766
|
+
@method serializeIntoHash
|
6767
|
+
@param {Object} hash
|
6768
|
+
@param {subclass of DS.Model} type
|
6769
|
+
@param {DS.Model} record
|
6770
|
+
@param {Object} options
|
6771
|
+
*/
|
6772
|
+
serializeIntoHash: function(hash, type, record, options) {
|
6773
|
+
hash[type.typeKey] = this.serialize(record, options);
|
6774
|
+
},
|
6775
|
+
|
6776
|
+
/**
|
6777
|
+
You can use this method to customize how polymorphic objects are serialized.
|
6778
|
+
By default the JSON Serializer creates the key by appending `Type` to
|
6779
|
+
the attribute and value from the model's camelcased model name.
|
6780
|
+
|
6781
|
+
@method serializePolymorphicType
|
6782
|
+
@param {DS.Model} record
|
6783
|
+
@param {Object} json
|
6784
|
+
@param relationship
|
6785
|
+
*/
|
6786
|
+
serializePolymorphicType: function(record, json, relationship) {
|
6787
|
+
var key = relationship.key,
|
6788
|
+
belongsTo = get(record, key);
|
6789
|
+
key = this.keyForAttribute ? this.keyForAttribute(key) : key;
|
6790
|
+
json[key + "Type"] = belongsTo.constructor.typeKey;
|
6406
6791
|
}
|
6407
6792
|
});
|
6408
6793
|
|
@@ -6448,7 +6833,7 @@ var forEach = Ember.ArrayPolyfills.forEach;
|
|
6448
6833
|
|
6449
6834
|
### Conventional Names
|
6450
6835
|
|
6451
|
-
Attribute names in your JSON payload should be the
|
6836
|
+
Attribute names in your JSON payload should be the camelcased versions of
|
6452
6837
|
the attributes in your Ember.js models.
|
6453
6838
|
|
6454
6839
|
For example, if you have a `Person` model:
|
@@ -6466,8 +6851,8 @@ var forEach = Ember.ArrayPolyfills.forEach;
|
|
6466
6851
|
```js
|
6467
6852
|
{
|
6468
6853
|
"person": {
|
6469
|
-
"
|
6470
|
-
"
|
6854
|
+
"firstName": "Barack",
|
6855
|
+
"lastName": "Obama",
|
6471
6856
|
"occupation": "President"
|
6472
6857
|
}
|
6473
6858
|
}
|
@@ -6645,6 +7030,8 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6645
7030
|
This method will be called with the parent record and `/posts/1/comments`.
|
6646
7031
|
|
6647
7032
|
It will make an Ajax request to the originally specified URL.
|
7033
|
+
If the URL is host-relative (starting with a single slash), the
|
7034
|
+
request will use the host specified on the adapter (if any).
|
6648
7035
|
|
6649
7036
|
@method findHasMany
|
6650
7037
|
@see RESTAdapter/buildURL
|
@@ -6655,7 +7042,51 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6655
7042
|
@returns Promise
|
6656
7043
|
*/
|
6657
7044
|
findHasMany: function(store, record, url) {
|
6658
|
-
|
7045
|
+
var host = get(this, 'host'),
|
7046
|
+
id = get(record, 'id'),
|
7047
|
+
type = record.constructor.typeKey;
|
7048
|
+
|
7049
|
+
if (host && url.charAt(0) === '/' && url.charAt(1) !== '/') {
|
7050
|
+
url = host + url;
|
7051
|
+
}
|
7052
|
+
|
7053
|
+
return this.ajax(this.urlPrefix(url, this.buildURL(type, id)), 'GET');
|
7054
|
+
},
|
7055
|
+
|
7056
|
+
/**
|
7057
|
+
Called by the store in order to fetch a JSON array for
|
7058
|
+
the unloaded records in a belongs-to relationship that were originally
|
7059
|
+
specified as a URL (inside of `links`).
|
7060
|
+
|
7061
|
+
For example, if your original payload looks like this:
|
7062
|
+
|
7063
|
+
```js
|
7064
|
+
{
|
7065
|
+
"person": {
|
7066
|
+
"id": 1,
|
7067
|
+
"name": "Tom Dale",
|
7068
|
+
"links": { "group": "/people/1/group" }
|
7069
|
+
}
|
7070
|
+
}
|
7071
|
+
```
|
7072
|
+
|
7073
|
+
This method will be called with the parent record and `/people/1/group`.
|
7074
|
+
|
7075
|
+
It will make an Ajax request to the originally specified URL.
|
7076
|
+
|
7077
|
+
@method findBelongsTo
|
7078
|
+
@see RESTAdapter/buildURL
|
7079
|
+
@see RESTAdapter/ajax
|
7080
|
+
@param {DS.Store} store
|
7081
|
+
@param {DS.Model} record
|
7082
|
+
@param {String} url
|
7083
|
+
@returns Promise
|
7084
|
+
*/
|
7085
|
+
findBelongsTo: function(store, record, url) {
|
7086
|
+
var id = get(record, 'id'),
|
7087
|
+
type = record.constructor.typeKey;
|
7088
|
+
|
7089
|
+
return this.ajax(this.urlPrefix(url, this.buildURL(type, id)), 'GET');
|
6659
7090
|
},
|
6660
7091
|
|
6661
7092
|
/**
|
@@ -6678,7 +7109,9 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6678
7109
|
*/
|
6679
7110
|
createRecord: function(store, type, record) {
|
6680
7111
|
var data = {};
|
6681
|
-
|
7112
|
+
var serializer = store.serializerFor(type.typeKey);
|
7113
|
+
|
7114
|
+
serializer.serializeIntoHash(data, type, record, { includeId: true });
|
6682
7115
|
|
6683
7116
|
return this.ajax(this.buildURL(type.typeKey), "POST", { data: data });
|
6684
7117
|
},
|
@@ -6702,7 +7135,9 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6702
7135
|
*/
|
6703
7136
|
updateRecord: function(store, type, record) {
|
6704
7137
|
var data = {};
|
6705
|
-
|
7138
|
+
var serializer = store.serializerFor(type.typeKey);
|
7139
|
+
|
7140
|
+
serializer.serializeIntoHash(data, type, record);
|
6706
7141
|
|
6707
7142
|
var id = get(record, 'id');
|
6708
7143
|
|
@@ -6732,7 +7167,10 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6732
7167
|
/**
|
6733
7168
|
Builds a URL for a given type and optional ID.
|
6734
7169
|
|
6735
|
-
|
7170
|
+
By default, it pluralizes the type's name (for example,
|
7171
|
+
'post' becomes 'posts' and 'person' becomes 'people').
|
7172
|
+
|
7173
|
+
If an ID is specified, it adds the ID to the path generated
|
6736
7174
|
for the type, separated by a `/`.
|
6737
7175
|
|
6738
7176
|
@method buildURL
|
@@ -6741,50 +7179,95 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6741
7179
|
@returns String
|
6742
7180
|
*/
|
6743
7181
|
buildURL: function(type, id) {
|
6744
|
-
var
|
6745
|
-
|
6746
|
-
|
6747
|
-
|
6748
|
-
if (host) { url.push(host); }
|
6749
|
-
if (namespace) { url.push(namespace); }
|
7182
|
+
var url = [],
|
7183
|
+
host = get(this, 'host'),
|
7184
|
+
prefix = this.urlPrefix();
|
6750
7185
|
|
6751
|
-
url.push(this.
|
7186
|
+
if (type) { url.push(this.pathForType(type)); }
|
6752
7187
|
if (id) { url.push(id); }
|
6753
7188
|
|
7189
|
+
if (prefix) { url.unshift(prefix); }
|
7190
|
+
|
6754
7191
|
url = url.join('/');
|
6755
|
-
if (!host) { url = '/' + url; }
|
7192
|
+
if (!host && url) { url = '/' + url; }
|
6756
7193
|
|
6757
7194
|
return url;
|
6758
7195
|
},
|
6759
7196
|
|
7197
|
+
urlPrefix: function(path, parentURL) {
|
7198
|
+
var host = get(this, 'host'),
|
7199
|
+
namespace = get(this, 'namespace'),
|
7200
|
+
url = [];
|
7201
|
+
|
7202
|
+
if (path) {
|
7203
|
+
// Absolute path
|
7204
|
+
if (path.charAt(0) === '/') {
|
7205
|
+
if (host) {
|
7206
|
+
path = path.slice(1);
|
7207
|
+
url.push(host);
|
7208
|
+
}
|
7209
|
+
// Relative path
|
7210
|
+
} else if (!/^http(s)?:\/\//.test(path)) {
|
7211
|
+
url.push(parentURL);
|
7212
|
+
}
|
7213
|
+
} else {
|
7214
|
+
if (host) { url.push(host); }
|
7215
|
+
if (namespace) { url.push(namespace); }
|
7216
|
+
}
|
7217
|
+
|
7218
|
+
if (path) {
|
7219
|
+
url.push(path);
|
7220
|
+
}
|
7221
|
+
|
7222
|
+
return url.join('/');
|
7223
|
+
},
|
7224
|
+
|
6760
7225
|
/**
|
6761
|
-
Determines the pathname
|
7226
|
+
Determines the pathname for a given type.
|
6762
7227
|
|
6763
7228
|
By default, it pluralizes the type's name (for example,
|
6764
7229
|
'post' becomes 'posts' and 'person' becomes 'people').
|
6765
7230
|
|
6766
|
-
### Pathname
|
7231
|
+
### Pathname customization
|
6767
7232
|
|
6768
7233
|
For example if you have an object LineItem with an
|
6769
7234
|
endpoint of "/line_items/".
|
6770
7235
|
|
6771
7236
|
```js
|
6772
7237
|
DS.RESTAdapter.reopen({
|
6773
|
-
|
7238
|
+
pathForType: function(type) {
|
6774
7239
|
var decamelized = Ember.String.decamelize(type);
|
6775
7240
|
return Ember.String.pluralize(decamelized);
|
6776
7241
|
};
|
6777
7242
|
});
|
6778
7243
|
```
|
6779
7244
|
|
6780
|
-
@method
|
7245
|
+
@method pathForType
|
6781
7246
|
@param {String} type
|
6782
7247
|
@returns String
|
6783
7248
|
**/
|
6784
|
-
|
7249
|
+
pathForType: function(type) {
|
6785
7250
|
return Ember.String.pluralize(type);
|
6786
7251
|
},
|
6787
7252
|
|
7253
|
+
/**
|
7254
|
+
Takes an ajax response, and returns a relavant error.
|
7255
|
+
|
7256
|
+
By default, it has the following behavior:
|
7257
|
+
|
7258
|
+
* It simply returns the ajax response.
|
7259
|
+
|
7260
|
+
@method ajaxError
|
7261
|
+
@param jqXHR
|
7262
|
+
*/
|
7263
|
+
ajaxError: function(jqXHR) {
|
7264
|
+
if (jqXHR) {
|
7265
|
+
jqXHR.then = null;
|
7266
|
+
}
|
7267
|
+
|
7268
|
+
return jqXHR;
|
7269
|
+
},
|
7270
|
+
|
6788
7271
|
/**
|
6789
7272
|
Takes a URL, an HTTP method and a hash of data, and makes an
|
6790
7273
|
HTTP request.
|
@@ -6812,40 +7295,43 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6812
7295
|
var adapter = this;
|
6813
7296
|
|
6814
7297
|
return new Ember.RSVP.Promise(function(resolve, reject) {
|
6815
|
-
hash =
|
6816
|
-
hash.url = url;
|
6817
|
-
hash.type = type;
|
6818
|
-
hash.dataType = 'json';
|
6819
|
-
hash.context = adapter;
|
6820
|
-
|
6821
|
-
if (hash.data && type !== 'GET') {
|
6822
|
-
hash.contentType = 'application/json; charset=utf-8';
|
6823
|
-
hash.data = JSON.stringify(hash.data);
|
6824
|
-
}
|
6825
|
-
|
6826
|
-
if (adapter.headers !== undefined) {
|
6827
|
-
var headers = adapter.headers;
|
6828
|
-
hash.beforeSend = function (xhr) {
|
6829
|
-
forEach.call(Ember.keys(headers), function(key) {
|
6830
|
-
xhr.setRequestHeader(key, headers[key]);
|
6831
|
-
});
|
6832
|
-
};
|
6833
|
-
}
|
7298
|
+
hash = adapter.ajaxOptions(url, type, hash);
|
6834
7299
|
|
6835
7300
|
hash.success = function(json) {
|
6836
7301
|
Ember.run(null, resolve, json);
|
6837
7302
|
};
|
6838
7303
|
|
6839
7304
|
hash.error = function(jqXHR, textStatus, errorThrown) {
|
6840
|
-
|
6841
|
-
jqXHR.then = null;
|
6842
|
-
}
|
6843
|
-
|
6844
|
-
Ember.run(null, reject, jqXHR);
|
7305
|
+
Ember.run(null, reject, adapter.ajaxError(jqXHR));
|
6845
7306
|
};
|
6846
7307
|
|
6847
7308
|
Ember.$.ajax(hash);
|
6848
7309
|
});
|
7310
|
+
},
|
7311
|
+
|
7312
|
+
ajaxOptions: function(url, type, hash) {
|
7313
|
+
hash = hash || {};
|
7314
|
+
hash.url = url;
|
7315
|
+
hash.type = type;
|
7316
|
+
hash.dataType = 'json';
|
7317
|
+
hash.context = this;
|
7318
|
+
|
7319
|
+
if (hash.data && type !== 'GET') {
|
7320
|
+
hash.contentType = 'application/json; charset=utf-8';
|
7321
|
+
hash.data = JSON.stringify(hash.data);
|
7322
|
+
}
|
7323
|
+
|
7324
|
+
if (this.headers !== undefined) {
|
7325
|
+
var headers = this.headers;
|
7326
|
+
hash.beforeSend = function (xhr) {
|
7327
|
+
forEach.call(Ember.keys(headers), function(key) {
|
7328
|
+
xhr.setRequestHeader(key, headers[key]);
|
7329
|
+
});
|
7330
|
+
};
|
7331
|
+
}
|
7332
|
+
|
7333
|
+
|
7334
|
+
return hash;
|
6849
7335
|
}
|
6850
7336
|
|
6851
7337
|
});
|
@@ -6867,16 +7353,20 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6867
7353
|
DS.Model.reopen({
|
6868
7354
|
|
6869
7355
|
/**
|
6870
|
-
|
6871
|
-
|
7356
|
+
Provides info about the model for debugging purposes
|
7357
|
+
by grouping the properties into more semantic groups.
|
6872
7358
|
|
6873
|
-
|
7359
|
+
Meant to be used by debugging tools such as the Chrome Ember Extension.
|
6874
7360
|
|
6875
|
-
|
6876
|
-
|
6877
|
-
|
6878
|
-
|
6879
|
-
|
7361
|
+
- Groups all attributes in "Attributes" group.
|
7362
|
+
- Groups all belongsTo relationships in "Belongs To" group.
|
7363
|
+
- Groups all hasMany relationships in "Has Many" group.
|
7364
|
+
- Groups all flags in "Flags" group.
|
7365
|
+
- Flags relationship CPs as expensive properties.
|
7366
|
+
|
7367
|
+
@method _debugInfo
|
7368
|
+
@for DS.Model
|
7369
|
+
@private
|
6880
7370
|
*/
|
6881
7371
|
_debugInfo: function() {
|
6882
7372
|
var attributes = ['id'],
|
@@ -6896,7 +7386,7 @@ DS.Model.reopen({
|
|
6896
7386
|
{
|
6897
7387
|
name: 'Attributes',
|
6898
7388
|
properties: attributes,
|
6899
|
-
expand: true
|
7389
|
+
expand: true
|
6900
7390
|
},
|
6901
7391
|
{
|
6902
7392
|
name: 'Belongs To',
|
@@ -6941,26 +7431,6 @@ DS.Model.reopen({
|
|
6941
7431
|
|
6942
7432
|
|
6943
7433
|
(function() {
|
6944
|
-
//Copyright (C) 2011 by Living Social, Inc.
|
6945
|
-
|
6946
|
-
//Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6947
|
-
//this software and associated documentation files (the "Software"), to deal in
|
6948
|
-
//the Software without restriction, including without limitation the rights to
|
6949
|
-
//use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
6950
|
-
//of the Software, and to permit persons to whom the Software is furnished to do
|
6951
|
-
//so, subject to the following conditions:
|
6952
|
-
|
6953
|
-
//The above copyright notice and this permission notice shall be included in all
|
6954
|
-
//copies or substantial portions of the Software.
|
6955
|
-
|
6956
|
-
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
6957
|
-
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
6958
|
-
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
6959
|
-
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
6960
|
-
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
6961
|
-
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
6962
|
-
//SOFTWARE.
|
6963
|
-
|
6964
7434
|
/**
|
6965
7435
|
Ember Data
|
6966
7436
|
|
@@ -7003,6 +7473,64 @@ function loadIrregular(rules, irregularPairs) {
|
|
7003
7473
|
}
|
7004
7474
|
}
|
7005
7475
|
|
7476
|
+
/**
|
7477
|
+
Inflector.Ember provides a mechanism for supplying inflection rules for your
|
7478
|
+
application. Ember includes a default set of inflection rules, and provides an
|
7479
|
+
API for providing additional rules.
|
7480
|
+
|
7481
|
+
Examples:
|
7482
|
+
|
7483
|
+
Creating an inflector with no rules.
|
7484
|
+
|
7485
|
+
```js
|
7486
|
+
var inflector = new Ember.Inflector();
|
7487
|
+
```
|
7488
|
+
|
7489
|
+
Creating an inflector with the default ember ruleset.
|
7490
|
+
|
7491
|
+
```js
|
7492
|
+
var inflector = new Ember.Inflector(Ember.Inflector.defaultRules);
|
7493
|
+
|
7494
|
+
inflector.pluralize('cow') //=> 'kine'
|
7495
|
+
inflector.singularize('kine') //=> 'cow'
|
7496
|
+
```
|
7497
|
+
|
7498
|
+
Creating an inflector and adding rules later.
|
7499
|
+
|
7500
|
+
```javascript
|
7501
|
+
var inflector = Ember.Inflector.inflector;
|
7502
|
+
|
7503
|
+
inflector.pluralize('advice') // => 'advices'
|
7504
|
+
inflector.uncountable('advice');
|
7505
|
+
inflector.pluralize('advice') // => 'advice'
|
7506
|
+
|
7507
|
+
inflector.pluralize('formula') // => 'formulas'
|
7508
|
+
inflector.irregular('formula', 'formulae');
|
7509
|
+
inflector.pluralize('formula') // => 'formulae'
|
7510
|
+
|
7511
|
+
// you would not need to add these as they are the default rules
|
7512
|
+
inflector.plural(/$/, 's');
|
7513
|
+
inflector.singular(/s$/i, '');
|
7514
|
+
```
|
7515
|
+
|
7516
|
+
Creating an inflector with a nondefault ruleset.
|
7517
|
+
|
7518
|
+
```javascript
|
7519
|
+
var rules = {
|
7520
|
+
plurals: [ /$/, 's' ],
|
7521
|
+
singular: [ /\s$/, '' ],
|
7522
|
+
irregularPairs: [
|
7523
|
+
[ 'cow', 'kine' ]
|
7524
|
+
],
|
7525
|
+
uncountable: [ 'fish' ]
|
7526
|
+
};
|
7527
|
+
|
7528
|
+
var inflector = new Ember.Inflector(rules);
|
7529
|
+
```
|
7530
|
+
|
7531
|
+
@class Inflector
|
7532
|
+
@namespace Ember
|
7533
|
+
*/
|
7006
7534
|
function Inflector(ruleSet) {
|
7007
7535
|
ruleSet = ruleSet || {};
|
7008
7536
|
ruleSet.uncountable = ruleSet.uncountable || {};
|
@@ -7021,15 +7549,66 @@ function Inflector(ruleSet) {
|
|
7021
7549
|
}
|
7022
7550
|
|
7023
7551
|
Inflector.prototype = {
|
7552
|
+
/**
|
7553
|
+
@method plural
|
7554
|
+
@param {RegExp} regex
|
7555
|
+
@param {String} string
|
7556
|
+
*/
|
7557
|
+
plural: function(regex, string) {
|
7558
|
+
this.rules.plurals.push([regex, string]);
|
7559
|
+
},
|
7560
|
+
|
7561
|
+
/**
|
7562
|
+
@method singular
|
7563
|
+
@param {RegExp} regex
|
7564
|
+
@param {String} string
|
7565
|
+
*/
|
7566
|
+
singular: function(regex, string) {
|
7567
|
+
this.rules.singular.push([regex, string]);
|
7568
|
+
},
|
7569
|
+
|
7570
|
+
/**
|
7571
|
+
@method uncountable
|
7572
|
+
@param {String} regex
|
7573
|
+
*/
|
7574
|
+
uncountable: function(string) {
|
7575
|
+
loadUncountable(this.rules, [string]);
|
7576
|
+
},
|
7577
|
+
|
7578
|
+
/**
|
7579
|
+
@method irregular
|
7580
|
+
@param {String} singular
|
7581
|
+
@param {String} plural
|
7582
|
+
*/
|
7583
|
+
irregular: function (singular, plural) {
|
7584
|
+
loadIrregular(this.rules, [[singular, plural]]);
|
7585
|
+
},
|
7586
|
+
|
7587
|
+
/**
|
7588
|
+
@method pluralize
|
7589
|
+
@param {String} word
|
7590
|
+
*/
|
7024
7591
|
pluralize: function(word) {
|
7025
|
-
return this.inflect(word, this.rules.plurals);
|
7592
|
+
return this.inflect(word, this.rules.plurals, this.rules.irregular);
|
7026
7593
|
},
|
7027
7594
|
|
7595
|
+
/**
|
7596
|
+
@method singularize
|
7597
|
+
@param {String} word
|
7598
|
+
*/
|
7028
7599
|
singularize: function(word) {
|
7029
|
-
return this.inflect(word, this.rules.singular);
|
7600
|
+
return this.inflect(word, this.rules.singular, this.rules.irregularInverse);
|
7030
7601
|
},
|
7031
7602
|
|
7032
|
-
|
7603
|
+
/**
|
7604
|
+
@protected
|
7605
|
+
|
7606
|
+
@method inflect
|
7607
|
+
@param {String} word
|
7608
|
+
@param {Object} typeRules
|
7609
|
+
@param {Object} irregular
|
7610
|
+
*/
|
7611
|
+
inflect: function(word, typeRules, irregular) {
|
7033
7612
|
var inflection, substitution, result, lowercase, isBlank,
|
7034
7613
|
isUncountable, isIrregular, isIrregularInverse, rule;
|
7035
7614
|
|
@@ -7047,18 +7626,12 @@ Inflector.prototype = {
|
|
7047
7626
|
return word;
|
7048
7627
|
}
|
7049
7628
|
|
7050
|
-
isIrregular =
|
7629
|
+
isIrregular = irregular && irregular[lowercase];
|
7051
7630
|
|
7052
7631
|
if (isIrregular) {
|
7053
7632
|
return isIrregular;
|
7054
7633
|
}
|
7055
7634
|
|
7056
|
-
isIrregularInverse = this.rules.irregularInverse[lowercase];
|
7057
|
-
|
7058
|
-
if (isIrregularInverse) {
|
7059
|
-
return isIrregularInverse;
|
7060
|
-
}
|
7061
|
-
|
7062
7635
|
for (var i = typeRules.length, min = 0; i > min; i--) {
|
7063
7636
|
inflection = typeRules[i-1];
|
7064
7637
|
rule = inflection[0];
|
@@ -7170,7 +7743,7 @@ Ember.Inflector.defaultRules = {
|
|
7170
7743
|
|
7171
7744
|
|
7172
7745
|
(function() {
|
7173
|
-
if (Ember.EXTEND_PROTOTYPES) {
|
7746
|
+
if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) {
|
7174
7747
|
/**
|
7175
7748
|
See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}}
|
7176
7749
|
|
@@ -7203,6 +7776,363 @@ Ember.Inflector.inflector = new Ember.Inflector(Ember.Inflector.defaultRules);
|
|
7203
7776
|
|
7204
7777
|
|
7205
7778
|
|
7779
|
+
(function() {
|
7780
|
+
|
7781
|
+
})();
|
7782
|
+
|
7783
|
+
(function() {
|
7784
|
+
/**
|
7785
|
+
@module ember-data
|
7786
|
+
*/
|
7787
|
+
|
7788
|
+
var get = Ember.get;
|
7789
|
+
var forEach = Ember.EnumerableUtils.forEach;
|
7790
|
+
|
7791
|
+
DS.ActiveModelSerializer = DS.RESTSerializer.extend({
|
7792
|
+
// SERIALIZE
|
7793
|
+
|
7794
|
+
/**
|
7795
|
+
Converts camelcased attributes to underscored when serializing.
|
7796
|
+
|
7797
|
+
@method keyForAttribute
|
7798
|
+
@param {String} attribute
|
7799
|
+
@returns String
|
7800
|
+
*/
|
7801
|
+
keyForAttribute: function(attr) {
|
7802
|
+
return Ember.String.decamelize(attr);
|
7803
|
+
},
|
7804
|
+
|
7805
|
+
/**
|
7806
|
+
Underscores relationship names and appends "_id" or "_ids" when serializing
|
7807
|
+
relationship keys.
|
7808
|
+
|
7809
|
+
@method keyForRelationship
|
7810
|
+
@param {String} key
|
7811
|
+
@param {String} kind
|
7812
|
+
@returns String
|
7813
|
+
*/
|
7814
|
+
keyForRelationship: function(key, kind) {
|
7815
|
+
key = Ember.String.decamelize(key);
|
7816
|
+
if (kind === "belongsTo") {
|
7817
|
+
return key + "_id";
|
7818
|
+
} else if (kind === "hasMany") {
|
7819
|
+
return Ember.String.singularize(key) + "_ids";
|
7820
|
+
} else {
|
7821
|
+
return key;
|
7822
|
+
}
|
7823
|
+
},
|
7824
|
+
|
7825
|
+
/**
|
7826
|
+
Serialize has-may relationship when it is configured as embedded objects.
|
7827
|
+
|
7828
|
+
@method serializeHasMany
|
7829
|
+
*/
|
7830
|
+
serializeHasMany: function(record, json, relationship) {
|
7831
|
+
var key = relationship.key,
|
7832
|
+
attrs = get(this, 'attrs'),
|
7833
|
+
embed = attrs && attrs[key] && attrs[key].embedded === 'always';
|
7834
|
+
|
7835
|
+
if (embed) {
|
7836
|
+
json[this.keyForAttribute(key)] = get(record, key).map(function(relation) {
|
7837
|
+
var data = relation.serialize(),
|
7838
|
+
primaryKey = get(this, 'primaryKey');
|
7839
|
+
|
7840
|
+
data[primaryKey] = get(relation, primaryKey);
|
7841
|
+
|
7842
|
+
return data;
|
7843
|
+
}, this);
|
7844
|
+
}
|
7845
|
+
},
|
7846
|
+
|
7847
|
+
/**
|
7848
|
+
Underscores the JSON root keys when serializing.
|
7849
|
+
|
7850
|
+
@method serializeIntoHash
|
7851
|
+
@param {Object} hash
|
7852
|
+
@param {subclass of DS.Model} type
|
7853
|
+
@param {DS.Model} record
|
7854
|
+
@param {Object} options
|
7855
|
+
*/
|
7856
|
+
serializeIntoHash: function(data, type, record, options) {
|
7857
|
+
var root = Ember.String.decamelize(type.typeKey);
|
7858
|
+
data[root] = this.serialize(record, options);
|
7859
|
+
},
|
7860
|
+
|
7861
|
+
/**
|
7862
|
+
Serializes a polymorphic type as a fully capitalized model name.
|
7863
|
+
|
7864
|
+
@method serializePolymorphicType
|
7865
|
+
@param {DS.Model} record
|
7866
|
+
@param {Object} json
|
7867
|
+
@param relationship
|
7868
|
+
*/
|
7869
|
+
serializePolymorphicType: function(record, json, relationship) {
|
7870
|
+
var key = relationship.key,
|
7871
|
+
belongsTo = get(record, key);
|
7872
|
+
key = this.keyForAttribute(key);
|
7873
|
+
json[key + "_type"] = Ember.String.capitalize(belongsTo.constructor.typeKey);
|
7874
|
+
},
|
7875
|
+
|
7876
|
+
// EXTRACT
|
7877
|
+
|
7878
|
+
/**
|
7879
|
+
Extracts the model typeKey from underscored root objects.
|
7880
|
+
|
7881
|
+
@method typeForRoot
|
7882
|
+
@param {String} root
|
7883
|
+
@returns String the model's typeKey
|
7884
|
+
*/
|
7885
|
+
typeForRoot: function(root) {
|
7886
|
+
var camelized = Ember.String.camelize(root);
|
7887
|
+
return Ember.String.singularize(camelized);
|
7888
|
+
},
|
7889
|
+
|
7890
|
+
/**
|
7891
|
+
Normalize the polymorphic type from the JSON.
|
7892
|
+
|
7893
|
+
Normalize:
|
7894
|
+
```js
|
7895
|
+
{
|
7896
|
+
id: "1"
|
7897
|
+
minion: { type: "evil_minion", id: "12"}
|
7898
|
+
}
|
7899
|
+
```
|
7900
|
+
|
7901
|
+
To:
|
7902
|
+
```js
|
7903
|
+
{
|
7904
|
+
id: "1"
|
7905
|
+
minion: { type: "evilMinion", id: "12"}
|
7906
|
+
}
|
7907
|
+
```
|
7908
|
+
|
7909
|
+
@method normalizeRelationships
|
7910
|
+
@private
|
7911
|
+
*/
|
7912
|
+
normalizeRelationships: function(type, hash) {
|
7913
|
+
var payloadKey, payload;
|
7914
|
+
|
7915
|
+
if (this.keyForRelationship) {
|
7916
|
+
type.eachRelationship(function(key, relationship) {
|
7917
|
+
if (relationship.options.polymorphic) {
|
7918
|
+
payloadKey = this.keyForAttribute(key);
|
7919
|
+
payload = hash[payloadKey];
|
7920
|
+
if (payload && payload.type) {
|
7921
|
+
payload.type = this.typeForRoot(payload.type);
|
7922
|
+
} else if (payload && relationship.kind === "hasMany") {
|
7923
|
+
var self = this;
|
7924
|
+
forEach(payload, function(single) {
|
7925
|
+
single.type = self.typeForRoot(single.type);
|
7926
|
+
});
|
7927
|
+
}
|
7928
|
+
} else {
|
7929
|
+
payloadKey = this.keyForRelationship(key, relationship.kind);
|
7930
|
+
payload = hash[payloadKey];
|
7931
|
+
}
|
7932
|
+
|
7933
|
+
hash[key] = payload;
|
7934
|
+
|
7935
|
+
if (key !== payloadKey) {
|
7936
|
+
delete hash[payloadKey];
|
7937
|
+
}
|
7938
|
+
}, this);
|
7939
|
+
}
|
7940
|
+
},
|
7941
|
+
|
7942
|
+
extractSingle: function(store, primaryType, payload, recordId, requestType) {
|
7943
|
+
var root = this.keyForAttribute(primaryType.typeKey),
|
7944
|
+
partial = payload[root];
|
7945
|
+
|
7946
|
+
updatePayloadWithEmbedded(store, this, primaryType, partial, payload);
|
7947
|
+
|
7948
|
+
return this._super(store, primaryType, payload, recordId, requestType);
|
7949
|
+
},
|
7950
|
+
|
7951
|
+
extractArray: function(store, type, payload) {
|
7952
|
+
var root = this.keyForAttribute(type.typeKey),
|
7953
|
+
partials = payload[Ember.String.pluralize(root)];
|
7954
|
+
|
7955
|
+
forEach(partials, function(partial) {
|
7956
|
+
updatePayloadWithEmbedded(store, this, type, partial, payload);
|
7957
|
+
}, this);
|
7958
|
+
|
7959
|
+
return this._super(store, type, payload);
|
7960
|
+
}
|
7961
|
+
});
|
7962
|
+
|
7963
|
+
function updatePayloadWithEmbedded(store, serializer, type, partial, payload) {
|
7964
|
+
var attrs = get(serializer, 'attrs');
|
7965
|
+
|
7966
|
+
if (!attrs) {
|
7967
|
+
return;
|
7968
|
+
}
|
7969
|
+
|
7970
|
+
type.eachRelationship(function(key, relationship) {
|
7971
|
+
var expandedKey, embeddedTypeKey, attribute, ids,
|
7972
|
+
config = attrs[key],
|
7973
|
+
serializer = store.serializerFor(relationship.type.typeKey),
|
7974
|
+
primaryKey = get(serializer, "primaryKey");
|
7975
|
+
|
7976
|
+
if (relationship.kind !== "hasMany") {
|
7977
|
+
return;
|
7978
|
+
}
|
7979
|
+
|
7980
|
+
if (config && (config.embedded === 'always' || config.embedded === 'load')) {
|
7981
|
+
// underscore forces the embedded records to be side loaded.
|
7982
|
+
// it is needed when main type === relationship.type
|
7983
|
+
embeddedTypeKey = '_' + Ember.String.pluralize(relationship.type.typeKey);
|
7984
|
+
expandedKey = this.keyForRelationship(key, relationship.kind);
|
7985
|
+
attribute = this.keyForAttribute(key);
|
7986
|
+
ids = [];
|
7987
|
+
|
7988
|
+
if (!partial[attribute]) {
|
7989
|
+
return;
|
7990
|
+
}
|
7991
|
+
|
7992
|
+
payload[embeddedTypeKey] = payload[embeddedTypeKey] || [];
|
7993
|
+
|
7994
|
+
forEach(partial[attribute], function(data) {
|
7995
|
+
var embeddedType = store.modelFor(relationship.type.typeKey);
|
7996
|
+
updatePayloadWithEmbedded(store, serializer, embeddedType, data, payload);
|
7997
|
+
ids.push(data[primaryKey]);
|
7998
|
+
payload[embeddedTypeKey].push(data);
|
7999
|
+
});
|
8000
|
+
|
8001
|
+
partial[expandedKey] = ids;
|
8002
|
+
delete partial[attribute];
|
8003
|
+
}
|
8004
|
+
}, serializer);
|
8005
|
+
}
|
8006
|
+
|
8007
|
+
})();
|
8008
|
+
|
8009
|
+
|
8010
|
+
|
8011
|
+
(function() {
|
8012
|
+
/**
|
8013
|
+
@module ember-data
|
8014
|
+
*/
|
8015
|
+
|
8016
|
+
var forEach = Ember.EnumerableUtils.forEach;
|
8017
|
+
|
8018
|
+
/**
|
8019
|
+
The ActiveModelAdapter is a subclass of the RESTAdapter designed to integrate
|
8020
|
+
with a JSON API that uses an underscored naming convention instead of camelcasing.
|
8021
|
+
It has been designed to work out of the box with the
|
8022
|
+
[active_model_serializers](http://github.com/rails-api/active_model_serializers)
|
8023
|
+
Ruby gem.
|
8024
|
+
|
8025
|
+
## JSON Structure
|
8026
|
+
|
8027
|
+
The ActiveModelAdapter expects the JSON returned from your server to follow
|
8028
|
+
the REST adapter conventions substituting underscored keys for camelcased ones.
|
8029
|
+
|
8030
|
+
### Conventional Names
|
8031
|
+
|
8032
|
+
Attribute names in your JSON payload should be the underscored versions of
|
8033
|
+
the attributes in your Ember.js models.
|
8034
|
+
|
8035
|
+
For example, if you have a `Person` model:
|
8036
|
+
|
8037
|
+
```js
|
8038
|
+
App.FamousPerson = DS.Model.extend({
|
8039
|
+
firstName: DS.attr('string'),
|
8040
|
+
lastName: DS.attr('string'),
|
8041
|
+
occupation: DS.attr('string')
|
8042
|
+
});
|
8043
|
+
```
|
8044
|
+
|
8045
|
+
The JSON returned should look like this:
|
8046
|
+
|
8047
|
+
```js
|
8048
|
+
{
|
8049
|
+
"famous_person": {
|
8050
|
+
"first_name": "Barack",
|
8051
|
+
"last_name": "Obama",
|
8052
|
+
"occupation": "President"
|
8053
|
+
}
|
8054
|
+
}
|
8055
|
+
```
|
8056
|
+
|
8057
|
+
@class ActiveModelAdapter
|
8058
|
+
@constructor
|
8059
|
+
@namespace DS
|
8060
|
+
@extends DS.Adapter
|
8061
|
+
**/
|
8062
|
+
|
8063
|
+
DS.ActiveModelAdapter = DS.RESTAdapter.extend({
|
8064
|
+
defaultSerializer: '_ams',
|
8065
|
+
/**
|
8066
|
+
The ActiveModelAdapter overrides the `pathForType` method
|
8067
|
+
to build underscored URLs.
|
8068
|
+
|
8069
|
+
```js
|
8070
|
+
this.pathForType("famousPerson");
|
8071
|
+
//=> "famous_people"
|
8072
|
+
```
|
8073
|
+
|
8074
|
+
@method pathForType
|
8075
|
+
@param {String} type
|
8076
|
+
@returns String
|
8077
|
+
*/
|
8078
|
+
pathForType: function(type) {
|
8079
|
+
var decamelized = Ember.String.decamelize(type);
|
8080
|
+
return Ember.String.pluralize(decamelized);
|
8081
|
+
},
|
8082
|
+
|
8083
|
+
/**
|
8084
|
+
The ActiveModelAdapter overrides the `ajaxError` method
|
8085
|
+
to return a DS.InvalidError for all 422 Unprocessable Entity
|
8086
|
+
responses.
|
8087
|
+
|
8088
|
+
@method ajaxError
|
8089
|
+
@param jqXHR
|
8090
|
+
@returns error
|
8091
|
+
*/
|
8092
|
+
ajaxError: function(jqXHR) {
|
8093
|
+
var error = this._super(jqXHR);
|
8094
|
+
|
8095
|
+
if (jqXHR && jqXHR.status === 422) {
|
8096
|
+
var jsonErrors = Ember.$.parseJSON(jqXHR.responseText)["errors"],
|
8097
|
+
errors = {};
|
8098
|
+
|
8099
|
+
forEach(Ember.keys(jsonErrors), function(key) {
|
8100
|
+
errors[Ember.String.camelize(key)] = jsonErrors[key];
|
8101
|
+
});
|
8102
|
+
|
8103
|
+
return new DS.InvalidError(errors);
|
8104
|
+
} else {
|
8105
|
+
return error;
|
8106
|
+
}
|
8107
|
+
}
|
8108
|
+
});
|
8109
|
+
|
8110
|
+
})();
|
8111
|
+
|
8112
|
+
|
8113
|
+
|
8114
|
+
(function() {
|
8115
|
+
|
8116
|
+
})();
|
8117
|
+
|
8118
|
+
|
8119
|
+
|
8120
|
+
(function() {
|
8121
|
+
Ember.onLoad('Ember.Application', function(Application) {
|
8122
|
+
Application.initializer({
|
8123
|
+
name: "activeModelAdapter",
|
8124
|
+
|
8125
|
+
initialize: function(container, application) {
|
8126
|
+
application.register('serializer:_ams', DS.ActiveModelSerializer);
|
8127
|
+
application.register('adapter:_ams', DS.ActiveModelAdapter);
|
8128
|
+
}
|
8129
|
+
});
|
8130
|
+
});
|
8131
|
+
|
8132
|
+
})();
|
8133
|
+
|
8134
|
+
|
8135
|
+
|
7206
8136
|
(function() {
|
7207
8137
|
|
7208
8138
|
})();
|