ember-data-source 1.0.0.beta.1 → 1.0.0.beta.2
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 +808 -544
- data/dist/ember-data.min.js +4 -3
- data/dist/ember-data.prod.js +6911 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ab50c82ea065fb1d9eb982e0fde381caa4184de
|
4
|
+
data.tar.gz: 4f52807164f630f58e6144e3a11bc41e09b2c26c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 483401b7507bc40fc841672dbf04d3cad28886cae33f342957bb77bfe0ab654d53d0ec21869da0426aa15907c8a028a65e7aa7a14fcea999644287fb50ce3111
|
7
|
+
data.tar.gz: b4a40bc1be9f8fcc995b2e5a99710ce824dad66b345f9cfd5f16e82687f3a99bf84971817e88565ef7473843ac4e80066e0cbb1f89a968c00d2d5607f6e76dbf
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.0-beta.
|
1
|
+
1.0.0-beta.2
|
data/dist/ember-data.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
// Version: v1.0.0-beta.
|
2
|
-
// Last commit:
|
1
|
+
// Version: v1.0.0-beta.2
|
2
|
+
// Last commit: d1158e2 (2013-09-04 16:03:06 -0700)
|
3
3
|
|
4
4
|
|
5
5
|
(function() {
|
@@ -41,249 +41,6 @@ var define, requireModule;
|
|
41
41
|
return seen[name] = exports || value;
|
42
42
|
};
|
43
43
|
})();
|
44
|
-
(function() {
|
45
|
-
Ember.String.pluralize = function(word) {
|
46
|
-
return Ember.Inflector.inflector.pluralize(word);
|
47
|
-
};
|
48
|
-
|
49
|
-
Ember.String.singularize = function(word) {
|
50
|
-
return Ember.Inflector.inflector.singularize(word);
|
51
|
-
};
|
52
|
-
|
53
|
-
})();
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
(function() {
|
58
|
-
var BLANK_REGEX = /^\s*$/;
|
59
|
-
|
60
|
-
function loadUncountable(rules, uncountable) {
|
61
|
-
for (var i = 0, length = uncountable.length; i < length; i++) {
|
62
|
-
rules.uncountable[uncountable[i]] = true;
|
63
|
-
}
|
64
|
-
}
|
65
|
-
|
66
|
-
function loadIrregular(rules, irregularPairs) {
|
67
|
-
var pair;
|
68
|
-
|
69
|
-
for (var i = 0, length = irregularPairs.length; i < length; i++) {
|
70
|
-
pair = irregularPairs[i];
|
71
|
-
|
72
|
-
rules.irregular[pair[0]] = pair[1];
|
73
|
-
rules.irregularInverse[pair[1]] = pair[0];
|
74
|
-
}
|
75
|
-
}
|
76
|
-
|
77
|
-
function Inflector(ruleSet) {
|
78
|
-
ruleSet = ruleSet || {};
|
79
|
-
ruleSet.uncountable = ruleSet.uncountable || {};
|
80
|
-
ruleSet.irregularPairs= ruleSet.irregularPairs|| {};
|
81
|
-
|
82
|
-
var rules = this.rules = {
|
83
|
-
plurals: ruleSet.plurals || [],
|
84
|
-
singular: ruleSet.singular || [],
|
85
|
-
irregular: {},
|
86
|
-
irregularInverse: {},
|
87
|
-
uncountable: {}
|
88
|
-
};
|
89
|
-
|
90
|
-
loadUncountable(rules, ruleSet.uncountable);
|
91
|
-
loadIrregular(rules, ruleSet.irregularPairs);
|
92
|
-
}
|
93
|
-
|
94
|
-
Inflector.prototype = {
|
95
|
-
pluralize: function(word) {
|
96
|
-
return this.inflect(word, this.rules.plurals);
|
97
|
-
},
|
98
|
-
|
99
|
-
singularize: function(word) {
|
100
|
-
return this.inflect(word, this.rules.singular);
|
101
|
-
},
|
102
|
-
|
103
|
-
inflect: function(word, typeRules) {
|
104
|
-
var inflection, substitution, result, lowercase, isBlank,
|
105
|
-
isUncountable, isIrregular, isIrregularInverse, rule;
|
106
|
-
|
107
|
-
isBlank = BLANK_REGEX.test(word);
|
108
|
-
|
109
|
-
if (isBlank) {
|
110
|
-
return word;
|
111
|
-
}
|
112
|
-
|
113
|
-
lowercase = word.toLowerCase();
|
114
|
-
|
115
|
-
isUncountable = this.rules.uncountable[lowercase];
|
116
|
-
|
117
|
-
if (isUncountable) {
|
118
|
-
return word;
|
119
|
-
}
|
120
|
-
|
121
|
-
isIrregular = this.rules.irregular[lowercase];
|
122
|
-
|
123
|
-
if (isIrregular) {
|
124
|
-
return isIrregular;
|
125
|
-
}
|
126
|
-
|
127
|
-
isIrregularInverse = this.rules.irregularInverse[lowercase];
|
128
|
-
|
129
|
-
if (isIrregularInverse) {
|
130
|
-
return isIrregularInverse;
|
131
|
-
}
|
132
|
-
|
133
|
-
for (var i = typeRules.length, min = 0; i > min; i--) {
|
134
|
-
inflection = typeRules[i-1];
|
135
|
-
rule = inflection[0];
|
136
|
-
|
137
|
-
if (rule.test(word)) {
|
138
|
-
break;
|
139
|
-
}
|
140
|
-
}
|
141
|
-
|
142
|
-
inflection = inflection || [];
|
143
|
-
|
144
|
-
rule = inflection[0];
|
145
|
-
substitution = inflection[1];
|
146
|
-
|
147
|
-
result = word.replace(rule, substitution);
|
148
|
-
|
149
|
-
return result;
|
150
|
-
}
|
151
|
-
};
|
152
|
-
|
153
|
-
Ember.Inflector = Inflector;
|
154
|
-
|
155
|
-
})();
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
(function() {
|
160
|
-
Ember.Inflector.defaultRules = {
|
161
|
-
plurals: [
|
162
|
-
[/$/, 's'],
|
163
|
-
[/s$/i, 's'],
|
164
|
-
[/^(ax|test)is$/i, '$1es'],
|
165
|
-
[/(octop|vir)us$/i, '$1i'],
|
166
|
-
[/(octop|vir)i$/i, '$1i'],
|
167
|
-
[/(alias|status)$/i, '$1es'],
|
168
|
-
[/(bu)s$/i, '$1ses'],
|
169
|
-
[/(buffal|tomat)o$/i, '$1oes'],
|
170
|
-
[/([ti])um$/i, '$1a'],
|
171
|
-
[/([ti])a$/i, '$1a'],
|
172
|
-
[/sis$/i, 'ses'],
|
173
|
-
[/(?:([^f])fe|([lr])f)$/i, '$1$2ves'],
|
174
|
-
[/(hive)$/i, '$1s'],
|
175
|
-
[/([^aeiouy]|qu)y$/i, '$1ies'],
|
176
|
-
[/(x|ch|ss|sh)$/i, '$1es'],
|
177
|
-
[/(matr|vert|ind)(?:ix|ex)$/i, '$1ices'],
|
178
|
-
[/^(m|l)ouse$/i, '$1ice'],
|
179
|
-
[/^(m|l)ice$/i, '$1ice'],
|
180
|
-
[/^(ox)$/i, '$1en'],
|
181
|
-
[/^(oxen)$/i, '$1'],
|
182
|
-
[/(quiz)$/i, '$1zes']
|
183
|
-
],
|
184
|
-
|
185
|
-
singular: [
|
186
|
-
[/s$/i, ''],
|
187
|
-
[/(ss)$/i, '$1'],
|
188
|
-
[/(n)ews$/i, '$1ews'],
|
189
|
-
[/([ti])a$/i, '$1um'],
|
190
|
-
[/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '$1sis'],
|
191
|
-
[/(^analy)(sis|ses)$/i, '$1sis'],
|
192
|
-
[/([^f])ves$/i, '$1fe'],
|
193
|
-
[/(hive)s$/i, '$1'],
|
194
|
-
[/(tive)s$/i, '$1'],
|
195
|
-
[/([lr])ves$/i, '$1f'],
|
196
|
-
[/([^aeiouy]|qu)ies$/i, '$1y'],
|
197
|
-
[/(s)eries$/i, '$1eries'],
|
198
|
-
[/(m)ovies$/i, '$1ovie'],
|
199
|
-
[/(x|ch|ss|sh)es$/i, '$1'],
|
200
|
-
[/^(m|l)ice$/i, '$1ouse'],
|
201
|
-
[/(bus)(es)?$/i, '$1'],
|
202
|
-
[/(o)es$/i, '$1'],
|
203
|
-
[/(shoe)s$/i, '$1'],
|
204
|
-
[/(cris|test)(is|es)$/i, '$1is'],
|
205
|
-
[/^(a)x[ie]s$/i, '$1xis'],
|
206
|
-
[/(octop|vir)(us|i)$/i, '$1us'],
|
207
|
-
[/(alias|status)(es)?$/i, '$1'],
|
208
|
-
[/^(ox)en/i, '$1'],
|
209
|
-
[/(vert|ind)ices$/i, '$1ex'],
|
210
|
-
[/(matr)ices$/i, '$1ix'],
|
211
|
-
[/(quiz)zes$/i, '$1'],
|
212
|
-
[/(database)s$/i, '$1']
|
213
|
-
],
|
214
|
-
|
215
|
-
irregularPairs: [
|
216
|
-
['person', 'people'],
|
217
|
-
['man', 'men'],
|
218
|
-
['child', 'children'],
|
219
|
-
['sex', 'sexes'],
|
220
|
-
['move', 'moves'],
|
221
|
-
['cow', 'kine'],
|
222
|
-
['zombie', 'zombies']
|
223
|
-
],
|
224
|
-
|
225
|
-
uncountable: [
|
226
|
-
'equipment',
|
227
|
-
'information',
|
228
|
-
'rice',
|
229
|
-
'money',
|
230
|
-
'species',
|
231
|
-
'series',
|
232
|
-
'fish',
|
233
|
-
'sheep',
|
234
|
-
'jeans',
|
235
|
-
'police'
|
236
|
-
]
|
237
|
-
};
|
238
|
-
|
239
|
-
})();
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
(function() {
|
244
|
-
if (Ember.EXTEND_PROTOTYPES) {
|
245
|
-
/**
|
246
|
-
See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}}
|
247
|
-
|
248
|
-
@method pluralize
|
249
|
-
@for String
|
250
|
-
*/
|
251
|
-
String.prototype.pluralize = function() {
|
252
|
-
return Ember.String.pluralize(this);
|
253
|
-
};
|
254
|
-
|
255
|
-
/**
|
256
|
-
See {{#crossLink "Ember.String/singularize"}}{{/crossLink}}
|
257
|
-
|
258
|
-
@method singularize
|
259
|
-
@for String
|
260
|
-
*/
|
261
|
-
String.prototype.singularize = function() {
|
262
|
-
return Ember.String.singularize(this);
|
263
|
-
};
|
264
|
-
}
|
265
|
-
|
266
|
-
})();
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
(function() {
|
271
|
-
Ember.Inflector.inflector = new Ember.Inflector(Ember.Inflector.defaultRules);
|
272
|
-
|
273
|
-
})();
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
(function() {
|
278
|
-
|
279
|
-
})();
|
280
|
-
|
281
|
-
|
282
|
-
})();
|
283
|
-
// Version: v1.0.0-beta.1
|
284
|
-
// Last commit: e9489ab (2013-09-01 00:38:13 -0700)
|
285
|
-
|
286
|
-
|
287
44
|
(function() {
|
288
45
|
/**
|
289
46
|
@module ember-data
|
@@ -309,120 +66,9 @@ if ('undefined' === typeof DS) {
|
|
309
66
|
|
310
67
|
|
311
68
|
|
312
|
-
(function() {
|
313
|
-
/**
|
314
|
-
@module ember-data
|
315
|
-
*/
|
316
|
-
|
317
|
-
var isNone = Ember.isNone, isEmpty = Ember.isEmpty;
|
318
|
-
|
319
|
-
/**
|
320
|
-
DS.JSONTransforms is a hash of transforms used by DS.Serializer.
|
321
|
-
|
322
|
-
@class JSONTransforms
|
323
|
-
@static
|
324
|
-
@namespace DS
|
325
|
-
*/
|
326
|
-
DS.JSONTransforms = {
|
327
|
-
string: {
|
328
|
-
deserialize: function(serialized) {
|
329
|
-
return isNone(serialized) ? null : String(serialized);
|
330
|
-
},
|
331
|
-
|
332
|
-
serialize: function(deserialized) {
|
333
|
-
return isNone(deserialized) ? null : String(deserialized);
|
334
|
-
}
|
335
|
-
},
|
336
|
-
|
337
|
-
number: {
|
338
|
-
deserialize: function(serialized) {
|
339
|
-
return isEmpty(serialized) ? null : Number(serialized);
|
340
|
-
},
|
341
|
-
|
342
|
-
serialize: function(deserialized) {
|
343
|
-
return isEmpty(deserialized) ? null : Number(deserialized);
|
344
|
-
}
|
345
|
-
},
|
346
|
-
|
347
|
-
// Handles the following boolean inputs:
|
348
|
-
// "TrUe", "t", "f", "FALSE", 0, (non-zero), or boolean true/false
|
349
|
-
'boolean': {
|
350
|
-
deserialize: function(serialized) {
|
351
|
-
var type = typeof serialized;
|
352
|
-
|
353
|
-
if (type === "boolean") {
|
354
|
-
return serialized;
|
355
|
-
} else if (type === "string") {
|
356
|
-
return serialized.match(/^true$|^t$|^1$/i) !== null;
|
357
|
-
} else if (type === "number") {
|
358
|
-
return serialized === 1;
|
359
|
-
} else {
|
360
|
-
return false;
|
361
|
-
}
|
362
|
-
},
|
363
|
-
|
364
|
-
serialize: function(deserialized) {
|
365
|
-
return Boolean(deserialized);
|
366
|
-
}
|
367
|
-
},
|
368
|
-
|
369
|
-
date: {
|
370
|
-
deserialize: function(serialized) {
|
371
|
-
var type = typeof serialized;
|
372
|
-
|
373
|
-
if (type === "string") {
|
374
|
-
return new Date(Ember.Date.parse(serialized));
|
375
|
-
} else if (type === "number") {
|
376
|
-
return new Date(serialized);
|
377
|
-
} else if (serialized === null || serialized === undefined) {
|
378
|
-
// if the value is not present in the data,
|
379
|
-
// return undefined, not null.
|
380
|
-
return serialized;
|
381
|
-
} else {
|
382
|
-
return null;
|
383
|
-
}
|
384
|
-
},
|
385
|
-
|
386
|
-
serialize: function(date) {
|
387
|
-
if (date instanceof Date) {
|
388
|
-
var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
389
|
-
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
390
|
-
|
391
|
-
var pad = function(num) {
|
392
|
-
return num < 10 ? "0"+num : ""+num;
|
393
|
-
};
|
394
|
-
|
395
|
-
var utcYear = date.getUTCFullYear(),
|
396
|
-
utcMonth = date.getUTCMonth(),
|
397
|
-
utcDayOfMonth = date.getUTCDate(),
|
398
|
-
utcDay = date.getUTCDay(),
|
399
|
-
utcHours = date.getUTCHours(),
|
400
|
-
utcMinutes = date.getUTCMinutes(),
|
401
|
-
utcSeconds = date.getUTCSeconds();
|
402
|
-
|
403
|
-
|
404
|
-
var dayOfWeek = days[utcDay];
|
405
|
-
var dayOfMonth = pad(utcDayOfMonth);
|
406
|
-
var month = months[utcMonth];
|
407
|
-
|
408
|
-
return dayOfWeek + ", " + dayOfMonth + " " + month + " " + utcYear + " " +
|
409
|
-
pad(utcHours) + ":" + pad(utcMinutes) + ":" + pad(utcSeconds) + " GMT";
|
410
|
-
} else {
|
411
|
-
return null;
|
412
|
-
}
|
413
|
-
}
|
414
|
-
}
|
415
|
-
};
|
416
|
-
|
417
|
-
})();
|
418
|
-
|
419
|
-
|
420
|
-
|
421
69
|
(function() {
|
422
70
|
var get = Ember.get, set = Ember.set, isNone = Ember.isNone;
|
423
71
|
|
424
|
-
var transforms = DS.JSONTransforms;
|
425
|
-
|
426
72
|
// Simple dispatcher to support overriding the aliased
|
427
73
|
// method in subclasses.
|
428
74
|
function aliasMethod(methodName) {
|
@@ -434,55 +80,20 @@ function aliasMethod(methodName) {
|
|
434
80
|
DS.JSONSerializer = Ember.Object.extend({
|
435
81
|
primaryKey: 'id',
|
436
82
|
|
437
|
-
|
438
|
-
var store = get(this, 'store');
|
439
|
-
|
83
|
+
applyTransforms: function(type, data) {
|
440
84
|
type.eachTransformedAttribute(function(key, type) {
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
type.eachRelationship(function(key, relationship) {
|
445
|
-
// A link (usually a URL) was already provided in
|
446
|
-
// normalized form
|
447
|
-
if (data.links && data.links[key]) {
|
448
|
-
return;
|
449
|
-
}
|
450
|
-
|
451
|
-
var type = relationship.type,
|
452
|
-
value = data[key];
|
453
|
-
|
454
|
-
if (value == null) { return; }
|
455
|
-
|
456
|
-
if (relationship.kind === 'belongsTo') {
|
457
|
-
this.deserializeRecordId(data, key, relationship, value);
|
458
|
-
} else if (relationship.kind === 'hasMany') {
|
459
|
-
this.deserializeRecordIds(data, key, relationship, value);
|
460
|
-
}
|
85
|
+
var transform = this.transformFor(type);
|
86
|
+
data[key] = transform.deserialize(data[key]);
|
461
87
|
}, this);
|
462
88
|
|
463
89
|
return data;
|
464
90
|
},
|
465
91
|
|
466
|
-
|
467
|
-
if (
|
468
|
-
return;
|
469
|
-
}
|
470
|
-
|
471
|
-
var type;
|
92
|
+
normalize: function(type, hash) {
|
93
|
+
if (!hash) { return hash; }
|
472
94
|
|
473
|
-
|
474
|
-
|
475
|
-
data[key] = get(this, 'store').recordForId(type, id);
|
476
|
-
} else if (typeof id === 'object') {
|
477
|
-
// polymorphic
|
478
|
-
data[key] = get(this, 'store').recordForId(id.type, id.id);
|
479
|
-
}
|
480
|
-
},
|
481
|
-
|
482
|
-
deserializeRecordIds: function(data, key, relationship, ids) {
|
483
|
-
for (var i=0, l=ids.length; i<l; i++) {
|
484
|
-
this.deserializeRecordId(ids, i, relationship, ids[i]);
|
485
|
-
}
|
95
|
+
this.applyTransforms(type, hash);
|
96
|
+
return hash;
|
486
97
|
},
|
487
98
|
|
488
99
|
// SERIALIZE
|
@@ -500,20 +111,8 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
500
111
|
}
|
501
112
|
}
|
502
113
|
|
503
|
-
var attrs = get(this, 'attrs');
|
504
|
-
|
505
114
|
record.eachAttribute(function(key, attribute) {
|
506
|
-
|
507
|
-
|
508
|
-
if (type) {
|
509
|
-
value = transforms[type].serialize(value);
|
510
|
-
}
|
511
|
-
|
512
|
-
// if provided, use the mapping provided by `attrs` in
|
513
|
-
// the serializer
|
514
|
-
key = attrs && attrs[key] || key;
|
515
|
-
|
516
|
-
json[key] = value;
|
115
|
+
this.serializeAttribute(record, json, key, attribute);
|
517
116
|
}, this);
|
518
117
|
|
519
118
|
record.eachRelationship(function(key, relationship) {
|
@@ -527,6 +126,22 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
527
126
|
return json;
|
528
127
|
},
|
529
128
|
|
129
|
+
serializeAttribute: function(record, json, key, attribute) {
|
130
|
+
var attrs = get(this, 'attrs');
|
131
|
+
var value = get(record, key), type = attribute.type;
|
132
|
+
|
133
|
+
if (type) {
|
134
|
+
var transform = this.transformFor(type);
|
135
|
+
value = transform.serialize(value);
|
136
|
+
}
|
137
|
+
|
138
|
+
// if provided, use the mapping provided by `attrs` in
|
139
|
+
// the serializer
|
140
|
+
key = attrs && attrs[key] || key;
|
141
|
+
|
142
|
+
json[key] = value;
|
143
|
+
},
|
144
|
+
|
530
145
|
serializeBelongsTo: function(record, json, relationship) {
|
531
146
|
var key = relationship.key;
|
532
147
|
|
@@ -541,11 +156,22 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
541
156
|
}
|
542
157
|
},
|
543
158
|
|
544
|
-
serializeHasMany:
|
159
|
+
serializeHasMany: function(record, json, relationship) {
|
160
|
+
var key = relationship.key;
|
161
|
+
|
162
|
+
var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
|
163
|
+
|
164
|
+
if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') {
|
165
|
+
json[key] = get(record, key).mapBy('id');
|
166
|
+
// TODO support for polymorphic manyToNone and manyToMany relationships
|
167
|
+
}
|
168
|
+
},
|
545
169
|
|
546
170
|
// EXTRACT
|
547
171
|
|
548
172
|
extract: function(store, type, payload, id, requestType) {
|
173
|
+
this.extractMeta(store, type, payload);
|
174
|
+
|
549
175
|
var specificExtract = "extract" + requestType.charAt(0).toUpperCase() + requestType.substr(1);
|
550
176
|
return this[specificExtract](store, type, payload, id, requestType);
|
551
177
|
},
|
@@ -563,12 +189,20 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
563
189
|
extractSave: aliasMethod('extractSingle'),
|
564
190
|
|
565
191
|
extractSingle: function(store, type, payload) {
|
566
|
-
return payload;
|
192
|
+
return this.normalize(type, payload);
|
567
193
|
},
|
568
194
|
|
569
195
|
extractArray: function(store, type, payload) {
|
570
|
-
return payload;
|
196
|
+
return this.normalize(type, payload);
|
571
197
|
},
|
198
|
+
|
199
|
+
extractMeta: function(store, type, payload) {
|
200
|
+
if (payload && payload.meta) {
|
201
|
+
store.metaForType(type, payload.meta);
|
202
|
+
delete payload.meta;
|
203
|
+
}
|
204
|
+
},
|
205
|
+
|
572
206
|
// HELPERS
|
573
207
|
|
574
208
|
typeFor: function(relationship, key, data) {
|
@@ -579,8 +213,8 @@ DS.JSONSerializer = Ember.Object.extend({
|
|
579
213
|
}
|
580
214
|
},
|
581
215
|
|
582
|
-
|
583
|
-
|
216
|
+
transformFor: function(attributeType) {
|
217
|
+
return this.container.lookup('transform:' + attributeType);
|
584
218
|
}
|
585
219
|
});
|
586
220
|
|
@@ -698,6 +332,139 @@ DS.DebugAdapter = Ember.DataAdapter.extend({
|
|
698
332
|
|
699
333
|
|
700
334
|
|
335
|
+
(function() {
|
336
|
+
DS.Transform = Ember.Object.extend({
|
337
|
+
|
338
|
+
serialize: Ember.required(),
|
339
|
+
|
340
|
+
deserialize: Ember.required()
|
341
|
+
|
342
|
+
});
|
343
|
+
})();
|
344
|
+
|
345
|
+
|
346
|
+
|
347
|
+
(function() {
|
348
|
+
|
349
|
+
DS.BooleanTransform = DS.Transform.extend({
|
350
|
+
deserialize: function(serialized) {
|
351
|
+
var type = typeof serialized;
|
352
|
+
|
353
|
+
if (type === "boolean") {
|
354
|
+
return serialized;
|
355
|
+
} else if (type === "string") {
|
356
|
+
return serialized.match(/^true$|^t$|^1$/i) !== null;
|
357
|
+
} else if (type === "number") {
|
358
|
+
return serialized === 1;
|
359
|
+
} else {
|
360
|
+
return false;
|
361
|
+
}
|
362
|
+
},
|
363
|
+
|
364
|
+
serialize: function(deserialized) {
|
365
|
+
return Boolean(deserialized);
|
366
|
+
}
|
367
|
+
});
|
368
|
+
|
369
|
+
})();
|
370
|
+
|
371
|
+
|
372
|
+
|
373
|
+
(function() {
|
374
|
+
DS.DateTransform = DS.Transform.extend({
|
375
|
+
|
376
|
+
deserialize: function(serialized) {
|
377
|
+
var type = typeof serialized;
|
378
|
+
|
379
|
+
if (type === "string") {
|
380
|
+
return new Date(Ember.Date.parse(serialized));
|
381
|
+
} else if (type === "number") {
|
382
|
+
return new Date(serialized);
|
383
|
+
} else if (serialized === null || serialized === undefined) {
|
384
|
+
// if the value is not present in the data,
|
385
|
+
// return undefined, not null.
|
386
|
+
return serialized;
|
387
|
+
} else {
|
388
|
+
return null;
|
389
|
+
}
|
390
|
+
},
|
391
|
+
|
392
|
+
serialize: function(date) {
|
393
|
+
if (date instanceof Date) {
|
394
|
+
var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
395
|
+
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
396
|
+
|
397
|
+
var pad = function(num) {
|
398
|
+
return num < 10 ? "0"+num : ""+num;
|
399
|
+
};
|
400
|
+
|
401
|
+
var utcYear = date.getUTCFullYear(),
|
402
|
+
utcMonth = date.getUTCMonth(),
|
403
|
+
utcDayOfMonth = date.getUTCDate(),
|
404
|
+
utcDay = date.getUTCDay(),
|
405
|
+
utcHours = date.getUTCHours(),
|
406
|
+
utcMinutes = date.getUTCMinutes(),
|
407
|
+
utcSeconds = date.getUTCSeconds();
|
408
|
+
|
409
|
+
|
410
|
+
var dayOfWeek = days[utcDay];
|
411
|
+
var dayOfMonth = pad(utcDayOfMonth);
|
412
|
+
var month = months[utcMonth];
|
413
|
+
|
414
|
+
return dayOfWeek + ", " + dayOfMonth + " " + month + " " + utcYear + " " +
|
415
|
+
pad(utcHours) + ":" + pad(utcMinutes) + ":" + pad(utcSeconds) + " GMT";
|
416
|
+
} else {
|
417
|
+
return null;
|
418
|
+
}
|
419
|
+
}
|
420
|
+
|
421
|
+
});
|
422
|
+
|
423
|
+
})();
|
424
|
+
|
425
|
+
|
426
|
+
|
427
|
+
(function() {
|
428
|
+
var empty = Ember.isEmpty;
|
429
|
+
|
430
|
+
DS.NumberTransform = DS.Transform.extend({
|
431
|
+
|
432
|
+
deserialize: function(serialized) {
|
433
|
+
return empty(serialized) ? null : Number(serialized);
|
434
|
+
},
|
435
|
+
|
436
|
+
serialize: function(deserialized) {
|
437
|
+
return empty(deserialized) ? null : Number(deserialized);
|
438
|
+
}
|
439
|
+
});
|
440
|
+
})();
|
441
|
+
|
442
|
+
|
443
|
+
|
444
|
+
(function() {
|
445
|
+
var none = Ember.isNone, empty = Ember.isEmpty;
|
446
|
+
|
447
|
+
DS.StringTransform = DS.Transform.extend({
|
448
|
+
|
449
|
+
deserialize: function(serialized) {
|
450
|
+
return none(serialized) ? null : String(serialized);
|
451
|
+
},
|
452
|
+
|
453
|
+
serialize: function(deserialized) {
|
454
|
+
return none(deserialized) ? null : String(deserialized);
|
455
|
+
}
|
456
|
+
|
457
|
+
});
|
458
|
+
})();
|
459
|
+
|
460
|
+
|
461
|
+
|
462
|
+
(function() {
|
463
|
+
|
464
|
+
})();
|
465
|
+
|
466
|
+
|
467
|
+
|
701
468
|
(function() {
|
702
469
|
/**
|
703
470
|
@module ember-data
|
@@ -718,7 +485,7 @@ var set = Ember.set;
|
|
718
485
|
For example, imagine an Ember.js application with the following classes:
|
719
486
|
|
720
487
|
App.Store = DS.Store.extend({
|
721
|
-
adapter: '
|
488
|
+
adapter: 'custom'
|
722
489
|
});
|
723
490
|
|
724
491
|
App.PostsController = Ember.ArrayController.extend({
|
@@ -751,17 +518,16 @@ Ember.onLoad('Ember.Application', function(Application) {
|
|
751
518
|
}
|
752
519
|
});
|
753
520
|
|
754
|
-
|
755
|
-
|
756
|
-
if (DS.DebugAdapter) {
|
757
|
-
Application.initializer({
|
758
|
-
name: "dataAdapter",
|
521
|
+
Application.initializer({
|
522
|
+
name: "transforms",
|
759
523
|
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
524
|
+
initialize: function(container, application) {
|
525
|
+
application.register('transform:boolean', DS.BooleanTransform);
|
526
|
+
application.register('transform:date', DS.DateTransform);
|
527
|
+
application.register('transform:number', DS.NumberTransform);
|
528
|
+
application.register('transform:string', DS.StringTransform);
|
529
|
+
}
|
530
|
+
});
|
765
531
|
|
766
532
|
Application.initializer({
|
767
533
|
name: "dataAdapter",
|
@@ -1209,6 +975,7 @@ DS.ManyArray = DS.RecordArray.extend({
|
|
1209
975
|
*/
|
1210
976
|
|
1211
977
|
var get = Ember.get;
|
978
|
+
var forEach = Ember.ArrayPolyfills.forEach;
|
1212
979
|
|
1213
980
|
var resolveMapConflict = function(oldValue, newValue) {
|
1214
981
|
return oldValue;
|
@@ -1304,7 +1071,7 @@ DS._Mappable = Ember.Mixin.create({
|
|
1304
1071
|
|
1305
1072
|
var classMap = classMeta[mapName];
|
1306
1073
|
if (classMap) {
|
1307
|
-
|
1074
|
+
forEach.call(classMap, eachMap, this);
|
1308
1075
|
}
|
1309
1076
|
|
1310
1077
|
function eachMap(key, value) {
|
@@ -1322,7 +1089,6 @@ DS._Mappable = Ember.Mixin.create({
|
|
1322
1089
|
}
|
1323
1090
|
}
|
1324
1091
|
|
1325
|
-
|
1326
1092
|
});
|
1327
1093
|
|
1328
1094
|
DS._Mappable.generateMapFunctionFor = function(mapName, transform) {
|
@@ -1501,12 +1267,15 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1501
1267
|
This property is cacheable, so the same instance of a specified
|
1502
1268
|
adapter class should be used for the lifetime of the store.
|
1503
1269
|
|
1504
|
-
@property
|
1270
|
+
@property defaultAdapter
|
1505
1271
|
@private
|
1506
1272
|
@returns DS.Adapter
|
1507
1273
|
*/
|
1508
|
-
|
1274
|
+
defaultAdapter: Ember.computed(function() {
|
1509
1275
|
var adapter = get(this, 'adapter');
|
1276
|
+
|
1277
|
+
Ember.assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name or a factory', !(adapter instanceof DS.Adapter));
|
1278
|
+
|
1510
1279
|
if (typeof adapter === 'string') {
|
1511
1280
|
adapter = this.container.lookup('adapter:' + adapter) || this.container.lookup('adapter:application') || this.container.lookup('adapter:_rest');
|
1512
1281
|
}
|
@@ -1878,19 +1647,20 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
1878
1647
|
var unloadedRecords = records.filterProperty('isEmpty', true),
|
1879
1648
|
manyArray = this.recordArrayManager.createManyArray(type, records);
|
1880
1649
|
|
1881
|
-
|
1650
|
+
forEach(unloadedRecords, function(record) {
|
1882
1651
|
record.loadingData();
|
1883
1652
|
});
|
1884
1653
|
|
1885
1654
|
manyArray.loadingRecordsCount = unloadedRecords.length;
|
1886
1655
|
|
1887
1656
|
if (unloadedRecords.length) {
|
1888
|
-
|
1657
|
+
forEach(unloadedRecords, function(record) {
|
1889
1658
|
this.recordArrayManager.registerWaitingRecordArray(record, manyArray);
|
1890
1659
|
}, this);
|
1891
1660
|
|
1892
1661
|
this.fetchMany(unloadedRecords, owner, resolver);
|
1893
1662
|
} else {
|
1663
|
+
if (resolver) { resolver.resolve(); }
|
1894
1664
|
manyArray.set('isLoaded', true);
|
1895
1665
|
Ember.run.once(manyArray, 'trigger', 'didLoad');
|
1896
1666
|
}
|
@@ -2027,6 +1797,8 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
2027
1797
|
@return {DS.RecordArray}
|
2028
1798
|
*/
|
2029
1799
|
all: function(type) {
|
1800
|
+
type = this.modelFor(type);
|
1801
|
+
|
2030
1802
|
var typeMap = this.typeMapFor(type),
|
2031
1803
|
findAllCache = typeMap.findAllCache;
|
2032
1804
|
|
@@ -2308,14 +2080,15 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
2308
2080
|
@method _load
|
2309
2081
|
@private
|
2310
2082
|
@param {DS.Model} type
|
2311
|
-
@param data
|
2312
|
-
@param
|
2083
|
+
@param {Object} data
|
2084
|
+
@param {Boolean} partial the data should be merged into
|
2085
|
+
the existing fata, not replace it.
|
2313
2086
|
*/
|
2314
|
-
_load: function(type, data) {
|
2087
|
+
_load: function(type, data, partial) {
|
2315
2088
|
var id = coerceId(data.id),
|
2316
2089
|
record = this.recordForId(type, id);
|
2317
2090
|
|
2318
|
-
record.setupData(data);
|
2091
|
+
record.setupData(data, partial);
|
2319
2092
|
this.recordArrayManager.recordDidChange(record);
|
2320
2093
|
|
2321
2094
|
return record;
|
@@ -2405,17 +2178,26 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
2405
2178
|
@returns DS.Model the record that was created or
|
2406
2179
|
updated.
|
2407
2180
|
*/
|
2408
|
-
push: function(type, data) {
|
2181
|
+
push: function(type, data, _partial) {
|
2182
|
+
// _partial is an internal param used by `update`.
|
2183
|
+
// If passed, it means that the data should be
|
2184
|
+
// merged into the existing data, not replace it.
|
2185
|
+
|
2409
2186
|
var serializer = this.serializerFor(type);
|
2410
2187
|
type = this.modelFor(type);
|
2411
2188
|
|
2412
|
-
|
2189
|
+
// normalize relationship IDs into records
|
2190
|
+
data = normalizeRelationships(this, type, data);
|
2413
2191
|
|
2414
|
-
this._load(type, data);
|
2192
|
+
this._load(type, data, _partial);
|
2415
2193
|
|
2416
2194
|
return this.recordForId(type, data.id);
|
2417
2195
|
},
|
2418
2196
|
|
2197
|
+
update: function(type, data) {
|
2198
|
+
return this.push(type, data, true);
|
2199
|
+
},
|
2200
|
+
|
2419
2201
|
/**
|
2420
2202
|
If you have an Array of normalized data to push,
|
2421
2203
|
you can call `pushMany` with the Array, and it will
|
@@ -2432,6 +2214,20 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
2432
2214
|
}, this);
|
2433
2215
|
},
|
2434
2216
|
|
2217
|
+
/**
|
2218
|
+
If you have some metadata to set for a type
|
2219
|
+
you can call `metaForType`.
|
2220
|
+
|
2221
|
+
@method metaForType
|
2222
|
+
@param {String} type
|
2223
|
+
@param {Object} metadata
|
2224
|
+
*/
|
2225
|
+
metaForType: function(type, metadata) {
|
2226
|
+
type = this.modelFor(type);
|
2227
|
+
|
2228
|
+
Ember.merge(this.typeMapFor(type).metadata, metadata);
|
2229
|
+
},
|
2230
|
+
|
2435
2231
|
/**
|
2436
2232
|
Build a brand new record for a given type, ID, and
|
2437
2233
|
initial data.
|
@@ -2566,7 +2362,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
2566
2362
|
adapter = container.lookup('adapter:' + type.typeKey) || container.lookup('adapter:application');
|
2567
2363
|
}
|
2568
2364
|
|
2569
|
-
return adapter || get(this, '
|
2365
|
+
return adapter || get(this, 'defaultAdapter');
|
2570
2366
|
},
|
2571
2367
|
|
2572
2368
|
// ..............................
|
@@ -2590,19 +2386,65 @@ DS.Store = Ember.Object.extend(DS._Mappable, {
|
|
2590
2386
|
@param {String} type the record to serialize
|
2591
2387
|
*/
|
2592
2388
|
serializerFor: function(type) {
|
2593
|
-
|
2389
|
+
type = this.modelFor(type);
|
2390
|
+
var adapter = this.adapterForType(type);
|
2391
|
+
|
2392
|
+
return serializerFor(this.container, type.typeKey, adapter && adapter.defaultSerializer);
|
2393
|
+
}
|
2394
|
+
});
|
2395
|
+
|
2396
|
+
function normalizeRelationships(store, type, data) {
|
2397
|
+
type.eachRelationship(function(key, relationship) {
|
2398
|
+
// A link (usually a URL) was already provided in
|
2399
|
+
// normalized form
|
2400
|
+
if (data.links && data.links[key]) {
|
2401
|
+
return;
|
2402
|
+
}
|
2594
2403
|
|
2595
|
-
|
2404
|
+
var type = relationship.type,
|
2405
|
+
value = data[key];
|
2596
2406
|
|
2597
|
-
if (
|
2598
|
-
|
2407
|
+
if (value == null) { return; }
|
2408
|
+
|
2409
|
+
if (relationship.kind === 'belongsTo') {
|
2410
|
+
deserializeRecordId(store, data, key, relationship, value);
|
2411
|
+
} else if (relationship.kind === 'hasMany') {
|
2412
|
+
deserializeRecordIds(store, data, key, relationship, value);
|
2599
2413
|
}
|
2414
|
+
});
|
2600
2415
|
|
2601
|
-
|
2602
|
-
|
2603
|
-
|
2416
|
+
return data;
|
2417
|
+
}
|
2418
|
+
|
2419
|
+
function deserializeRecordId(store, data, key, relationship, id) {
|
2420
|
+
if (isNone(id) || id instanceof DS.Model) {
|
2421
|
+
return;
|
2604
2422
|
}
|
2605
|
-
|
2423
|
+
|
2424
|
+
var type;
|
2425
|
+
|
2426
|
+
if (typeof id === 'number' || typeof id === 'string') {
|
2427
|
+
type = typeFor(relationship, key, data);
|
2428
|
+
data[key] = store.recordForId(type, id);
|
2429
|
+
} else if (typeof id === 'object') {
|
2430
|
+
// polymorphic
|
2431
|
+
data[key] = store.recordForId(id.type, id.id);
|
2432
|
+
}
|
2433
|
+
}
|
2434
|
+
|
2435
|
+
function typeFor(relationship, key, data) {
|
2436
|
+
if (relationship.options.polymorphic) {
|
2437
|
+
return data[key + "_type"];
|
2438
|
+
} else {
|
2439
|
+
return relationship.type;
|
2440
|
+
}
|
2441
|
+
}
|
2442
|
+
|
2443
|
+
function deserializeRecordIds(store, data, key, relationship, ids) {
|
2444
|
+
for (var i=0, l=ids.length; i<l; i++) {
|
2445
|
+
deserializeRecordId(store, ids, i, relationship, ids[i]);
|
2446
|
+
}
|
2447
|
+
}
|
2606
2448
|
|
2607
2449
|
// Delegation to the adapter and promise management
|
2608
2450
|
|
@@ -2621,15 +2463,20 @@ function isThenable(object) {
|
|
2621
2463
|
return object && typeof object.then === 'function';
|
2622
2464
|
}
|
2623
2465
|
|
2624
|
-
function serializerFor(
|
2466
|
+
function serializerFor(container, type, defaultSerializer) {
|
2467
|
+
return container.lookup('serializer:'+type) ||
|
2468
|
+
container.lookup('serializer:application') ||
|
2469
|
+
container.lookup('serializer:' + defaultSerializer) ||
|
2470
|
+
container.lookup('serializer:_default');
|
2471
|
+
}
|
2472
|
+
|
2473
|
+
function serializerForAdapter(adapter, type) {
|
2625
2474
|
var serializer = adapter.serializer,
|
2626
2475
|
defaultSerializer = adapter.defaultSerializer,
|
2627
2476
|
container = adapter.container;
|
2628
2477
|
|
2629
2478
|
if (container && serializer === undefined) {
|
2630
|
-
serializer = container
|
2631
|
-
container.lookup('serializer:application') ||
|
2632
|
-
container.lookup('serializer:' + defaultSerializer || 'serializer:_default');
|
2479
|
+
serializer = serializerFor(container, type.typeKey, defaultSerializer);
|
2633
2480
|
}
|
2634
2481
|
|
2635
2482
|
if (serializer === null || serializer === undefined) {
|
@@ -2643,7 +2490,7 @@ function serializerFor(adapter, type) {
|
|
2643
2490
|
|
2644
2491
|
function _find(adapter, store, type, id, resolver) {
|
2645
2492
|
var promise = adapter.find(store, type, id),
|
2646
|
-
serializer =
|
2493
|
+
serializer = serializerForAdapter(adapter, type);
|
2647
2494
|
|
2648
2495
|
return resolve(promise).then(function(payload) {
|
2649
2496
|
Ember.assert("You made a request for a " + type.typeKey + " with id " + id + ", but the adapter's response did not have any data", payload);
|
@@ -2655,7 +2502,7 @@ function _find(adapter, store, type, id, resolver) {
|
|
2655
2502
|
|
2656
2503
|
function _findMany(adapter, store, type, ids, owner, resolver) {
|
2657
2504
|
var promise = adapter.findMany(store, type, ids, owner),
|
2658
|
-
serializer =
|
2505
|
+
serializer = serializerForAdapter(adapter, type);
|
2659
2506
|
|
2660
2507
|
return resolve(promise).then(function(payload) {
|
2661
2508
|
payload = serializer.extract(store, type, payload, null, 'findMany');
|
@@ -2666,7 +2513,7 @@ function _findMany(adapter, store, type, ids, owner, resolver) {
|
|
2666
2513
|
|
2667
2514
|
function _findHasMany(adapter, store, record, link, relationship, resolver) {
|
2668
2515
|
var promise = adapter.findHasMany(store, record, link, relationship),
|
2669
|
-
serializer =
|
2516
|
+
serializer = serializerForAdapter(adapter, relationship.type);
|
2670
2517
|
|
2671
2518
|
return resolve(promise).then(function(payload) {
|
2672
2519
|
payload = serializer.extract(store, relationship.type, payload, null, 'findHasMany');
|
@@ -2678,7 +2525,7 @@ function _findHasMany(adapter, store, record, link, relationship, resolver) {
|
|
2678
2525
|
|
2679
2526
|
function _findAll(adapter, store, type, sinceToken, resolver) {
|
2680
2527
|
var promise = adapter.findAll(store, type, sinceToken),
|
2681
|
-
serializer =
|
2528
|
+
serializer = serializerForAdapter(adapter, type);
|
2682
2529
|
|
2683
2530
|
return resolve(promise).then(function(payload) {
|
2684
2531
|
payload = serializer.extract(store, type, payload, null, 'findAll');
|
@@ -2691,7 +2538,7 @@ function _findAll(adapter, store, type, sinceToken, resolver) {
|
|
2691
2538
|
|
2692
2539
|
function _findQuery(adapter, store, type, query, recordArray, resolver) {
|
2693
2540
|
var promise = adapter.findQuery(store, type, query, recordArray),
|
2694
|
-
serializer =
|
2541
|
+
serializer = serializerForAdapter(adapter, type);
|
2695
2542
|
|
2696
2543
|
return resolve(promise).then(function(payload) {
|
2697
2544
|
payload = serializer.extract(store, type, payload, null, 'findAll');
|
@@ -2704,7 +2551,7 @@ function _findQuery(adapter, store, type, query, recordArray, resolver) {
|
|
2704
2551
|
function _commit(adapter, store, operation, record, resolver) {
|
2705
2552
|
var type = record.constructor,
|
2706
2553
|
promise = adapter[operation](store, type, record),
|
2707
|
-
serializer =
|
2554
|
+
serializer = serializerForAdapter(adapter, type);
|
2708
2555
|
|
2709
2556
|
Ember.assert("Your adapter's '" + operation + "' method must return a promise, but it returned " + promise, isThenable(promise));
|
2710
2557
|
|
@@ -2978,7 +2825,7 @@ var DirtyState = {
|
|
2978
2825
|
get(record, 'store').reloadRecord(record, resolver);
|
2979
2826
|
},
|
2980
2827
|
|
2981
|
-
|
2828
|
+
rolledBack: function(record) {
|
2982
2829
|
record.transitionTo('loaded.saved');
|
2983
2830
|
},
|
2984
2831
|
|
@@ -3108,6 +2955,10 @@ var createdState = dirtyState({
|
|
3108
2955
|
isNew: true
|
3109
2956
|
});
|
3110
2957
|
|
2958
|
+
createdState.uncommitted.rolledBack = function(record) {
|
2959
|
+
record.transitionTo('deleted.saved');
|
2960
|
+
};
|
2961
|
+
|
3111
2962
|
var updatedState = dirtyState({
|
3112
2963
|
dirtyType: 'updated'
|
3113
2964
|
});
|
@@ -3138,6 +2989,14 @@ var RootState = {
|
|
3138
2989
|
isNew: false,
|
3139
2990
|
isValid: true,
|
3140
2991
|
|
2992
|
+
// DEFAULT EVENTS
|
2993
|
+
|
2994
|
+
// Trying to roll back if you're not in the dirty state
|
2995
|
+
// doesn't change your state. For example, if you're in the
|
2996
|
+
// in-flight state, rolling back the record doesn't move
|
2997
|
+
// you out of the in-flight state.
|
2998
|
+
rolledBack: Ember.K,
|
2999
|
+
|
3141
3000
|
// SUBSTATES
|
3142
3001
|
|
3143
3002
|
// A record begins its lifecycle in the `empty` state.
|
@@ -3301,7 +3160,7 @@ var RootState = {
|
|
3301
3160
|
becomeDirty: Ember.K,
|
3302
3161
|
deleteRecord: Ember.K,
|
3303
3162
|
|
3304
|
-
|
3163
|
+
rolledBack: function(record) {
|
3305
3164
|
record.transitionTo('loaded.saved');
|
3306
3165
|
}
|
3307
3166
|
},
|
@@ -3322,6 +3181,11 @@ var RootState = {
|
|
3322
3181
|
record.transitionTo('saved');
|
3323
3182
|
|
3324
3183
|
record.send('invokeLifecycleCallbacks');
|
3184
|
+
},
|
3185
|
+
|
3186
|
+
becameError: function(record) {
|
3187
|
+
record.transitionTo('uncommitted');
|
3188
|
+
record.triggerLater('becameError', record);
|
3325
3189
|
}
|
3326
3190
|
},
|
3327
3191
|
|
@@ -3701,8 +3565,18 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
3701
3565
|
Ember.run.once(this, this.updateRecordArrays);
|
3702
3566
|
},
|
3703
3567
|
|
3704
|
-
setupData: function(data) {
|
3705
|
-
|
3568
|
+
setupData: function(data, partial) {
|
3569
|
+
if (partial) {
|
3570
|
+
Ember.merge(this._data, data);
|
3571
|
+
} else {
|
3572
|
+
this._data = data;
|
3573
|
+
}
|
3574
|
+
|
3575
|
+
var relationships = this._relationships;
|
3576
|
+
|
3577
|
+
this.eachRelationship(function(name, rel) {
|
3578
|
+
if (rel.options.async) { relationships[name] = null; }
|
3579
|
+
});
|
3706
3580
|
|
3707
3581
|
if (data) { this.pushedData(); }
|
3708
3582
|
|
@@ -3730,8 +3604,8 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
3730
3604
|
},
|
3731
3605
|
|
3732
3606
|
rollback: function() {
|
3733
|
-
this.
|
3734
|
-
this.send('
|
3607
|
+
this._attributes = {};
|
3608
|
+
this.send('rolledBack');
|
3735
3609
|
|
3736
3610
|
this.suspendRelationshipObservers(function() {
|
3737
3611
|
this.notifyPropertyChange('data');
|
@@ -3962,21 +3836,48 @@ DS.Model.reopen({
|
|
3962
3836
|
}
|
3963
3837
|
});
|
3964
3838
|
|
3965
|
-
function
|
3966
|
-
|
3967
|
-
|
3968
|
-
|
3969
|
-
|
3970
|
-
if (typeof options.defaultValue === "function") {
|
3971
|
-
value = options.defaultValue();
|
3972
|
-
} else {
|
3973
|
-
value = options.defaultValue;
|
3974
|
-
}
|
3839
|
+
function getDefaultValue(record, options, key) {
|
3840
|
+
if (typeof options.defaultValue === "function") {
|
3841
|
+
return options.defaultValue();
|
3842
|
+
} else {
|
3843
|
+
return options.defaultValue;
|
3975
3844
|
}
|
3845
|
+
}
|
3976
3846
|
|
3977
|
-
|
3847
|
+
function hasValue(record, key) {
|
3848
|
+
return record._attributes.hasOwnProperty(key) ||
|
3849
|
+
record._inFlightAttributes.hasOwnProperty(key) ||
|
3850
|
+
record._data.hasOwnProperty(key);
|
3851
|
+
}
|
3852
|
+
|
3853
|
+
function getValue(record, key) {
|
3854
|
+
if (record._attributes.hasOwnProperty(key)) {
|
3855
|
+
return record._attributes[key];
|
3856
|
+
} else if (record._inFlightAttributes.hasOwnProperty(key)) {
|
3857
|
+
return record._inFlightAttributes[key];
|
3858
|
+
} else {
|
3859
|
+
return record._data[key];
|
3860
|
+
}
|
3978
3861
|
}
|
3979
3862
|
|
3863
|
+
/**
|
3864
|
+
`DS.attr` defines an attribute on a DS.Model.
|
3865
|
+
By default, attributes are passed through as-is, however you can specify an
|
3866
|
+
optional type to have the value automatically transformed.
|
3867
|
+
Ember Data ships with four basic transform types:
|
3868
|
+
'string', 'number', 'boolean' and 'date'.
|
3869
|
+
You can define your own transforms by subclassing DS.Transform.
|
3870
|
+
|
3871
|
+
DS.attr takes an optional hash as a second parameter, currently
|
3872
|
+
supported options are:
|
3873
|
+
'defaultValue': Pass a string or a function to be called to set the attribute
|
3874
|
+
to a default value if none is supplied.
|
3875
|
+
|
3876
|
+
@method attr
|
3877
|
+
@param {String} type the attribute type
|
3878
|
+
@param {Object} options a hash of options
|
3879
|
+
*/
|
3880
|
+
|
3980
3881
|
DS.attr = function(type, options) {
|
3981
3882
|
options = options || {};
|
3982
3883
|
|
@@ -3987,17 +3888,19 @@ DS.attr = function(type, options) {
|
|
3987
3888
|
};
|
3988
3889
|
|
3989
3890
|
return Ember.computed(function(key, value, oldValue) {
|
3891
|
+
var currentValue;
|
3892
|
+
|
3990
3893
|
if (arguments.length > 1) {
|
3991
3894
|
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');
|
3992
3895
|
this.send('didSetProperty', { name: key, oldValue: this._attributes[key] || this._inFlightAttributes[key] || this._data[key], value: value });
|
3993
3896
|
this._attributes[key] = value;
|
3994
|
-
|
3995
|
-
|
3897
|
+
return value;
|
3898
|
+
} else if (hasValue(this, key)) {
|
3899
|
+
return getValue(this, key);
|
3996
3900
|
} else {
|
3997
|
-
|
3901
|
+
return getDefaultValue(this, options, key);
|
3998
3902
|
}
|
3999
3903
|
|
4000
|
-
return value;
|
4001
3904
|
// `data` is never set directly. However, it may be
|
4002
3905
|
// invalidated from the state manager's setData
|
4003
3906
|
// event.
|
@@ -4542,14 +4445,21 @@ var get = Ember.get, set = Ember.set,
|
|
4542
4445
|
function asyncBelongsTo(type, options, meta) {
|
4543
4446
|
return Ember.computed(function(key, value) {
|
4544
4447
|
var data = get(this, 'data'),
|
4545
|
-
store = get(this, 'store')
|
4448
|
+
store = get(this, 'store'),
|
4449
|
+
belongsTo;
|
4546
4450
|
|
4547
4451
|
if (arguments.length === 2) {
|
4548
|
-
Ember.assert("You can only add a '" + type + "' record to this relationship", !value || store.modelFor(type)
|
4452
|
+
Ember.assert("You can only add a '" + type + "' record to this relationship", !value || value instanceof store.modelFor(type));
|
4549
4453
|
return value === undefined ? null : value;
|
4550
4454
|
}
|
4551
4455
|
|
4552
|
-
|
4456
|
+
belongsTo = data[key];
|
4457
|
+
|
4458
|
+
if(!isNone(belongsTo) && get(belongsTo, 'isEmpty')) {
|
4459
|
+
return store.fetchRecord(belongsTo);
|
4460
|
+
} else {
|
4461
|
+
return null;
|
4462
|
+
}
|
4553
4463
|
}).property('data').meta(meta);
|
4554
4464
|
}
|
4555
4465
|
|
@@ -4579,7 +4489,7 @@ DS.belongsTo = function(type, options) {
|
|
4579
4489
|
}
|
4580
4490
|
|
4581
4491
|
if (arguments.length === 2) {
|
4582
|
-
Ember.assert("You can only add a '" + type + "' record to this relationship", !value || typeClass
|
4492
|
+
Ember.assert("You can only add a '" + type + "' record to this relationship", !value || value instanceof typeClass);
|
4583
4493
|
return value === undefined ? null : value;
|
4584
4494
|
}
|
4585
4495
|
|
@@ -5376,7 +5286,7 @@ DS.RecordArrayManager = Ember.Object.extend({
|
|
5376
5286
|
*/
|
5377
5287
|
|
5378
5288
|
var get = Ember.get, set = Ember.set, merge = Ember.merge;
|
5379
|
-
var
|
5289
|
+
var map = Ember.ArrayPolyfills.map;
|
5380
5290
|
var resolve = Ember.RSVP.resolve;
|
5381
5291
|
|
5382
5292
|
var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
|
@@ -5441,7 +5351,7 @@ function aliasMethod(methodName) {
|
|
5441
5351
|
* `deleteRecords()`
|
5442
5352
|
* `commit()`
|
5443
5353
|
|
5444
|
-
For an example implementation, see `DS.
|
5354
|
+
For an example implementation, see `DS.RESTAdapter`, the
|
5445
5355
|
included REST adapter.
|
5446
5356
|
|
5447
5357
|
@class Adapter
|
@@ -5589,7 +5499,7 @@ DS.Adapter = Ember.Object.extend(DS._Mappable, {
|
|
5589
5499
|
@property {Array} ids
|
5590
5500
|
*/
|
5591
5501
|
findMany: function(store, type, ids) {
|
5592
|
-
var promises =
|
5502
|
+
var promises = map.call(ids, function(id) {
|
5593
5503
|
return this.find(store, type, id);
|
5594
5504
|
}, this);
|
5595
5505
|
|
@@ -5712,7 +5622,7 @@ DS.FixtureAdapter = DS.Adapter.extend({
|
|
5712
5622
|
var fixtures = this.fixturesForType(type),
|
5713
5623
|
fixture;
|
5714
5624
|
|
5715
|
-
Ember.
|
5625
|
+
Ember.assert("Unable to find fixtures for model type "+type.toString(), fixtures);
|
5716
5626
|
|
5717
5627
|
if (fixtures) {
|
5718
5628
|
fixture = Ember.A(fixtures).findProperty('id', id);
|
@@ -5734,7 +5644,7 @@ DS.FixtureAdapter = DS.Adapter.extend({
|
|
5734
5644
|
findMany: function(store, type, ids) {
|
5735
5645
|
var fixtures = this.fixturesForType(type);
|
5736
5646
|
|
5737
|
-
Ember.assert("Unable to find fixtures for model type "+type.toString(),
|
5647
|
+
Ember.assert("Unable to find fixtures for model type "+type.toString(), fixtures);
|
5738
5648
|
|
5739
5649
|
if (fixtures) {
|
5740
5650
|
fixtures = fixtures.filter(function(item) {
|
@@ -5757,7 +5667,7 @@ DS.FixtureAdapter = DS.Adapter.extend({
|
|
5757
5667
|
findAll: function(store, type) {
|
5758
5668
|
var fixtures = this.fixturesForType(type);
|
5759
5669
|
|
5760
|
-
Ember.assert("Unable to find fixtures for model type "+type.toString(),
|
5670
|
+
Ember.assert("Unable to find fixtures for model type "+type.toString(), fixtures);
|
5761
5671
|
|
5762
5672
|
return this.simulateRemoteCall(function() {
|
5763
5673
|
return fixtures;
|
@@ -5774,7 +5684,7 @@ DS.FixtureAdapter = DS.Adapter.extend({
|
|
5774
5684
|
findQuery: function(store, type, query, array) {
|
5775
5685
|
var fixtures = this.fixturesForType(type);
|
5776
5686
|
|
5777
|
-
Ember.assert("Unable to find fixtures for model type "+type.toString(),
|
5687
|
+
Ember.assert("Unable to find fixtures for model type "+type.toString(), fixtures);
|
5778
5688
|
|
5779
5689
|
fixtures = this.queryFixtures(fixtures, query, type);
|
5780
5690
|
|
@@ -5914,17 +5824,48 @@ DS.FixtureAdapter = DS.Adapter.extend({
|
|
5914
5824
|
*/
|
5915
5825
|
|
5916
5826
|
var get = Ember.get, set = Ember.set;
|
5917
|
-
|
5918
|
-
DS.rejectionHandler = function(reason) {
|
5919
|
-
Ember.Logger.assert([reason, reason.message, reason.stack]);
|
5920
|
-
|
5921
|
-
throw reason;
|
5922
|
-
};
|
5827
|
+
var forEach = Ember.ArrayPolyfills.forEach;
|
5923
5828
|
|
5924
5829
|
function coerceId(id) {
|
5925
5830
|
return id == null ? null : id+'';
|
5926
5831
|
}
|
5927
5832
|
|
5833
|
+
/**
|
5834
|
+
Normally, applications will use the `RESTSerializer` by implementing
|
5835
|
+
the `normalize` method and individual normalizations under
|
5836
|
+
`normalizeHash`.
|
5837
|
+
|
5838
|
+
This allows you to do whatever kind of munging you need, and is
|
5839
|
+
especially useful if your server is inconsistent and you need to
|
5840
|
+
do munging differently for many different kinds of responses.
|
5841
|
+
|
5842
|
+
See the `normalize` documentation for more information.
|
5843
|
+
|
5844
|
+
## Across the Board Normalization
|
5845
|
+
|
5846
|
+
There are also a number of hooks that you might find useful to defined
|
5847
|
+
across-the-board rules for your payload. These rules will be useful
|
5848
|
+
if your server is consistent, or if you're building an adapter for
|
5849
|
+
an infrastructure service, like Parse, and want to encode service
|
5850
|
+
conventions.
|
5851
|
+
|
5852
|
+
For example, if all of your keys are underscored and all-caps, but
|
5853
|
+
otherwise consistent with the names you use in your models, you
|
5854
|
+
can implement across-the-board rules for how to convert an attribute
|
5855
|
+
name in your model to a key in your JSON.
|
5856
|
+
|
5857
|
+
```js
|
5858
|
+
App.ApplicationSerializer = DS.RESTSerializer.extend({
|
5859
|
+
keyForAttribute: function(attr) {
|
5860
|
+
return Ember.String.underscore(attr).toUpperCase();
|
5861
|
+
}
|
5862
|
+
});
|
5863
|
+
```
|
5864
|
+
|
5865
|
+
You can also implement `keyForRelationship`, which takes the name
|
5866
|
+
of the relationship as the first parameter, and the kind of
|
5867
|
+
relationship (`hasMany` or `belongsTo`) as the second parameter.
|
5868
|
+
*/
|
5928
5869
|
DS.RESTSerializer = DS.JSONSerializer.extend({
|
5929
5870
|
/**
|
5930
5871
|
Normalizes a part of the JSON payload returned by
|
@@ -5990,15 +5931,17 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
5990
5931
|
@param {Object} hash
|
5991
5932
|
@returns Object
|
5992
5933
|
*/
|
5993
|
-
normalize: function(type,
|
5934
|
+
normalize: function(type, hash, prop) {
|
5994
5935
|
this.normalizeId(hash);
|
5995
|
-
this.
|
5936
|
+
this.normalizeUsingDeclaredMapping(type, hash);
|
5937
|
+
this.normalizeAttributes(type, hash);
|
5938
|
+
this.normalizeRelationships(type, hash);
|
5996
5939
|
|
5997
5940
|
if (this.normalizeHash && this.normalizeHash[prop]) {
|
5998
5941
|
return this.normalizeHash[prop](hash);
|
5999
5942
|
}
|
6000
5943
|
|
6001
|
-
return hash;
|
5944
|
+
return this._super(type, hash, prop);
|
6002
5945
|
},
|
6003
5946
|
|
6004
5947
|
/**
|
@@ -6014,20 +5957,56 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
6014
5957
|
delete hash[primaryKey];
|
6015
5958
|
},
|
6016
5959
|
|
5960
|
+
/**
|
5961
|
+
@method normalizeUsingDeclaredMapping
|
5962
|
+
@private
|
5963
|
+
*/
|
5964
|
+
normalizeUsingDeclaredMapping: function(type, hash) {
|
5965
|
+
var attrs = get(this, 'attrs'), payloadKey, key;
|
5966
|
+
|
5967
|
+
if (attrs) {
|
5968
|
+
for (key in attrs) {
|
5969
|
+
payloadKey = attrs[key];
|
5970
|
+
|
5971
|
+
hash[key] = hash[payloadKey];
|
5972
|
+
delete hash[payloadKey];
|
5973
|
+
}
|
5974
|
+
}
|
5975
|
+
},
|
5976
|
+
|
6017
5977
|
/**
|
6018
5978
|
@method normalizeAttributes
|
6019
5979
|
@private
|
6020
5980
|
*/
|
6021
|
-
normalizeAttributes: function(hash) {
|
6022
|
-
var
|
5981
|
+
normalizeAttributes: function(type, hash) {
|
5982
|
+
var payloadKey, key;
|
5983
|
+
|
5984
|
+
if (this.keyForAttribute) {
|
5985
|
+
type.eachAttribute(function(key) {
|
5986
|
+
payloadKey = this.keyForAttribute(key);
|
5987
|
+
if (key === payloadKey) { return; }
|
5988
|
+
|
5989
|
+
hash[key] = hash[payloadKey];
|
5990
|
+
delete hash[payloadKey];
|
5991
|
+
}, this);
|
5992
|
+
}
|
5993
|
+
},
|
6023
5994
|
|
6024
|
-
|
5995
|
+
/**
|
5996
|
+
@method normalizeRelationships
|
5997
|
+
@private
|
5998
|
+
*/
|
5999
|
+
normalizeRelationships: function(type, hash) {
|
6000
|
+
var payloadKey, key;
|
6025
6001
|
|
6026
|
-
|
6027
|
-
|
6002
|
+
if (this.keyForRelationship) {
|
6003
|
+
type.eachRelationship(function(key, relationship) {
|
6004
|
+
payloadKey = this.keyForRelationship(key, relationship.kind);
|
6005
|
+
if (key === payloadKey) { return; }
|
6028
6006
|
|
6029
|
-
|
6030
|
-
|
6007
|
+
hash[key] = hash[payloadKey];
|
6008
|
+
delete hash[payloadKey];
|
6009
|
+
}, this);
|
6031
6010
|
}
|
6032
6011
|
},
|
6033
6012
|
|
@@ -6114,7 +6093,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
6114
6093
|
for (var prop in payload) {
|
6115
6094
|
// legacy support for singular names
|
6116
6095
|
if (prop === primaryTypeName) {
|
6117
|
-
primaryRecord = this.normalize(primaryType, prop,
|
6096
|
+
primaryRecord = this.normalize(primaryType, payload[prop], prop);
|
6118
6097
|
continue;
|
6119
6098
|
}
|
6120
6099
|
|
@@ -6122,8 +6101,8 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
6122
6101
|
type = store.modelFor(typeName);
|
6123
6102
|
|
6124
6103
|
/*jshint loopfunc:true*/
|
6125
|
-
payload[prop]
|
6126
|
-
hash = this.normalize(type,
|
6104
|
+
forEach.call(payload[prop], function(hash) {
|
6105
|
+
hash = this.normalize(type, hash, prop);
|
6127
6106
|
|
6128
6107
|
var isFirstCreatedRecord = typeName === primaryTypeName && !recordId && !primaryRecord,
|
6129
6108
|
isUpdatedRecord = typeName === primaryTypeName && coerceId(hash.id) === recordId;
|
@@ -6251,7 +6230,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
6251
6230
|
|
6252
6231
|
/*jshint loopfunc:true*/
|
6253
6232
|
var normalizedArray = payload[prop].map(function(hash) {
|
6254
|
-
return this.normalize(type,
|
6233
|
+
return this.normalize(type, hash, prop);
|
6255
6234
|
}, this);
|
6256
6235
|
|
6257
6236
|
if (isPrimary) {
|
@@ -6427,6 +6406,18 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
6427
6406
|
}
|
6428
6407
|
});
|
6429
6408
|
|
6409
|
+
})();
|
6410
|
+
|
6411
|
+
|
6412
|
+
|
6413
|
+
(function() {
|
6414
|
+
/**
|
6415
|
+
@module ember-data
|
6416
|
+
*/
|
6417
|
+
|
6418
|
+
var get = Ember.get, set = Ember.set;
|
6419
|
+
var forEach = Ember.ArrayPolyfills.forEach;
|
6420
|
+
|
6430
6421
|
/**
|
6431
6422
|
The REST adapter allows your store to communicate with an HTTP server by
|
6432
6423
|
transmitting JSON via XHR. Most Ember.js apps that consume a JSON API
|
@@ -6498,11 +6489,11 @@ DS.RESTSerializer = DS.JSONSerializer.extend({
|
|
6498
6489
|
|
6499
6490
|
### Host customization
|
6500
6491
|
|
6501
|
-
An adapter can target other hosts by setting the `
|
6492
|
+
An adapter can target other hosts by setting the `host` property.
|
6502
6493
|
|
6503
6494
|
```js
|
6504
6495
|
DS.RESTAdapter.reopen({
|
6505
|
-
|
6496
|
+
host: 'https://api.example.com'
|
6506
6497
|
});
|
6507
6498
|
```
|
6508
6499
|
|
@@ -6544,7 +6535,7 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6544
6535
|
@returns Promise
|
6545
6536
|
*/
|
6546
6537
|
find: function(store, type, id) {
|
6547
|
-
return this.ajax(this.buildURL(type, id), 'GET');
|
6538
|
+
return this.ajax(this.buildURL(type.typeKey, id), 'GET');
|
6548
6539
|
},
|
6549
6540
|
|
6550
6541
|
/**
|
@@ -6559,10 +6550,17 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6559
6550
|
@see RESTAdapter/ajax
|
6560
6551
|
@param {DS.Store} store
|
6561
6552
|
@param {subclass of DS.Model} type
|
6553
|
+
@param {String} sinceToken
|
6562
6554
|
@returns Promise
|
6563
6555
|
*/
|
6564
|
-
findAll: function(store, type) {
|
6565
|
-
|
6556
|
+
findAll: function(store, type, sinceToken) {
|
6557
|
+
var query;
|
6558
|
+
|
6559
|
+
if (sinceToken) {
|
6560
|
+
query = { since: sinceToken };
|
6561
|
+
}
|
6562
|
+
|
6563
|
+
return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query });
|
6566
6564
|
},
|
6567
6565
|
|
6568
6566
|
/**
|
@@ -6584,7 +6582,7 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6584
6582
|
@returns Promise
|
6585
6583
|
*/
|
6586
6584
|
findQuery: function(store, type, query) {
|
6587
|
-
return this.ajax(this.buildURL(type), 'GET', query);
|
6585
|
+
return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query });
|
6588
6586
|
},
|
6589
6587
|
|
6590
6588
|
/**
|
@@ -6623,8 +6621,8 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6623
6621
|
@param {Array<String>} ids
|
6624
6622
|
@returns Promise
|
6625
6623
|
*/
|
6626
|
-
findMany: function(store, type, ids) {
|
6627
|
-
return this.ajax(this.buildURL(type), 'GET', { ids: ids });
|
6624
|
+
findMany: function(store, type, ids, owner) {
|
6625
|
+
return this.ajax(this.buildURL(type.typeKey), 'GET', { data: { ids: ids } });
|
6628
6626
|
},
|
6629
6627
|
|
6630
6628
|
/**
|
@@ -6680,9 +6678,9 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6680
6678
|
*/
|
6681
6679
|
createRecord: function(store, type, record) {
|
6682
6680
|
var data = {};
|
6683
|
-
data[type.typeKey] =
|
6681
|
+
data[type.typeKey] = store.serializerFor(type.typeKey).serialize(record, { includeId: true });
|
6684
6682
|
|
6685
|
-
return this.ajax(this.buildURL(type), "POST", { data: data });
|
6683
|
+
return this.ajax(this.buildURL(type.typeKey), "POST", { data: data });
|
6686
6684
|
},
|
6687
6685
|
|
6688
6686
|
/**
|
@@ -6704,11 +6702,11 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6704
6702
|
*/
|
6705
6703
|
updateRecord: function(store, type, record) {
|
6706
6704
|
var data = {};
|
6707
|
-
data[type.typeKey] =
|
6705
|
+
data[type.typeKey] = store.serializerFor(type.typeKey).serialize(record);
|
6708
6706
|
|
6709
6707
|
var id = get(record, 'id');
|
6710
6708
|
|
6711
|
-
return this.ajax(this.buildURL(type, id), "PUT", { data: data });
|
6709
|
+
return this.ajax(this.buildURL(type.typeKey, id), "PUT", { data: data });
|
6712
6710
|
},
|
6713
6711
|
|
6714
6712
|
/**
|
@@ -6728,38 +6726,65 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6728
6726
|
deleteRecord: function(store, type, record) {
|
6729
6727
|
var id = get(record, 'id');
|
6730
6728
|
|
6731
|
-
return this.ajax(this.buildURL(type, id), "DELETE");
|
6729
|
+
return this.ajax(this.buildURL(type.typeKey, id), "DELETE");
|
6730
|
+
},
|
6731
|
+
|
6732
|
+
/**
|
6733
|
+
Builds a URL for a given type and optional ID.
|
6734
|
+
|
6735
|
+
If an ID is specified, it adds the ID to the root generated
|
6736
|
+
for the type, separated by a `/`.
|
6737
|
+
|
6738
|
+
@method buildURL
|
6739
|
+
@param {String} type
|
6740
|
+
@param {String} id
|
6741
|
+
@returns String
|
6742
|
+
*/
|
6743
|
+
buildURL: function(type, id) {
|
6744
|
+
var host = get(this, 'host'),
|
6745
|
+
namespace = get(this, 'namespace'),
|
6746
|
+
url = [];
|
6747
|
+
|
6748
|
+
if (host) { url.push(host); }
|
6749
|
+
if (namespace) { url.push(namespace); }
|
6750
|
+
|
6751
|
+
url.push(this.rootForType(type));
|
6752
|
+
if (id) { url.push(id); }
|
6753
|
+
|
6754
|
+
url = url.join('/');
|
6755
|
+
if (!host) { url = '/' + url; }
|
6756
|
+
|
6757
|
+
return url;
|
6732
6758
|
},
|
6733
6759
|
|
6734
6760
|
/**
|
6735
|
-
|
6761
|
+
Determines the pathname root for a given type.
|
6736
6762
|
|
6737
6763
|
By default, it pluralizes the type's name (for example,
|
6738
6764
|
'post' becomes 'posts' and 'person' becomes 'people').
|
6739
6765
|
|
6740
|
-
|
6741
|
-
of the type, separated by a `/`.
|
6766
|
+
### Pathname root customization
|
6742
6767
|
|
6743
|
-
|
6744
|
-
|
6745
|
-
@param {String} id
|
6746
|
-
@returns String
|
6747
|
-
*/
|
6748
|
-
buildURL: function(type, id) {
|
6749
|
-
var url = "/" + Ember.String.pluralize(type.typeKey);
|
6750
|
-
if (id) { url += "/" + id; }
|
6768
|
+
For example if you have an object LineItem with an
|
6769
|
+
endpoint of "/line_items/".
|
6751
6770
|
|
6752
|
-
|
6753
|
-
|
6771
|
+
```js
|
6772
|
+
DS.RESTAdapter.reopen({
|
6773
|
+
rootForType: function(type) {
|
6774
|
+
var decamelized = Ember.String.decamelize(type);
|
6775
|
+
return Ember.String.pluralize(decamelized);
|
6776
|
+
};
|
6777
|
+
});
|
6778
|
+
```
|
6754
6779
|
|
6755
|
-
|
6756
|
-
|
6757
|
-
|
6758
|
-
|
6759
|
-
|
6780
|
+
@method rootForType
|
6781
|
+
@param {String} type
|
6782
|
+
@returns String
|
6783
|
+
**/
|
6784
|
+
rootForType: function(type) {
|
6785
|
+
return Ember.String.pluralize(type);
|
6760
6786
|
},
|
6761
6787
|
|
6762
|
-
|
6763
6788
|
/**
|
6764
6789
|
Takes a URL, an HTTP method and a hash of data, and makes an
|
6765
6790
|
HTTP request.
|
@@ -6801,7 +6826,7 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
6801
6826
|
if (adapter.headers !== undefined) {
|
6802
6827
|
var headers = adapter.headers;
|
6803
6828
|
hash.beforeSend = function (xhr) {
|
6804
|
-
Ember.keys(headers)
|
6829
|
+
forEach.call(Ember.keys(headers), function(key) {
|
6805
6830
|
xhr.setRequestHeader(key, headers[key]);
|
6806
6831
|
});
|
6807
6832
|
};
|
@@ -6945,3 +6970,242 @@ DS.Model.reopen({
|
|
6945
6970
|
|
6946
6971
|
})();
|
6947
6972
|
|
6973
|
+
(function() {
|
6974
|
+
Ember.String.pluralize = function(word) {
|
6975
|
+
return Ember.Inflector.inflector.pluralize(word);
|
6976
|
+
};
|
6977
|
+
|
6978
|
+
Ember.String.singularize = function(word) {
|
6979
|
+
return Ember.Inflector.inflector.singularize(word);
|
6980
|
+
};
|
6981
|
+
|
6982
|
+
})();
|
6983
|
+
|
6984
|
+
|
6985
|
+
|
6986
|
+
(function() {
|
6987
|
+
var BLANK_REGEX = /^\s*$/;
|
6988
|
+
|
6989
|
+
function loadUncountable(rules, uncountable) {
|
6990
|
+
for (var i = 0, length = uncountable.length; i < length; i++) {
|
6991
|
+
rules.uncountable[uncountable[i]] = true;
|
6992
|
+
}
|
6993
|
+
}
|
6994
|
+
|
6995
|
+
function loadIrregular(rules, irregularPairs) {
|
6996
|
+
var pair;
|
6997
|
+
|
6998
|
+
for (var i = 0, length = irregularPairs.length; i < length; i++) {
|
6999
|
+
pair = irregularPairs[i];
|
7000
|
+
|
7001
|
+
rules.irregular[pair[0]] = pair[1];
|
7002
|
+
rules.irregularInverse[pair[1]] = pair[0];
|
7003
|
+
}
|
7004
|
+
}
|
7005
|
+
|
7006
|
+
function Inflector(ruleSet) {
|
7007
|
+
ruleSet = ruleSet || {};
|
7008
|
+
ruleSet.uncountable = ruleSet.uncountable || {};
|
7009
|
+
ruleSet.irregularPairs= ruleSet.irregularPairs|| {};
|
7010
|
+
|
7011
|
+
var rules = this.rules = {
|
7012
|
+
plurals: ruleSet.plurals || [],
|
7013
|
+
singular: ruleSet.singular || [],
|
7014
|
+
irregular: {},
|
7015
|
+
irregularInverse: {},
|
7016
|
+
uncountable: {}
|
7017
|
+
};
|
7018
|
+
|
7019
|
+
loadUncountable(rules, ruleSet.uncountable);
|
7020
|
+
loadIrregular(rules, ruleSet.irregularPairs);
|
7021
|
+
}
|
7022
|
+
|
7023
|
+
Inflector.prototype = {
|
7024
|
+
pluralize: function(word) {
|
7025
|
+
return this.inflect(word, this.rules.plurals);
|
7026
|
+
},
|
7027
|
+
|
7028
|
+
singularize: function(word) {
|
7029
|
+
return this.inflect(word, this.rules.singular);
|
7030
|
+
},
|
7031
|
+
|
7032
|
+
inflect: function(word, typeRules) {
|
7033
|
+
var inflection, substitution, result, lowercase, isBlank,
|
7034
|
+
isUncountable, isIrregular, isIrregularInverse, rule;
|
7035
|
+
|
7036
|
+
isBlank = BLANK_REGEX.test(word);
|
7037
|
+
|
7038
|
+
if (isBlank) {
|
7039
|
+
return word;
|
7040
|
+
}
|
7041
|
+
|
7042
|
+
lowercase = word.toLowerCase();
|
7043
|
+
|
7044
|
+
isUncountable = this.rules.uncountable[lowercase];
|
7045
|
+
|
7046
|
+
if (isUncountable) {
|
7047
|
+
return word;
|
7048
|
+
}
|
7049
|
+
|
7050
|
+
isIrregular = this.rules.irregular[lowercase];
|
7051
|
+
|
7052
|
+
if (isIrregular) {
|
7053
|
+
return isIrregular;
|
7054
|
+
}
|
7055
|
+
|
7056
|
+
isIrregularInverse = this.rules.irregularInverse[lowercase];
|
7057
|
+
|
7058
|
+
if (isIrregularInverse) {
|
7059
|
+
return isIrregularInverse;
|
7060
|
+
}
|
7061
|
+
|
7062
|
+
for (var i = typeRules.length, min = 0; i > min; i--) {
|
7063
|
+
inflection = typeRules[i-1];
|
7064
|
+
rule = inflection[0];
|
7065
|
+
|
7066
|
+
if (rule.test(word)) {
|
7067
|
+
break;
|
7068
|
+
}
|
7069
|
+
}
|
7070
|
+
|
7071
|
+
inflection = inflection || [];
|
7072
|
+
|
7073
|
+
rule = inflection[0];
|
7074
|
+
substitution = inflection[1];
|
7075
|
+
|
7076
|
+
result = word.replace(rule, substitution);
|
7077
|
+
|
7078
|
+
return result;
|
7079
|
+
}
|
7080
|
+
};
|
7081
|
+
|
7082
|
+
Ember.Inflector = Inflector;
|
7083
|
+
|
7084
|
+
})();
|
7085
|
+
|
7086
|
+
|
7087
|
+
|
7088
|
+
(function() {
|
7089
|
+
Ember.Inflector.defaultRules = {
|
7090
|
+
plurals: [
|
7091
|
+
[/$/, 's'],
|
7092
|
+
[/s$/i, 's'],
|
7093
|
+
[/^(ax|test)is$/i, '$1es'],
|
7094
|
+
[/(octop|vir)us$/i, '$1i'],
|
7095
|
+
[/(octop|vir)i$/i, '$1i'],
|
7096
|
+
[/(alias|status)$/i, '$1es'],
|
7097
|
+
[/(bu)s$/i, '$1ses'],
|
7098
|
+
[/(buffal|tomat)o$/i, '$1oes'],
|
7099
|
+
[/([ti])um$/i, '$1a'],
|
7100
|
+
[/([ti])a$/i, '$1a'],
|
7101
|
+
[/sis$/i, 'ses'],
|
7102
|
+
[/(?:([^f])fe|([lr])f)$/i, '$1$2ves'],
|
7103
|
+
[/(hive)$/i, '$1s'],
|
7104
|
+
[/([^aeiouy]|qu)y$/i, '$1ies'],
|
7105
|
+
[/(x|ch|ss|sh)$/i, '$1es'],
|
7106
|
+
[/(matr|vert|ind)(?:ix|ex)$/i, '$1ices'],
|
7107
|
+
[/^(m|l)ouse$/i, '$1ice'],
|
7108
|
+
[/^(m|l)ice$/i, '$1ice'],
|
7109
|
+
[/^(ox)$/i, '$1en'],
|
7110
|
+
[/^(oxen)$/i, '$1'],
|
7111
|
+
[/(quiz)$/i, '$1zes']
|
7112
|
+
],
|
7113
|
+
|
7114
|
+
singular: [
|
7115
|
+
[/s$/i, ''],
|
7116
|
+
[/(ss)$/i, '$1'],
|
7117
|
+
[/(n)ews$/i, '$1ews'],
|
7118
|
+
[/([ti])a$/i, '$1um'],
|
7119
|
+
[/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '$1sis'],
|
7120
|
+
[/(^analy)(sis|ses)$/i, '$1sis'],
|
7121
|
+
[/([^f])ves$/i, '$1fe'],
|
7122
|
+
[/(hive)s$/i, '$1'],
|
7123
|
+
[/(tive)s$/i, '$1'],
|
7124
|
+
[/([lr])ves$/i, '$1f'],
|
7125
|
+
[/([^aeiouy]|qu)ies$/i, '$1y'],
|
7126
|
+
[/(s)eries$/i, '$1eries'],
|
7127
|
+
[/(m)ovies$/i, '$1ovie'],
|
7128
|
+
[/(x|ch|ss|sh)es$/i, '$1'],
|
7129
|
+
[/^(m|l)ice$/i, '$1ouse'],
|
7130
|
+
[/(bus)(es)?$/i, '$1'],
|
7131
|
+
[/(o)es$/i, '$1'],
|
7132
|
+
[/(shoe)s$/i, '$1'],
|
7133
|
+
[/(cris|test)(is|es)$/i, '$1is'],
|
7134
|
+
[/^(a)x[ie]s$/i, '$1xis'],
|
7135
|
+
[/(octop|vir)(us|i)$/i, '$1us'],
|
7136
|
+
[/(alias|status)(es)?$/i, '$1'],
|
7137
|
+
[/^(ox)en/i, '$1'],
|
7138
|
+
[/(vert|ind)ices$/i, '$1ex'],
|
7139
|
+
[/(matr)ices$/i, '$1ix'],
|
7140
|
+
[/(quiz)zes$/i, '$1'],
|
7141
|
+
[/(database)s$/i, '$1']
|
7142
|
+
],
|
7143
|
+
|
7144
|
+
irregularPairs: [
|
7145
|
+
['person', 'people'],
|
7146
|
+
['man', 'men'],
|
7147
|
+
['child', 'children'],
|
7148
|
+
['sex', 'sexes'],
|
7149
|
+
['move', 'moves'],
|
7150
|
+
['cow', 'kine'],
|
7151
|
+
['zombie', 'zombies']
|
7152
|
+
],
|
7153
|
+
|
7154
|
+
uncountable: [
|
7155
|
+
'equipment',
|
7156
|
+
'information',
|
7157
|
+
'rice',
|
7158
|
+
'money',
|
7159
|
+
'species',
|
7160
|
+
'series',
|
7161
|
+
'fish',
|
7162
|
+
'sheep',
|
7163
|
+
'jeans',
|
7164
|
+
'police'
|
7165
|
+
]
|
7166
|
+
};
|
7167
|
+
|
7168
|
+
})();
|
7169
|
+
|
7170
|
+
|
7171
|
+
|
7172
|
+
(function() {
|
7173
|
+
if (Ember.EXTEND_PROTOTYPES) {
|
7174
|
+
/**
|
7175
|
+
See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}}
|
7176
|
+
|
7177
|
+
@method pluralize
|
7178
|
+
@for String
|
7179
|
+
*/
|
7180
|
+
String.prototype.pluralize = function() {
|
7181
|
+
return Ember.String.pluralize(this);
|
7182
|
+
};
|
7183
|
+
|
7184
|
+
/**
|
7185
|
+
See {{#crossLink "Ember.String/singularize"}}{{/crossLink}}
|
7186
|
+
|
7187
|
+
@method singularize
|
7188
|
+
@for String
|
7189
|
+
*/
|
7190
|
+
String.prototype.singularize = function() {
|
7191
|
+
return Ember.String.singularize(this);
|
7192
|
+
};
|
7193
|
+
}
|
7194
|
+
|
7195
|
+
})();
|
7196
|
+
|
7197
|
+
|
7198
|
+
|
7199
|
+
(function() {
|
7200
|
+
Ember.Inflector.inflector = new Ember.Inflector(Ember.Inflector.defaultRules);
|
7201
|
+
|
7202
|
+
})();
|
7203
|
+
|
7204
|
+
|
7205
|
+
|
7206
|
+
(function() {
|
7207
|
+
|
7208
|
+
})();
|
7209
|
+
|
7210
|
+
|
7211
|
+
})();
|