ember-data-source 1.0.0.beta.2 → 1.0.0.beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/dist/ember-data.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
|
})();
|