@ember-data/model 4.3.0 → 4.4.0-alpha.10
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.
- package/addon/-private/{errors.js → errors.ts} +82 -55
- package/addon/-private/model.js +15 -4
- package/addon/-private/system/{diff-array.js → diff-array.ts} +8 -2
- package/addon/-private/system/{many-array.js → many-array.ts} +72 -29
- package/addon/-private/system/promise-belongs-to.ts +72 -0
- package/addon/-private/system/promise-many-array.ts +20 -5
- package/package.json +7 -7
- package/addon/-private/system/promise-belongs-to.js +0 -41
|
@@ -1,11 +1,29 @@
|
|
|
1
|
-
import { A
|
|
1
|
+
import { A } from '@ember/array';
|
|
2
|
+
import type NativeArray from '@ember/array/-private/native-array';
|
|
2
3
|
import ArrayProxy from '@ember/array/proxy';
|
|
3
4
|
import { computed, get } from '@ember/object';
|
|
4
5
|
import { mapBy, not } from '@ember/object/computed';
|
|
5
6
|
|
|
7
|
+
type ValidationError = {
|
|
8
|
+
attribute: string;
|
|
9
|
+
message: string;
|
|
10
|
+
};
|
|
6
11
|
/**
|
|
7
|
-
@module @ember-data/
|
|
12
|
+
@module @ember-data/model
|
|
8
13
|
*/
|
|
14
|
+
interface ArrayProxyWithCustomOverrides<T, M = T> extends Omit<ArrayProxy<T, M>, 'clear' | 'content'> {
|
|
15
|
+
// Omit causes `content` to be merged with the class def for ArrayProxy
|
|
16
|
+
// which then causes it to be seen as a property, disallowing defining it
|
|
17
|
+
// as an accessor. This restores our ability to define it as an accessor.
|
|
18
|
+
content: NativeArray<T>;
|
|
19
|
+
clear(): void;
|
|
20
|
+
_has(name: string): boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// we force the type here to our own construct because mixin and extend patterns
|
|
24
|
+
// lose generic signatures. We also do this because we need to Omit `clear` from
|
|
25
|
+
// the type of ArrayProxy as we override it's signature.
|
|
26
|
+
const ArrayProxyWithCustomOverrides = ArrayProxy as unknown as new <T, M = T>() => ArrayProxyWithCustomOverrides<T, M>;
|
|
9
27
|
|
|
10
28
|
/**
|
|
11
29
|
Holds validation errors for a given record, organized by attribute names.
|
|
@@ -82,28 +100,34 @@ import { mapBy, not } from '@ember/object/computed';
|
|
|
82
100
|
@public
|
|
83
101
|
@extends Ember.ArrayProxy
|
|
84
102
|
*/
|
|
85
|
-
export default
|
|
103
|
+
export default class Errors extends ArrayProxyWithCustomOverrides<ValidationError> {
|
|
104
|
+
declare _registeredHandlers?: {
|
|
105
|
+
becameInvalid: () => void;
|
|
106
|
+
becameValid: () => void;
|
|
107
|
+
};
|
|
108
|
+
|
|
86
109
|
/**
|
|
87
110
|
Register with target handler
|
|
88
111
|
|
|
89
112
|
@method _registerHandlers
|
|
90
113
|
@private
|
|
91
114
|
*/
|
|
92
|
-
_registerHandlers(becameInvalid, becameValid) {
|
|
115
|
+
_registerHandlers(becameInvalid: () => void, becameValid: () => void): void {
|
|
93
116
|
this._registeredHandlers = {
|
|
94
117
|
becameInvalid,
|
|
95
118
|
becameValid,
|
|
96
119
|
};
|
|
97
|
-
}
|
|
120
|
+
}
|
|
98
121
|
|
|
99
122
|
/**
|
|
100
123
|
@property errorsByAttributeName
|
|
101
124
|
@type {MapWithDefault}
|
|
102
125
|
@private
|
|
103
126
|
*/
|
|
104
|
-
|
|
127
|
+
@computed()
|
|
128
|
+
get errorsByAttributeName(): Map<string, NativeArray<ValidationError>> {
|
|
105
129
|
return new Map();
|
|
106
|
-
}
|
|
130
|
+
}
|
|
107
131
|
|
|
108
132
|
/**
|
|
109
133
|
Returns errors for a given attribute
|
|
@@ -124,13 +148,13 @@ export default ArrayProxy.extend({
|
|
|
124
148
|
@param {String} attribute
|
|
125
149
|
@return {Array}
|
|
126
150
|
*/
|
|
127
|
-
errorsFor(attribute) {
|
|
128
|
-
let map =
|
|
151
|
+
errorsFor(attribute: string): NativeArray<ValidationError> {
|
|
152
|
+
let map = this.errorsByAttributeName;
|
|
129
153
|
|
|
130
154
|
let errors = map.get(attribute);
|
|
131
155
|
|
|
132
156
|
if (errors === undefined) {
|
|
133
|
-
errors = A();
|
|
157
|
+
errors = A<ValidationError>();
|
|
134
158
|
map.set(attribute, errors);
|
|
135
159
|
}
|
|
136
160
|
|
|
@@ -141,7 +165,7 @@ export default ArrayProxy.extend({
|
|
|
141
165
|
get(errors, '[]');
|
|
142
166
|
|
|
143
167
|
return errors;
|
|
144
|
-
}
|
|
168
|
+
}
|
|
145
169
|
|
|
146
170
|
/**
|
|
147
171
|
An array containing all of the error messages for this
|
|
@@ -159,28 +183,30 @@ export default ArrayProxy.extend({
|
|
|
159
183
|
@public
|
|
160
184
|
@type {Array}
|
|
161
185
|
*/
|
|
162
|
-
|
|
186
|
+
@mapBy('content', 'message')
|
|
187
|
+
declare messages: string[];
|
|
163
188
|
|
|
164
189
|
/**
|
|
165
190
|
@property content
|
|
166
191
|
@type {Array}
|
|
167
192
|
@private
|
|
168
193
|
*/
|
|
169
|
-
|
|
194
|
+
@computed()
|
|
195
|
+
get content(): NativeArray<ValidationError> {
|
|
170
196
|
return A();
|
|
171
|
-
}
|
|
197
|
+
}
|
|
172
198
|
|
|
173
199
|
/**
|
|
174
200
|
@method unknownProperty
|
|
175
201
|
@private
|
|
176
202
|
*/
|
|
177
|
-
unknownProperty(attribute) {
|
|
203
|
+
unknownProperty(attribute: string) {
|
|
178
204
|
let errors = this.errorsFor(attribute);
|
|
179
205
|
if (errors.length === 0) {
|
|
180
206
|
return undefined;
|
|
181
207
|
}
|
|
182
208
|
return errors;
|
|
183
|
-
}
|
|
209
|
+
}
|
|
184
210
|
|
|
185
211
|
/**
|
|
186
212
|
Total number of errors.
|
|
@@ -199,7 +225,8 @@ export default ArrayProxy.extend({
|
|
|
199
225
|
@public
|
|
200
226
|
@readOnly
|
|
201
227
|
*/
|
|
202
|
-
|
|
228
|
+
@not('length')
|
|
229
|
+
declare isEmpty: boolean;
|
|
203
230
|
|
|
204
231
|
/**
|
|
205
232
|
Manually adds errors to the record. This will trigger the `becameInvalid` event/ lifecycle method on
|
|
@@ -233,20 +260,20 @@ export default ArrayProxy.extend({
|
|
|
233
260
|
// { attribute: 'username', message: 'This field is required' },
|
|
234
261
|
// ]
|
|
235
262
|
```
|
|
236
|
-
|
|
263
|
+
@method add
|
|
237
264
|
@public
|
|
238
|
-
|
|
239
|
-
|
|
265
|
+
@param {string} attribute - the property name of an attribute or relationship
|
|
266
|
+
@param {string[]|string} messages - an error message or array of error messages for the attribute
|
|
240
267
|
*/
|
|
241
|
-
add(attribute, messages) {
|
|
242
|
-
let wasEmpty =
|
|
268
|
+
add(attribute: string, messages: string[] | string): void {
|
|
269
|
+
let wasEmpty: boolean = this.isEmpty;
|
|
243
270
|
|
|
244
271
|
this._add(attribute, messages);
|
|
245
272
|
|
|
246
|
-
if (wasEmpty && !
|
|
273
|
+
if (wasEmpty && !this.isEmpty) {
|
|
247
274
|
this._registeredHandlers && this._registeredHandlers.becameInvalid();
|
|
248
275
|
}
|
|
249
|
-
}
|
|
276
|
+
}
|
|
250
277
|
|
|
251
278
|
/**
|
|
252
279
|
Adds error messages to a given attribute without sending event.
|
|
@@ -254,23 +281,23 @@ export default ArrayProxy.extend({
|
|
|
254
281
|
@method _add
|
|
255
282
|
@private
|
|
256
283
|
*/
|
|
257
|
-
_add(attribute, messages) {
|
|
258
|
-
|
|
259
|
-
this.addObjects(
|
|
284
|
+
_add(attribute: string, messages: string[] | string) {
|
|
285
|
+
const errors = this._findOrCreateMessages(attribute, messages);
|
|
286
|
+
this.addObjects(errors);
|
|
260
287
|
|
|
261
|
-
this.errorsFor(attribute).addObjects(
|
|
288
|
+
this.errorsFor(attribute).addObjects(errors);
|
|
262
289
|
|
|
263
290
|
this.notifyPropertyChange(attribute);
|
|
264
|
-
}
|
|
291
|
+
}
|
|
265
292
|
|
|
266
293
|
/**
|
|
267
294
|
@method _findOrCreateMessages
|
|
268
295
|
@private
|
|
269
296
|
*/
|
|
270
|
-
_findOrCreateMessages(attribute, messages) {
|
|
297
|
+
_findOrCreateMessages(attribute: string, messages: string | string[]): ValidationError[] {
|
|
271
298
|
let errors = this.errorsFor(attribute);
|
|
272
|
-
let messagesArray =
|
|
273
|
-
let _messages = new Array(messagesArray.length);
|
|
299
|
+
let messagesArray = Array.isArray(messages) ? messages : [messages];
|
|
300
|
+
let _messages: ValidationError[] = new Array(messagesArray.length) as ValidationError[];
|
|
274
301
|
|
|
275
302
|
for (let i = 0; i < messagesArray.length; i++) {
|
|
276
303
|
let message = messagesArray[i];
|
|
@@ -280,13 +307,13 @@ export default ArrayProxy.extend({
|
|
|
280
307
|
} else {
|
|
281
308
|
_messages[i] = {
|
|
282
309
|
attribute: attribute,
|
|
283
|
-
message
|
|
310
|
+
message,
|
|
284
311
|
};
|
|
285
312
|
}
|
|
286
313
|
}
|
|
287
314
|
|
|
288
315
|
return _messages;
|
|
289
|
-
}
|
|
316
|
+
}
|
|
290
317
|
|
|
291
318
|
/**
|
|
292
319
|
Manually removes all errors for a given member from the record.
|
|
@@ -315,17 +342,17 @@ export default ArrayProxy.extend({
|
|
|
315
342
|
@public
|
|
316
343
|
@param {string} member - the property name of an attribute or relationship
|
|
317
344
|
*/
|
|
318
|
-
remove(attribute) {
|
|
319
|
-
if (
|
|
345
|
+
remove(attribute: string) {
|
|
346
|
+
if (this.isEmpty) {
|
|
320
347
|
return;
|
|
321
348
|
}
|
|
322
349
|
|
|
323
350
|
this._remove(attribute);
|
|
324
351
|
|
|
325
|
-
if (
|
|
352
|
+
if (this.isEmpty) {
|
|
326
353
|
this._registeredHandlers && this._registeredHandlers.becameValid();
|
|
327
354
|
}
|
|
328
|
-
}
|
|
355
|
+
}
|
|
329
356
|
|
|
330
357
|
/**
|
|
331
358
|
Removes all error messages from the given attribute without sending event.
|
|
@@ -333,13 +360,13 @@ export default ArrayProxy.extend({
|
|
|
333
360
|
@method _remove
|
|
334
361
|
@private
|
|
335
362
|
*/
|
|
336
|
-
_remove(attribute) {
|
|
337
|
-
if (
|
|
363
|
+
_remove(attribute: string) {
|
|
364
|
+
if (this.isEmpty) {
|
|
338
365
|
return;
|
|
339
366
|
}
|
|
340
367
|
|
|
341
368
|
let content = this.rejectBy('attribute', attribute);
|
|
342
|
-
|
|
369
|
+
this.content.setObjects(content);
|
|
343
370
|
|
|
344
371
|
// Although errorsByAttributeName.delete is technically enough to sync errors state, we also
|
|
345
372
|
// must mutate the array as well for autotracking
|
|
@@ -350,11 +377,11 @@ export default ArrayProxy.extend({
|
|
|
350
377
|
errors.replace(i, 1);
|
|
351
378
|
}
|
|
352
379
|
}
|
|
353
|
-
|
|
380
|
+
this.errorsByAttributeName.delete(attribute);
|
|
354
381
|
|
|
355
382
|
this.notifyPropertyChange(attribute);
|
|
356
383
|
this.notifyPropertyChange('length');
|
|
357
|
-
}
|
|
384
|
+
}
|
|
358
385
|
|
|
359
386
|
/**
|
|
360
387
|
Manually clears all errors for the record.
|
|
@@ -393,16 +420,16 @@ export default ArrayProxy.extend({
|
|
|
393
420
|
// => []
|
|
394
421
|
```
|
|
395
422
|
@method clear
|
|
396
|
-
|
|
423
|
+
@public
|
|
397
424
|
*/
|
|
398
|
-
clear() {
|
|
399
|
-
if (
|
|
425
|
+
clear(): void {
|
|
426
|
+
if (this.isEmpty) {
|
|
400
427
|
return;
|
|
401
428
|
}
|
|
402
429
|
|
|
403
430
|
this._clear();
|
|
404
431
|
this._registeredHandlers && this._registeredHandlers.becameValid();
|
|
405
|
-
}
|
|
432
|
+
}
|
|
406
433
|
|
|
407
434
|
/**
|
|
408
435
|
Removes all error messages.
|
|
@@ -411,13 +438,13 @@ export default ArrayProxy.extend({
|
|
|
411
438
|
@method _clear
|
|
412
439
|
@private
|
|
413
440
|
*/
|
|
414
|
-
_clear() {
|
|
415
|
-
if (
|
|
441
|
+
_clear(): void {
|
|
442
|
+
if (this.isEmpty) {
|
|
416
443
|
return;
|
|
417
444
|
}
|
|
418
445
|
|
|
419
|
-
let errorsByAttributeName =
|
|
420
|
-
let attributes = [];
|
|
446
|
+
let errorsByAttributeName = this.errorsByAttributeName;
|
|
447
|
+
let attributes: string[] = [];
|
|
421
448
|
|
|
422
449
|
errorsByAttributeName.forEach(function (_, attribute) {
|
|
423
450
|
attributes.push(attribute);
|
|
@@ -429,7 +456,7 @@ export default ArrayProxy.extend({
|
|
|
429
456
|
});
|
|
430
457
|
|
|
431
458
|
ArrayProxy.prototype.clear.call(this);
|
|
432
|
-
}
|
|
459
|
+
}
|
|
433
460
|
|
|
434
461
|
/**
|
|
435
462
|
Checks if there are error messages for the given attribute.
|
|
@@ -454,7 +481,7 @@ export default ArrayProxy.extend({
|
|
|
454
481
|
@param {String} attribute
|
|
455
482
|
@return {Boolean} true if there some errors on given attribute
|
|
456
483
|
*/
|
|
457
|
-
has(attribute) {
|
|
484
|
+
has(attribute: string): boolean {
|
|
458
485
|
return this.errorsFor(attribute).length > 0;
|
|
459
|
-
}
|
|
460
|
-
}
|
|
486
|
+
}
|
|
487
|
+
}
|
package/addon/-private/model.js
CHANGED
|
@@ -13,7 +13,15 @@ import { tracked } from '@glimmer/tracking';
|
|
|
13
13
|
import Ember from 'ember';
|
|
14
14
|
|
|
15
15
|
import { HAS_DEBUG_PACKAGE } from '@ember-data/private-build-infra';
|
|
16
|
-
import {
|
|
16
|
+
import { DEPRECATE_SAVE_PROMISE_ACCESS } from '@ember-data/private-build-infra/deprecations';
|
|
17
|
+
import {
|
|
18
|
+
coerceId,
|
|
19
|
+
deprecatedPromiseObject,
|
|
20
|
+
errorsArrayToHash,
|
|
21
|
+
InternalModel,
|
|
22
|
+
PromiseObject,
|
|
23
|
+
recordDataFor,
|
|
24
|
+
} from '@ember-data/store/-private';
|
|
17
25
|
|
|
18
26
|
import Errors from './errors';
|
|
19
27
|
import RecordState, { peekTag, tagged } from './record-state';
|
|
@@ -846,9 +854,12 @@ class Model extends EmberObject {
|
|
|
846
854
|
successfully or rejected if the adapter returns with an error.
|
|
847
855
|
*/
|
|
848
856
|
save(options) {
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
857
|
+
const promise = this._internalModel.save(options).then(() => this);
|
|
858
|
+
if (DEPRECATE_SAVE_PROMISE_ACCESS) {
|
|
859
|
+
return deprecatedPromiseObject(PromiseObject.create({ promise }));
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
return promise;
|
|
852
863
|
}
|
|
853
864
|
|
|
854
865
|
/**
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
@module @ember-data/model
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
export interface ArrayDiffResult {
|
|
6
|
+
firstChangeIndex: number | null;
|
|
7
|
+
removedCount: number;
|
|
8
|
+
addedCount: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
5
11
|
/**
|
|
6
12
|
@method diffArray
|
|
7
13
|
@internal
|
|
@@ -13,12 +19,12 @@
|
|
|
13
19
|
removedCount: <integer> // 0 if no change
|
|
14
20
|
}
|
|
15
21
|
*/
|
|
16
|
-
export default function diffArray(oldArray, newArray) {
|
|
22
|
+
export default function diffArray(oldArray: unknown[], newArray: unknown[]): ArrayDiffResult {
|
|
17
23
|
const oldLength = oldArray.length;
|
|
18
24
|
const newLength = newArray.length;
|
|
19
25
|
|
|
20
26
|
const shortestLength = Math.min(oldLength, newLength);
|
|
21
|
-
let firstChangeIndex = null; // null signifies no changes
|
|
27
|
+
let firstChangeIndex: number | null = null; // null signifies no changes
|
|
22
28
|
|
|
23
29
|
// find the first change
|
|
24
30
|
for (let i = 0; i < shortestLength; i++) {
|
|
@@ -8,10 +8,36 @@ import EmberObject, { get } from '@ember/object';
|
|
|
8
8
|
|
|
9
9
|
import { all } from 'rsvp';
|
|
10
10
|
|
|
11
|
+
import type { RelationshipRecordData } from '@ember-data/record-data/-private/ts-interfaces/relationship-record-data';
|
|
12
|
+
import type { InternalModel } from '@ember-data/store/-private';
|
|
11
13
|
import { PromiseArray, recordDataFor } from '@ember-data/store/-private';
|
|
14
|
+
import type CoreStore from '@ember-data/store/-private/system/core-store';
|
|
15
|
+
import type { CreateRecordProperties } from '@ember-data/store/-private/system/core-store';
|
|
16
|
+
import ShimModelClass from '@ember-data/store/-private/system/model/shim-model-class';
|
|
17
|
+
import type { DSModelSchema } from '@ember-data/store/-private/ts-interfaces/ds-model';
|
|
18
|
+
import type { Links, PaginationLinks } from '@ember-data/store/-private/ts-interfaces/ember-data-json-api';
|
|
19
|
+
import type { RecordInstance } from '@ember-data/store/-private/ts-interfaces/record-instance';
|
|
20
|
+
import type { Dict } from '@ember-data/store/-private/ts-interfaces/utils';
|
|
12
21
|
|
|
13
22
|
import diffArray from './diff-array';
|
|
14
23
|
|
|
24
|
+
interface MutableArrayWithObject<T, M = T> extends EmberObject, MutableArray<M> {}
|
|
25
|
+
const MutableArrayWithObject = EmberObject.extend(MutableArray) as unknown as new <
|
|
26
|
+
T,
|
|
27
|
+
M = T
|
|
28
|
+
>() => MutableArrayWithObject<T, M>;
|
|
29
|
+
|
|
30
|
+
export interface ManyArrayCreateArgs {
|
|
31
|
+
store: CoreStore;
|
|
32
|
+
type: ShimModelClass;
|
|
33
|
+
recordData: RelationshipRecordData;
|
|
34
|
+
key: string;
|
|
35
|
+
isPolymorphic: boolean;
|
|
36
|
+
isAsync: boolean;
|
|
37
|
+
_inverseIsAsync: boolean;
|
|
38
|
+
internalModel: InternalModel;
|
|
39
|
+
isLoaded: boolean;
|
|
40
|
+
}
|
|
15
41
|
/**
|
|
16
42
|
A `ManyArray` is a `MutableArray` that represents the contents of a has-many
|
|
17
43
|
relationship.
|
|
@@ -57,12 +83,27 @@ import diffArray from './diff-array';
|
|
|
57
83
|
@extends Ember.EmberObject
|
|
58
84
|
@uses Ember.MutableArray
|
|
59
85
|
*/
|
|
60
|
-
export default
|
|
61
|
-
isAsync:
|
|
62
|
-
isLoaded:
|
|
86
|
+
export default class ManyArray extends MutableArrayWithObject<InternalModel, RecordInstance> {
|
|
87
|
+
declare isAsync: boolean;
|
|
88
|
+
declare isLoaded: boolean;
|
|
89
|
+
declare isPolymorphic: boolean;
|
|
90
|
+
declare _isDirty: boolean;
|
|
91
|
+
declare _isUpdating: boolean;
|
|
92
|
+
declare _hasNotified: boolean;
|
|
93
|
+
declare __hasArrayObservers: boolean;
|
|
94
|
+
declare hasArrayObservers: boolean; // override the base declaration
|
|
95
|
+
declare _length: number;
|
|
96
|
+
declare _meta: Dict<unknown> | null;
|
|
97
|
+
declare _links: Links | PaginationLinks | null;
|
|
98
|
+
declare currentState: InternalModel[];
|
|
99
|
+
declare recordData: RelationshipRecordData;
|
|
100
|
+
declare internalModel: InternalModel;
|
|
101
|
+
declare store: CoreStore;
|
|
102
|
+
declare key: string;
|
|
103
|
+
declare type: DSModelSchema;
|
|
63
104
|
|
|
64
105
|
init() {
|
|
65
|
-
|
|
106
|
+
super.init();
|
|
66
107
|
|
|
67
108
|
/**
|
|
68
109
|
The loading state of this array
|
|
@@ -71,6 +112,7 @@ export default EmberObject.extend(MutableArray, {
|
|
|
71
112
|
@public
|
|
72
113
|
*/
|
|
73
114
|
this.isLoaded = this.isLoaded || false;
|
|
115
|
+
this.isAsync = this.isAsync || false;
|
|
74
116
|
|
|
75
117
|
this._length = 0;
|
|
76
118
|
|
|
@@ -158,12 +200,13 @@ export default EmberObject.extend(MutableArray, {
|
|
|
158
200
|
// make sure we initialize to the correct state
|
|
159
201
|
// since the user has already accessed
|
|
160
202
|
this.retrieveLatest();
|
|
161
|
-
}
|
|
203
|
+
}
|
|
162
204
|
|
|
163
205
|
// TODO refactor away _hasArrayObservers for tests
|
|
164
206
|
get _hasArrayObservers() {
|
|
207
|
+
// cast necessary because hasArrayObservers is typed as a ComputedProperty<boolean> vs a boolean;
|
|
165
208
|
return this.hasArrayObservers || this.__hasArrayObservers;
|
|
166
|
-
}
|
|
209
|
+
}
|
|
167
210
|
|
|
168
211
|
notify() {
|
|
169
212
|
this._isDirty = true;
|
|
@@ -175,7 +218,7 @@ export default EmberObject.extend(MutableArray, {
|
|
|
175
218
|
this.notifyPropertyChange('firstObject');
|
|
176
219
|
this.notifyPropertyChange('lastObject');
|
|
177
220
|
}
|
|
178
|
-
}
|
|
221
|
+
}
|
|
179
222
|
|
|
180
223
|
get length() {
|
|
181
224
|
if (this._isDirty) {
|
|
@@ -185,11 +228,11 @@ export default EmberObject.extend(MutableArray, {
|
|
|
185
228
|
get(this, '[]');
|
|
186
229
|
|
|
187
230
|
return this._length;
|
|
188
|
-
}
|
|
231
|
+
}
|
|
189
232
|
|
|
190
233
|
set length(value) {
|
|
191
234
|
this._length = value;
|
|
192
|
-
}
|
|
235
|
+
}
|
|
193
236
|
|
|
194
237
|
get links() {
|
|
195
238
|
get(this, '[]');
|
|
@@ -197,10 +240,10 @@ export default EmberObject.extend(MutableArray, {
|
|
|
197
240
|
this.retrieveLatest();
|
|
198
241
|
}
|
|
199
242
|
return this._links;
|
|
200
|
-
}
|
|
243
|
+
}
|
|
201
244
|
set links(v) {
|
|
202
245
|
this._links = v;
|
|
203
|
-
}
|
|
246
|
+
}
|
|
204
247
|
|
|
205
248
|
get meta() {
|
|
206
249
|
get(this, '[]');
|
|
@@ -208,12 +251,12 @@ export default EmberObject.extend(MutableArray, {
|
|
|
208
251
|
this.retrieveLatest();
|
|
209
252
|
}
|
|
210
253
|
return this._meta;
|
|
211
|
-
}
|
|
254
|
+
}
|
|
212
255
|
set meta(v) {
|
|
213
256
|
this._meta = v;
|
|
214
|
-
}
|
|
257
|
+
}
|
|
215
258
|
|
|
216
|
-
objectAt(index) {
|
|
259
|
+
objectAt(index: number): RecordInstance | undefined {
|
|
217
260
|
if (this._isDirty) {
|
|
218
261
|
this.retrieveLatest();
|
|
219
262
|
}
|
|
@@ -223,12 +266,12 @@ export default EmberObject.extend(MutableArray, {
|
|
|
223
266
|
}
|
|
224
267
|
|
|
225
268
|
return internalModel.getRecord();
|
|
226
|
-
}
|
|
269
|
+
}
|
|
227
270
|
|
|
228
|
-
replace(idx, amt, objects) {
|
|
271
|
+
replace(idx: number, amt: number, objects?: RecordInstance[]) {
|
|
229
272
|
assert(`Cannot push mutations to the cache while updating the relationship from cache`, !this._isUpdating);
|
|
230
273
|
this.store._backburner.join(() => {
|
|
231
|
-
let internalModels;
|
|
274
|
+
let internalModels: InternalModel[];
|
|
232
275
|
if (amt > 0) {
|
|
233
276
|
internalModels = this.currentState.slice(idx, idx + amt);
|
|
234
277
|
this.recordData.removeFromHasMany(
|
|
@@ -243,13 +286,13 @@ export default EmberObject.extend(MutableArray, {
|
|
|
243
286
|
);
|
|
244
287
|
this.recordData.addToHasMany(
|
|
245
288
|
this.key,
|
|
246
|
-
objects.map((obj) => recordDataFor(obj)),
|
|
289
|
+
objects.map((obj: RecordInstance) => recordDataFor(obj)),
|
|
247
290
|
idx
|
|
248
291
|
);
|
|
249
292
|
}
|
|
250
293
|
this.notify();
|
|
251
294
|
});
|
|
252
|
-
}
|
|
295
|
+
}
|
|
253
296
|
|
|
254
297
|
retrieveLatest() {
|
|
255
298
|
// It’s possible the parent side of the relationship may have been destroyed by this point
|
|
@@ -260,7 +303,7 @@ export default EmberObject.extend(MutableArray, {
|
|
|
260
303
|
this._isUpdating = true;
|
|
261
304
|
let jsonApi = this.recordData.getHasMany(this.key);
|
|
262
305
|
|
|
263
|
-
let internalModels = [];
|
|
306
|
+
let internalModels: InternalModel[] = [];
|
|
264
307
|
if (jsonApi.data) {
|
|
265
308
|
for (let i = 0; i < jsonApi.data.length; i++) {
|
|
266
309
|
let im = this.store._internalModelForResource(jsonApi.data[i]);
|
|
@@ -298,7 +341,7 @@ export default EmberObject.extend(MutableArray, {
|
|
|
298
341
|
}
|
|
299
342
|
|
|
300
343
|
this._isUpdating = false;
|
|
301
|
-
}
|
|
344
|
+
}
|
|
302
345
|
|
|
303
346
|
/**
|
|
304
347
|
Reloads all of the records in the manyArray. If the manyArray
|
|
@@ -324,8 +367,8 @@ export default EmberObject.extend(MutableArray, {
|
|
|
324
367
|
*/
|
|
325
368
|
reload(options) {
|
|
326
369
|
// TODO this is odd, we don't ask the store for anything else like this?
|
|
327
|
-
return this.
|
|
328
|
-
}
|
|
370
|
+
return this.internalModel.reloadHasMany(this.key, options);
|
|
371
|
+
}
|
|
329
372
|
|
|
330
373
|
/**
|
|
331
374
|
Saves all of the records in the `ManyArray`.
|
|
@@ -347,7 +390,7 @@ export default EmberObject.extend(MutableArray, {
|
|
|
347
390
|
*/
|
|
348
391
|
save() {
|
|
349
392
|
let manyArray = this;
|
|
350
|
-
let promiseLabel = 'DS: ManyArray#save ' + this.type;
|
|
393
|
+
let promiseLabel = 'DS: ManyArray#save ' + this.type.modelName;
|
|
351
394
|
let promise = all(this.invoke('save'), promiseLabel).then(
|
|
352
395
|
() => manyArray,
|
|
353
396
|
null,
|
|
@@ -356,7 +399,7 @@ export default EmberObject.extend(MutableArray, {
|
|
|
356
399
|
|
|
357
400
|
// TODO deprecate returning a promiseArray here
|
|
358
401
|
return PromiseArray.create({ promise });
|
|
359
|
-
}
|
|
402
|
+
}
|
|
360
403
|
|
|
361
404
|
/**
|
|
362
405
|
Create a child record within the owner
|
|
@@ -366,12 +409,12 @@ export default EmberObject.extend(MutableArray, {
|
|
|
366
409
|
@param {Object} hash
|
|
367
410
|
@return {Model} record
|
|
368
411
|
*/
|
|
369
|
-
createRecord(hash) {
|
|
412
|
+
createRecord(hash: CreateRecordProperties): RecordInstance {
|
|
370
413
|
const { store, type } = this;
|
|
371
414
|
|
|
372
|
-
|
|
415
|
+
const record = store.createRecord(type.modelName, hash);
|
|
373
416
|
this.pushObject(record);
|
|
374
417
|
|
|
375
418
|
return record;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { assert } from '@ember/debug';
|
|
2
|
+
import { computed } from '@ember/object';
|
|
3
|
+
import type PromiseProxyMixin from '@ember/object/promise-proxy-mixin';
|
|
4
|
+
import type ObjectProxy from '@ember/object/proxy';
|
|
5
|
+
|
|
6
|
+
import type { InternalModel } from '@ember-data/store/-private';
|
|
7
|
+
import { PromiseObject } from '@ember-data/store/-private';
|
|
8
|
+
import type CoreStore from '@ember-data/store/-private/system/core-store';
|
|
9
|
+
import type { RecordInstance } from '@ember-data/store/-private/ts-interfaces/record-instance';
|
|
10
|
+
import type { Dict } from '@ember-data/store/-private/ts-interfaces/utils';
|
|
11
|
+
|
|
12
|
+
export interface BelongsToProxyMeta {
|
|
13
|
+
key: string;
|
|
14
|
+
store: CoreStore;
|
|
15
|
+
originatingInternalModel: InternalModel;
|
|
16
|
+
modelName: string;
|
|
17
|
+
}
|
|
18
|
+
export interface BelongsToProxyCreateArgs {
|
|
19
|
+
promise: Promise<RecordInstance | null>;
|
|
20
|
+
content?: RecordInstance | null;
|
|
21
|
+
_belongsToState: BelongsToProxyMeta;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface PromiseObjectType<T extends object> extends PromiseProxyMixin<T | null>, ObjectProxy<T> {
|
|
25
|
+
new <T extends object>(...args: unknown[]): PromiseObjectType<T>;
|
|
26
|
+
}
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
28
|
+
declare class PromiseObjectType<T extends object> {}
|
|
29
|
+
|
|
30
|
+
const Extended: PromiseObjectType<RecordInstance> = PromiseObject as unknown as PromiseObjectType<RecordInstance>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
@module @ember-data/model
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
A PromiseBelongsTo is a PromiseObject that also proxies certain method calls
|
|
38
|
+
to the underlying belongsTo model.
|
|
39
|
+
Right now we proxy:
|
|
40
|
+
* `reload()`
|
|
41
|
+
@class PromiseBelongsTo
|
|
42
|
+
@extends PromiseObject
|
|
43
|
+
@private
|
|
44
|
+
*/
|
|
45
|
+
class PromiseBelongsTo extends Extended<RecordInstance> {
|
|
46
|
+
declare _belongsToState: BelongsToProxyMeta;
|
|
47
|
+
// we don't proxy meta because we would need to proxy it to the relationship state container
|
|
48
|
+
// however, meta on relationships does not trigger change notifications.
|
|
49
|
+
// if you need relationship meta, you should do `record.belongsTo(relationshipName).meta()`
|
|
50
|
+
@computed()
|
|
51
|
+
get meta() {
|
|
52
|
+
// eslint-disable-next-line no-constant-condition
|
|
53
|
+
if (1) {
|
|
54
|
+
assert(
|
|
55
|
+
'You attempted to access meta on the promise for the async belongsTo relationship ' +
|
|
56
|
+
`${this.get('_belongsToState').modelName}:${this.get('_belongsToState').key}'.` +
|
|
57
|
+
'\nUse `record.belongsTo(relationshipName).meta()` instead.',
|
|
58
|
+
false
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async reload(options: Dict<unknown>): Promise<this> {
|
|
65
|
+
assert('You are trying to reload an async belongsTo before it has been created', this.content !== undefined);
|
|
66
|
+
let { key, store, originatingInternalModel } = this._belongsToState;
|
|
67
|
+
await store.reloadBelongsTo(this, originatingInternalModel, key, options);
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export default PromiseBelongsTo;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ArrayMixin from '@ember/array';
|
|
2
|
+
import type ArrayProxy from '@ember/array/proxy';
|
|
2
3
|
import { assert } from '@ember/debug';
|
|
3
4
|
import { dependentKeyCompat } from '@ember/object/compat';
|
|
4
5
|
import { tracked } from '@glimmer/tracking';
|
|
@@ -6,6 +7,16 @@ import Ember from 'ember';
|
|
|
6
7
|
|
|
7
8
|
import { resolve } from 'rsvp';
|
|
8
9
|
|
|
10
|
+
import type { ManyArray } from 'ember-data/-private';
|
|
11
|
+
|
|
12
|
+
import type { InternalModel } from '@ember-data/store/-private';
|
|
13
|
+
import type { RecordInstance } from '@ember-data/store/-private/ts-interfaces/record-instance';
|
|
14
|
+
|
|
15
|
+
export interface HasManyProxyCreateArgs {
|
|
16
|
+
promise: Promise<ManyArray>;
|
|
17
|
+
content?: ManyArray;
|
|
18
|
+
}
|
|
19
|
+
|
|
9
20
|
/**
|
|
10
21
|
@module @ember-data/model
|
|
11
22
|
*/
|
|
@@ -31,12 +42,13 @@ import { resolve } from 'rsvp';
|
|
|
31
42
|
@class PromiseManyArray
|
|
32
43
|
@public
|
|
33
44
|
*/
|
|
45
|
+
export default interface PromiseManyArray extends Omit<ArrayProxy<InternalModel, RecordInstance>, 'destroy'> {}
|
|
34
46
|
export default class PromiseManyArray {
|
|
35
|
-
declare promise: Promise<
|
|
47
|
+
declare promise: Promise<ManyArray> | null;
|
|
36
48
|
declare isDestroyed: boolean;
|
|
37
49
|
declare isDestroying: boolean;
|
|
38
50
|
|
|
39
|
-
constructor(promise
|
|
51
|
+
constructor(promise: Promise<ManyArray>, content?: ManyArray) {
|
|
40
52
|
this._update(promise, content);
|
|
41
53
|
this.isDestroyed = false;
|
|
42
54
|
this.isDestroying = false;
|
|
@@ -61,6 +73,9 @@ export default class PromiseManyArray {
|
|
|
61
73
|
*/
|
|
62
74
|
@dependentKeyCompat
|
|
63
75
|
get length(): number {
|
|
76
|
+
// shouldn't be needed, but ends up being needed
|
|
77
|
+
// for computed chains even in 4.x
|
|
78
|
+
this['[]'];
|
|
64
79
|
return this.content ? this.content.length : 0;
|
|
65
80
|
}
|
|
66
81
|
|
|
@@ -201,7 +216,7 @@ export default class PromiseManyArray {
|
|
|
201
216
|
|
|
202
217
|
//---- Our own stuff
|
|
203
218
|
|
|
204
|
-
_update(promise
|
|
219
|
+
_update(promise: Promise<ManyArray>, content?: ManyArray) {
|
|
205
220
|
if (content !== undefined) {
|
|
206
221
|
this.content = content;
|
|
207
222
|
}
|
|
@@ -209,7 +224,7 @@ export default class PromiseManyArray {
|
|
|
209
224
|
this.promise = tapPromise(this, promise);
|
|
210
225
|
}
|
|
211
226
|
|
|
212
|
-
static create({ promise, content }) {
|
|
227
|
+
static create({ promise, content }: HasManyProxyCreateArgs): PromiseManyArray {
|
|
213
228
|
return new this(promise, content);
|
|
214
229
|
}
|
|
215
230
|
|
|
@@ -230,7 +245,7 @@ export default class PromiseManyArray {
|
|
|
230
245
|
}
|
|
231
246
|
}
|
|
232
247
|
|
|
233
|
-
function tapPromise(proxy, promise) {
|
|
248
|
+
function tapPromise(proxy: PromiseManyArray, promise: Promise<ManyArray>) {
|
|
234
249
|
proxy.isPending = true;
|
|
235
250
|
proxy.isSettled = false;
|
|
236
251
|
proxy.isFulfilled = false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ember-data/model",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0-alpha.10",
|
|
4
4
|
"description": "The default blueprint for ember-cli addons.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ember-addon"
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
"test:node": "mocha"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@ember-data/canary-features": "4.
|
|
22
|
-
"@ember-data/private-build-infra": "4.
|
|
23
|
-
"@ember-data/store": "4.
|
|
21
|
+
"@ember-data/canary-features": "4.4.0-alpha.10",
|
|
22
|
+
"@ember-data/private-build-infra": "4.4.0-alpha.10",
|
|
23
|
+
"@ember-data/store": "4.4.0-alpha.10",
|
|
24
24
|
"@ember/edition-utils": "^1.2.0",
|
|
25
25
|
"@ember/string": "^3.0.0",
|
|
26
26
|
"ember-auto-import": "^2.2.4",
|
|
@@ -33,13 +33,13 @@
|
|
|
33
33
|
"inflection": "~1.13.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@ember-data/unpublished-test-infra": "4.
|
|
36
|
+
"@ember-data/unpublished-test-infra": "4.4.0-alpha.10",
|
|
37
37
|
"@ember/optional-features": "^2.0.0",
|
|
38
38
|
"@ember/test-helpers": "^2.6.0",
|
|
39
39
|
"broccoli-asset-rev": "^3.0.0",
|
|
40
|
-
"ember-cli": "~4.
|
|
40
|
+
"ember-cli": "~4.3.0",
|
|
41
41
|
"ember-cli-blueprint-test-helpers": "^0.19.1",
|
|
42
|
-
"ember-cli-dependency-checker": "^3.
|
|
42
|
+
"ember-cli-dependency-checker": "^3.3.1",
|
|
43
43
|
"ember-cli-htmlbars": "^6.0.1",
|
|
44
44
|
"ember-cli-inject-live-reload": "^2.0.2",
|
|
45
45
|
"ember-cli-sri": "^2.1.1",
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { assert } from '@ember/debug';
|
|
2
|
-
import { computed } from '@ember/object';
|
|
3
|
-
|
|
4
|
-
import { PromiseObject } from '@ember-data/store/-private';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
@module @ember-data/model
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
A PromiseBelongsTo is a PromiseObject that also proxies certain method calls
|
|
12
|
-
to the underlying belongsTo model.
|
|
13
|
-
Right now we proxy:
|
|
14
|
-
|
|
15
|
-
* `reload()`
|
|
16
|
-
|
|
17
|
-
@class PromiseBelongsTo
|
|
18
|
-
@extends PromiseObject
|
|
19
|
-
@private
|
|
20
|
-
*/
|
|
21
|
-
const PromiseBelongsTo = PromiseObject.extend({
|
|
22
|
-
// we don't proxy meta because we would need to proxy it to the relationship state container
|
|
23
|
-
// however, meta on relationships does not trigger change notifications.
|
|
24
|
-
// if you need relationship meta, you should do `record.belongsTo(relationshipName).meta()`
|
|
25
|
-
meta: computed(function () {
|
|
26
|
-
assert(
|
|
27
|
-
'You attempted to access meta on the promise for the async belongsTo relationship ' +
|
|
28
|
-
`${this.get('_belongsToState').modelName}:${this.get('_belongsToState').key}'.` +
|
|
29
|
-
'\nUse `record.belongsTo(relationshipName).meta()` instead.',
|
|
30
|
-
false
|
|
31
|
-
);
|
|
32
|
-
}),
|
|
33
|
-
|
|
34
|
-
reload(options) {
|
|
35
|
-
assert('You are trying to reload an async belongsTo before it has been created', this.get('content') !== undefined);
|
|
36
|
-
let { key, store, originatingInternalModel } = this._belongsToState;
|
|
37
|
-
return store.reloadBelongsTo(this, originatingInternalModel, key, options).then(() => this);
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
export default PromiseBelongsTo;
|