ember-data-source 1.0.0.beta.1 → 1.0.0.beta.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/dist/ember-data.js +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
|
+
})();
|