@ember-data/store 4.6.1 → 4.7.0
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/-debug/index.js +35 -13
- package/addon/-private/{identifier-cache.ts → caches/identifier-cache.ts} +148 -73
- package/addon/-private/caches/instance-cache.ts +690 -0
- package/addon/-private/{record-data-for.ts → caches/record-data-for.ts} +2 -7
- package/addon/-private/index.ts +44 -24
- package/addon/-private/{model → legacy-model-support}/record-reference.ts +15 -13
- package/addon/-private/{schema-definition-service.ts → legacy-model-support/schema-definition-service.ts} +13 -9
- package/addon/-private/{model → legacy-model-support}/shim-model-class.ts +18 -11
- package/addon/-private/managers/record-array-manager.ts +377 -0
- package/addon/-private/managers/record-data-manager.ts +845 -0
- package/addon/-private/managers/record-data-store-wrapper.ts +421 -0
- package/addon/-private/managers/record-notification-manager.ts +109 -0
- package/addon/-private/network/fetch-manager.ts +567 -0
- package/addon/-private/{finders.js → network/finders.js} +14 -17
- package/addon/-private/{request-cache.ts → network/request-cache.ts} +21 -18
- package/addon/-private/{snapshot-record-array.ts → network/snapshot-record-array.ts} +14 -31
- package/addon/-private/{snapshot.ts → network/snapshot.ts} +40 -49
- package/addon/-private/{promise-proxies.ts → proxies/promise-proxies.ts} +76 -15
- package/addon/-private/{promise-proxy-base.js → proxies/promise-proxy-base.js} +0 -0
- package/addon/-private/record-arrays/identifier-array.ts +924 -0
- package/addon/-private/{core-store.ts → store-service.ts} +574 -215
- package/addon/-private/{coerce-id.ts → utils/coerce-id.ts} +1 -1
- package/addon/-private/{common.js → utils/common.js} +1 -2
- package/addon/-private/utils/construct-resource.ts +2 -2
- package/addon/-private/{identifer-debug-consts.ts → utils/identifer-debug-consts.ts} +0 -0
- package/addon/-private/utils/is-non-empty-string.ts +1 -1
- package/addon/-private/{normalize-model-name.ts → utils/normalize-model-name.ts} +1 -3
- package/addon/-private/utils/promise-record.ts +5 -6
- package/addon/-private/{serializer-response.ts → utils/serializer-response.ts} +2 -2
- package/addon/-private/utils/uuid-polyfill.ts +73 -0
- package/package.json +12 -8
- package/addon/-private/backburner.js +0 -25
- package/addon/-private/errors-utils.js +0 -146
- package/addon/-private/fetch-manager.ts +0 -597
- package/addon/-private/identity-map.ts +0 -54
- package/addon/-private/instance-cache.ts +0 -387
- package/addon/-private/internal-model-factory.ts +0 -359
- package/addon/-private/internal-model-map.ts +0 -121
- package/addon/-private/model/internal-model.ts +0 -602
- package/addon/-private/record-array-manager.ts +0 -444
- package/addon/-private/record-arrays/adapter-populated-record-array.ts +0 -130
- package/addon/-private/record-arrays/record-array.ts +0 -318
- package/addon/-private/record-data-store-wrapper.ts +0 -243
- package/addon/-private/record-notification-manager.ts +0 -73
- package/addon/-private/weak-cache.ts +0 -125
|
@@ -0,0 +1,924 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@module @ember-data/store
|
|
3
|
+
*/
|
|
4
|
+
import { assert, deprecate } from '@ember/debug';
|
|
5
|
+
import { get, set } from '@ember/object';
|
|
6
|
+
import { dependentKeyCompat } from '@ember/object/compat';
|
|
7
|
+
import { compare } from '@ember/utils';
|
|
8
|
+
import { DEBUG } from '@glimmer/env';
|
|
9
|
+
import { tracked } from '@glimmer/tracking';
|
|
10
|
+
import Ember from 'ember';
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
DEPRECATE_A_USAGE,
|
|
14
|
+
DEPRECATE_ARRAY_LIKE,
|
|
15
|
+
DEPRECATE_PROMISE_PROXIES,
|
|
16
|
+
DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS,
|
|
17
|
+
} from '@ember-data/private-build-infra/deprecations';
|
|
18
|
+
import { Links, PaginationLinks } from '@ember-data/types/q/ember-data-json-api';
|
|
19
|
+
import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
|
|
20
|
+
import type { RecordInstance } from '@ember-data/types/q/record-instance';
|
|
21
|
+
import { Dict } from '@ember-data/types/q/utils';
|
|
22
|
+
|
|
23
|
+
import { recordIdentifierFor } from '../caches/instance-cache';
|
|
24
|
+
import type RecordArrayManager from '../managers/record-array-manager';
|
|
25
|
+
import { PromiseArray, promiseArray } from '../proxies/promise-proxies';
|
|
26
|
+
import type Store from '../store-service';
|
|
27
|
+
|
|
28
|
+
type KeyType = string | symbol | number;
|
|
29
|
+
const ARRAY_GETTER_METHODS = new Set<KeyType>([
|
|
30
|
+
Symbol.iterator,
|
|
31
|
+
'concat',
|
|
32
|
+
'entries',
|
|
33
|
+
'every',
|
|
34
|
+
'fill',
|
|
35
|
+
'filter',
|
|
36
|
+
'find',
|
|
37
|
+
'findIndex',
|
|
38
|
+
'flat',
|
|
39
|
+
'flatMap',
|
|
40
|
+
'forEach',
|
|
41
|
+
'includes',
|
|
42
|
+
'indexOf',
|
|
43
|
+
'join',
|
|
44
|
+
'keys',
|
|
45
|
+
'lastIndexOf',
|
|
46
|
+
'map',
|
|
47
|
+
'reduce',
|
|
48
|
+
'reduceRight',
|
|
49
|
+
'slice',
|
|
50
|
+
'some',
|
|
51
|
+
'values',
|
|
52
|
+
]);
|
|
53
|
+
const ARRAY_SETTER_METHODS = new Set<KeyType>(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
|
|
54
|
+
const SYNC_PROPS = new Set<KeyType>(['[]', 'length', 'links', 'meta']);
|
|
55
|
+
function isArrayGetter(prop: KeyType): boolean {
|
|
56
|
+
return ARRAY_GETTER_METHODS.has(prop);
|
|
57
|
+
}
|
|
58
|
+
function isArraySetter(prop: KeyType): boolean {
|
|
59
|
+
return ARRAY_SETTER_METHODS.has(prop);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const IDENTIFIER_ARRAY_TAG = Symbol('#tag');
|
|
63
|
+
export const SOURCE = Symbol('#source');
|
|
64
|
+
export const MUTATE = Symbol('#update');
|
|
65
|
+
|
|
66
|
+
function convertToInt(prop: KeyType): number | null {
|
|
67
|
+
if (typeof prop === 'symbol') return null;
|
|
68
|
+
|
|
69
|
+
const num = Number(prop);
|
|
70
|
+
|
|
71
|
+
if (isNaN(num)) return null;
|
|
72
|
+
|
|
73
|
+
return num % 1 === 0 ? num : null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
class Tag {
|
|
77
|
+
@tracked ref = null;
|
|
78
|
+
shouldReset: boolean = false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
type ProxiedMethod = (...args: unknown[]) => unknown;
|
|
82
|
+
declare global {
|
|
83
|
+
interface ProxyConstructor {
|
|
84
|
+
new <TSource extends object, TTarget extends object>(target: TSource, handler: ProxyHandler<TSource>): TTarget;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export type IdentifierArrayCreateOptions = {
|
|
89
|
+
identifiers: StableRecordIdentifier[];
|
|
90
|
+
type: string;
|
|
91
|
+
store: Store;
|
|
92
|
+
allowMutation: boolean;
|
|
93
|
+
manager: RecordArrayManager;
|
|
94
|
+
links?: Links | PaginationLinks | null;
|
|
95
|
+
meta?: Dict<unknown> | null;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
function deprecateArrayLike(className: string, fnName: string, replName: string) {
|
|
99
|
+
deprecate(
|
|
100
|
+
`The \`${fnName}\` method on the class ${className} is deprecated. Use the native array method \`${replName}\` instead.`,
|
|
101
|
+
false,
|
|
102
|
+
{
|
|
103
|
+
id: 'ember-data:deprecate-array-like',
|
|
104
|
+
until: '5.0',
|
|
105
|
+
since: { enabled: '4.8', available: '4.8' },
|
|
106
|
+
for: 'ember-data',
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface PrivateState {
|
|
112
|
+
links: Links | PaginationLinks | null;
|
|
113
|
+
meta: Dict<unknown> | null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
A record array is an array that contains records of a certain type (or modelName).
|
|
118
|
+
The record array materializes records as needed when they are retrieved for the first
|
|
119
|
+
time. You should not create record arrays yourself. Instead, an instance of
|
|
120
|
+
`RecordArray` or its subclasses will be returned by your application's store
|
|
121
|
+
in response to queries.
|
|
122
|
+
|
|
123
|
+
This class should not be imported and instantiated by consuming applications.
|
|
124
|
+
|
|
125
|
+
@class RecordArray
|
|
126
|
+
@public
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
interface IdentifierArray {
|
|
130
|
+
[MUTATE]?(prop: string, args: unknown[], result?: unknown): void;
|
|
131
|
+
}
|
|
132
|
+
interface IdentifierArray extends Array<RecordInstance> {}
|
|
133
|
+
class IdentifierArray {
|
|
134
|
+
declare DEPRECATED_CLASS_NAME: string;
|
|
135
|
+
/**
|
|
136
|
+
The flag to signal a `RecordArray` is currently loading data.
|
|
137
|
+
Example
|
|
138
|
+
```javascript
|
|
139
|
+
let people = store.peekAll('person');
|
|
140
|
+
people.isUpdating; // false
|
|
141
|
+
people.update();
|
|
142
|
+
people.isUpdating; // true
|
|
143
|
+
```
|
|
144
|
+
@property isUpdating
|
|
145
|
+
@public
|
|
146
|
+
@type Boolean
|
|
147
|
+
*/
|
|
148
|
+
@tracked isUpdating: boolean = false;
|
|
149
|
+
isLoaded: boolean = true;
|
|
150
|
+
isDestroying: boolean = false;
|
|
151
|
+
isDestroyed: boolean = false;
|
|
152
|
+
_updatingPromise: PromiseArray<RecordInstance, IdentifierArray> | Promise<IdentifierArray> | null = null;
|
|
153
|
+
|
|
154
|
+
[IDENTIFIER_ARRAY_TAG] = new Tag();
|
|
155
|
+
[SOURCE]: StableRecordIdentifier[];
|
|
156
|
+
|
|
157
|
+
declare links: Links | PaginationLinks | null;
|
|
158
|
+
declare meta: Dict<unknown> | null;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
The modelClass represented by this record array.
|
|
162
|
+
|
|
163
|
+
@property type
|
|
164
|
+
@public
|
|
165
|
+
@deprecated
|
|
166
|
+
@type {subclass of Model}
|
|
167
|
+
*/
|
|
168
|
+
declare modelName: string;
|
|
169
|
+
/**
|
|
170
|
+
The store that created this record array.
|
|
171
|
+
|
|
172
|
+
@property store
|
|
173
|
+
@private
|
|
174
|
+
@type Store
|
|
175
|
+
*/
|
|
176
|
+
declare store: Store;
|
|
177
|
+
declare _manager: RecordArrayManager;
|
|
178
|
+
|
|
179
|
+
destroy() {
|
|
180
|
+
this.isDestroying = true;
|
|
181
|
+
// changing the reference breaks the Proxy
|
|
182
|
+
// this[SOURCE] = [];
|
|
183
|
+
this[SOURCE].length = 0;
|
|
184
|
+
this[IDENTIFIER_ARRAY_TAG].ref = null;
|
|
185
|
+
this.isDestroyed = true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// length must be on self for proxied methods to work properly
|
|
189
|
+
@dependentKeyCompat
|
|
190
|
+
get length() {
|
|
191
|
+
return this[SOURCE].length;
|
|
192
|
+
}
|
|
193
|
+
set length(value) {
|
|
194
|
+
this[SOURCE].length = value;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
constructor(options: IdentifierArrayCreateOptions) {
|
|
198
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
199
|
+
let self = this;
|
|
200
|
+
this.modelName = options.type;
|
|
201
|
+
this.store = options.store;
|
|
202
|
+
this._manager = options.manager;
|
|
203
|
+
this[SOURCE] = options.identifiers;
|
|
204
|
+
const store = options.store;
|
|
205
|
+
const boundFns = new Map<KeyType, ProxiedMethod>();
|
|
206
|
+
const _TAG = this[IDENTIFIER_ARRAY_TAG];
|
|
207
|
+
const PrivateState: PrivateState = {
|
|
208
|
+
links: options.links || null,
|
|
209
|
+
meta: options.meta || null,
|
|
210
|
+
};
|
|
211
|
+
let transaction: boolean = false;
|
|
212
|
+
|
|
213
|
+
// when a mutation occurs
|
|
214
|
+
// we track all mutations within the call
|
|
215
|
+
// and forward them as one
|
|
216
|
+
|
|
217
|
+
const proxy = new Proxy<StableRecordIdentifier[], RecordInstance[]>(this[SOURCE], {
|
|
218
|
+
get(target: StableRecordIdentifier[], prop: KeyType, receiver: IdentifierArray): unknown {
|
|
219
|
+
let index = convertToInt(prop);
|
|
220
|
+
if (_TAG.shouldReset && (index !== null || SYNC_PROPS.has(prop) || isArrayGetter(prop))) {
|
|
221
|
+
options.manager._syncArray(receiver as unknown as IdentifierArray);
|
|
222
|
+
_TAG.shouldReset = false;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (index !== null) {
|
|
226
|
+
const identifier = target[index];
|
|
227
|
+
if (!transaction) {
|
|
228
|
+
_TAG.ref;
|
|
229
|
+
}
|
|
230
|
+
return identifier && store._instanceCache.getRecord(identifier);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (prop === 'meta') return _TAG.ref, PrivateState.meta;
|
|
234
|
+
if (prop === 'links') return _TAG.ref, PrivateState.links;
|
|
235
|
+
if (prop === '[]') return _TAG.ref, receiver;
|
|
236
|
+
|
|
237
|
+
if (isArrayGetter(prop)) {
|
|
238
|
+
let fn = boundFns.get(prop);
|
|
239
|
+
|
|
240
|
+
if (fn === undefined) {
|
|
241
|
+
fn = function () {
|
|
242
|
+
_TAG.ref;
|
|
243
|
+
// array functions must run through Reflect to work properly
|
|
244
|
+
// binding via other means will not work.
|
|
245
|
+
transaction = true;
|
|
246
|
+
let result = Reflect.apply(target[prop] as ProxiedMethod, receiver, arguments) as unknown;
|
|
247
|
+
transaction = false;
|
|
248
|
+
return result;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
boundFns.set(prop, fn);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return fn;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (isArraySetter(prop)) {
|
|
258
|
+
let fn = boundFns.get(prop);
|
|
259
|
+
|
|
260
|
+
if (fn === undefined) {
|
|
261
|
+
fn = function () {
|
|
262
|
+
// array functions must run through Reflect to work properly
|
|
263
|
+
// binding via other means will not work.
|
|
264
|
+
if (!options.allowMutation) {
|
|
265
|
+
assert(`Mutating this array of records via ${String(prop)} is not allowed.`, options.allowMutation);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const args: unknown[] = Array.prototype.slice.call(arguments);
|
|
269
|
+
assert(`Cannot start a new array transaction while a previous transaction is underway`, !transaction);
|
|
270
|
+
transaction = true;
|
|
271
|
+
let result = Reflect.apply(target[prop] as ProxiedMethod, receiver, args) as unknown;
|
|
272
|
+
self[MUTATE]!(prop as string, args, result);
|
|
273
|
+
_TAG.ref = null;
|
|
274
|
+
// TODO handle cache updates
|
|
275
|
+
transaction = false;
|
|
276
|
+
return result;
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
boundFns.set(prop, fn);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return fn;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (prop in self) {
|
|
286
|
+
if (DEPRECATE_ARRAY_LIKE) {
|
|
287
|
+
if (prop === 'firstObject') {
|
|
288
|
+
deprecateArrayLike(self.DEPRECATED_CLASS_NAME, prop, '[0]');
|
|
289
|
+
return receiver.at(0);
|
|
290
|
+
} else if (prop === 'lastObject') {
|
|
291
|
+
deprecateArrayLike(self.DEPRECATED_CLASS_NAME, prop, 'at(-1)');
|
|
292
|
+
return receiver.at(-1);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
let fn = boundFns.get(prop);
|
|
297
|
+
if (fn) return fn;
|
|
298
|
+
|
|
299
|
+
let outcome: unknown = self[prop];
|
|
300
|
+
|
|
301
|
+
if (typeof outcome === 'function') {
|
|
302
|
+
fn = function () {
|
|
303
|
+
_TAG.ref;
|
|
304
|
+
// array functions must run through Reflect to work properly
|
|
305
|
+
// binding via other means will not work.
|
|
306
|
+
return Reflect.apply(outcome as ProxiedMethod, receiver, arguments) as unknown;
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
boundFns.set(prop, fn);
|
|
310
|
+
return fn;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return _TAG.ref, outcome;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return target[prop];
|
|
317
|
+
},
|
|
318
|
+
|
|
319
|
+
set(target: StableRecordIdentifier[], prop: KeyType, value: unknown /*, receiver */): boolean {
|
|
320
|
+
if (prop === 'length') {
|
|
321
|
+
if (!transaction && value === 0) {
|
|
322
|
+
transaction = true;
|
|
323
|
+
_TAG.ref = null;
|
|
324
|
+
Reflect.set(target, prop, value);
|
|
325
|
+
self[MUTATE]!('length 0', []);
|
|
326
|
+
transaction = false;
|
|
327
|
+
return true;
|
|
328
|
+
} else if (transaction) {
|
|
329
|
+
return Reflect.set(target, prop, value);
|
|
330
|
+
} else {
|
|
331
|
+
assert(`unexpected length set`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (prop === 'links') {
|
|
335
|
+
PrivateState.links = (value || null) as PaginationLinks | Links | null;
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
if (prop === 'meta') {
|
|
339
|
+
PrivateState.meta = (value || null) as Dict<unknown> | null;
|
|
340
|
+
return true;
|
|
341
|
+
}
|
|
342
|
+
let index = convertToInt(prop);
|
|
343
|
+
|
|
344
|
+
if (index === null || index > target.length) {
|
|
345
|
+
if (prop in self) {
|
|
346
|
+
self[prop] = value;
|
|
347
|
+
return true;
|
|
348
|
+
}
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (!options.allowMutation) {
|
|
353
|
+
assert(`Mutating ${String(prop)} on this RecordArray is not allowed.`, options.allowMutation);
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
let original: StableRecordIdentifier | undefined = target[index];
|
|
358
|
+
let newIdentifier = extractIdentifierFromRecord(value as RecordInstance);
|
|
359
|
+
(target as unknown as Record<KeyType, unknown>)[index] = newIdentifier;
|
|
360
|
+
if (!transaction) {
|
|
361
|
+
self[MUTATE]!('replace cell', [index, original, newIdentifier]);
|
|
362
|
+
_TAG.ref = null;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return true;
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
deleteProperty(target: StableRecordIdentifier[], prop: string | symbol): boolean {
|
|
369
|
+
assert(`Deleting keys on managed arrays is disallowed`, transaction);
|
|
370
|
+
if (!transaction) {
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
return Reflect.deleteProperty(target, prop);
|
|
374
|
+
},
|
|
375
|
+
|
|
376
|
+
getPrototypeOf() {
|
|
377
|
+
return IdentifierArray.prototype;
|
|
378
|
+
},
|
|
379
|
+
}) as IdentifierArray;
|
|
380
|
+
|
|
381
|
+
if (DEPRECATE_A_USAGE) {
|
|
382
|
+
const meta = Ember.meta(this);
|
|
383
|
+
meta.hasMixin = (mixin: Object) => {
|
|
384
|
+
deprecate(`Do not call A() on EmberData RecordArrays`, false, {
|
|
385
|
+
id: 'ember-data:no-a-with-array-like',
|
|
386
|
+
until: '5.0',
|
|
387
|
+
since: { enabled: '4.8', available: '4.8' },
|
|
388
|
+
for: 'ember-data',
|
|
389
|
+
});
|
|
390
|
+
// @ts-expect-error ArrayMixin is more than a type
|
|
391
|
+
if (mixin === NativeArray || mixin === ArrayMixin) {
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
return false;
|
|
395
|
+
};
|
|
396
|
+
} else if (DEBUG) {
|
|
397
|
+
const meta = Ember.meta(this);
|
|
398
|
+
meta.hasMixin = (mixin: Object) => {
|
|
399
|
+
assert(`Do not call A() on EmberData RecordArrays`);
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return proxy;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
Used to get the latest version of all of the records in this array
|
|
408
|
+
from the adapter.
|
|
409
|
+
|
|
410
|
+
Example
|
|
411
|
+
|
|
412
|
+
```javascript
|
|
413
|
+
let people = store.peekAll('person');
|
|
414
|
+
people.isUpdating; // false
|
|
415
|
+
|
|
416
|
+
people.update().then(function() {
|
|
417
|
+
people.isUpdating; // false
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
people.isUpdating; // true
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
@method update
|
|
424
|
+
@public
|
|
425
|
+
*/
|
|
426
|
+
update(): PromiseArray<RecordInstance, IdentifierArray> | Promise<IdentifierArray> {
|
|
427
|
+
if (this.isUpdating) {
|
|
428
|
+
return this._updatingPromise!;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
this.isUpdating = true;
|
|
432
|
+
|
|
433
|
+
let updatingPromise = this._update();
|
|
434
|
+
updatingPromise.finally(() => {
|
|
435
|
+
this._updatingPromise = null;
|
|
436
|
+
if (this.isDestroying || this.isDestroyed) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
this.isUpdating = false;
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
this._updatingPromise = updatingPromise;
|
|
443
|
+
|
|
444
|
+
return updatingPromise;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/*
|
|
448
|
+
Update this RecordArray and return a promise which resolves once the update
|
|
449
|
+
is finished.
|
|
450
|
+
*/
|
|
451
|
+
_update(): PromiseArray<RecordInstance, IdentifierArray> | Promise<IdentifierArray> {
|
|
452
|
+
return this.store.findAll(this.modelName, { reload: true });
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// TODO deprecate
|
|
456
|
+
/**
|
|
457
|
+
Saves all of the records in the `RecordArray`.
|
|
458
|
+
|
|
459
|
+
Example
|
|
460
|
+
|
|
461
|
+
```javascript
|
|
462
|
+
let messages = store.peekAll('message');
|
|
463
|
+
messages.forEach(function(message) {
|
|
464
|
+
message.hasBeenSeen = true;
|
|
465
|
+
});
|
|
466
|
+
messages.save();
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
@method save
|
|
470
|
+
@public
|
|
471
|
+
@return {PromiseArray} promise
|
|
472
|
+
*/
|
|
473
|
+
save(): PromiseArray<RecordInstance, IdentifierArray> | Promise<IdentifierArray> {
|
|
474
|
+
let promise = Promise.all(this.map((record) => this.store.saveRecord(record))).then(() => this);
|
|
475
|
+
|
|
476
|
+
if (DEPRECATE_PROMISE_PROXIES) {
|
|
477
|
+
return promiseArray<RecordInstance, IdentifierArray>(promise);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return promise;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
export default IdentifierArray;
|
|
485
|
+
|
|
486
|
+
if (DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS) {
|
|
487
|
+
Object.defineProperty(IdentifierArray.prototype, 'type', {
|
|
488
|
+
get() {
|
|
489
|
+
deprecate(
|
|
490
|
+
`Using RecordArray.type to access the ModelClass for a record is deprecated. Use store.modelFor(<modelName>) instead.`,
|
|
491
|
+
false,
|
|
492
|
+
{
|
|
493
|
+
id: 'ember-data:deprecate-snapshot-model-class-access',
|
|
494
|
+
until: '5.0',
|
|
495
|
+
for: 'ember-data',
|
|
496
|
+
since: { available: '4.5.0', enabled: '4.5.0' },
|
|
497
|
+
}
|
|
498
|
+
);
|
|
499
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
500
|
+
if (!this.modelName) {
|
|
501
|
+
return null;
|
|
502
|
+
}
|
|
503
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
|
504
|
+
return this.store.modelFor(this.modelName);
|
|
505
|
+
},
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
export type CollectionCreateOptions = IdentifierArrayCreateOptions & {
|
|
510
|
+
query: Dict<unknown> | null;
|
|
511
|
+
isLoaded: boolean;
|
|
512
|
+
};
|
|
513
|
+
export class Collection extends IdentifierArray {
|
|
514
|
+
query: Dict<unknown> | null = null;
|
|
515
|
+
|
|
516
|
+
constructor(options: CollectionCreateOptions) {
|
|
517
|
+
super(options as IdentifierArrayCreateOptions);
|
|
518
|
+
this.query = options.query || null;
|
|
519
|
+
this.isLoaded = options.isLoaded || false;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
_update(): PromiseArray<RecordInstance, Collection> | Promise<Collection> {
|
|
523
|
+
const { store, query } = this;
|
|
524
|
+
|
|
525
|
+
// TODO save options from initial request?
|
|
526
|
+
const promise = store.query(this.modelName, query, { _recordArray: this });
|
|
527
|
+
|
|
528
|
+
if (DEPRECATE_PROMISE_PROXIES) {
|
|
529
|
+
return promiseArray(promise);
|
|
530
|
+
}
|
|
531
|
+
return promise;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
destroy() {
|
|
535
|
+
super.destroy();
|
|
536
|
+
this._manager._managed.delete(this);
|
|
537
|
+
this._manager._pending.delete(this);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
// trick the proxy "in" check
|
|
541
|
+
Collection.prototype.query = null;
|
|
542
|
+
|
|
543
|
+
// Ensure instanceof works correctly
|
|
544
|
+
// Object.setPrototypeOf(IdentifierArray.prototype, Array.prototype);
|
|
545
|
+
|
|
546
|
+
if (DEPRECATE_ARRAY_LIKE) {
|
|
547
|
+
IdentifierArray.prototype.DEPRECATED_CLASS_NAME = 'RecordArray';
|
|
548
|
+
Collection.prototype.DEPRECATED_CLASS_NAME = 'RecordArray';
|
|
549
|
+
const EmberObjectMethods = [
|
|
550
|
+
'addObserver',
|
|
551
|
+
'cacheFor',
|
|
552
|
+
'decrementProperty',
|
|
553
|
+
'get',
|
|
554
|
+
'getProperties',
|
|
555
|
+
'incrementProperty',
|
|
556
|
+
'notifyPropertyChange',
|
|
557
|
+
'removeObserver',
|
|
558
|
+
'set',
|
|
559
|
+
'setProperties',
|
|
560
|
+
'toggleProperty',
|
|
561
|
+
];
|
|
562
|
+
EmberObjectMethods.forEach((method) => {
|
|
563
|
+
IdentifierArray.prototype[method] = function delegatedMethod(...args: unknown[]): unknown {
|
|
564
|
+
deprecate(
|
|
565
|
+
`The EmberObject ${method} method on the class ${this.DEPRECATED_CLASS_NAME} is deprecated. Use dot-notation javascript get/set access instead.`,
|
|
566
|
+
false,
|
|
567
|
+
{
|
|
568
|
+
id: 'ember-data:deprecate-array-like',
|
|
569
|
+
until: '5.0',
|
|
570
|
+
since: { enabled: '4.8', available: '4.8' },
|
|
571
|
+
for: 'ember-data',
|
|
572
|
+
}
|
|
573
|
+
);
|
|
574
|
+
return (Ember[method] as (...args: unknown[]) => unknown)(this, ...args);
|
|
575
|
+
};
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
IdentifierArray.prototype.addObject = function (obj: RecordInstance) {
|
|
579
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'addObject', 'push');
|
|
580
|
+
let index = this.indexOf(obj);
|
|
581
|
+
if (index === -1) {
|
|
582
|
+
this.push(obj);
|
|
583
|
+
}
|
|
584
|
+
return this;
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
IdentifierArray.prototype.addObjects = function (objs: RecordInstance[]) {
|
|
588
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'addObjects', 'push');
|
|
589
|
+
objs.forEach((obj: RecordInstance) => {
|
|
590
|
+
let index = this.indexOf(obj);
|
|
591
|
+
if (index === -1) {
|
|
592
|
+
this.push(obj);
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
return this;
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
IdentifierArray.prototype.popObject = function () {
|
|
599
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'popObject', 'pop');
|
|
600
|
+
return this.pop() as RecordInstance;
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
IdentifierArray.prototype.pushObject = function (obj: RecordInstance) {
|
|
604
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'pushObject', 'push');
|
|
605
|
+
this.push(obj);
|
|
606
|
+
return obj;
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
IdentifierArray.prototype.pushObjects = function (objs: RecordInstance[]) {
|
|
610
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'pushObjects', 'push');
|
|
611
|
+
this.push(...objs);
|
|
612
|
+
return this;
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
IdentifierArray.prototype.shiftObject = function () {
|
|
616
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'shiftObject', 'shift');
|
|
617
|
+
return this.shift()!;
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
IdentifierArray.prototype.unshiftObject = function (obj: RecordInstance) {
|
|
621
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'unshiftObject', 'unshift');
|
|
622
|
+
this.unshift(obj);
|
|
623
|
+
return obj;
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
IdentifierArray.prototype.unshiftObjects = function (objs: RecordInstance[]) {
|
|
627
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'unshiftObjects', 'unshift');
|
|
628
|
+
this.unshift(...objs);
|
|
629
|
+
return this;
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
IdentifierArray.prototype.objectAt = function (index: number) {
|
|
633
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'objectAt', 'at');
|
|
634
|
+
return this.at(index);
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
IdentifierArray.prototype.objectsAt = function (indeces: number[]) {
|
|
638
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'objectsAt', 'at');
|
|
639
|
+
return indeces.map((index) => this.at(index)!);
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
IdentifierArray.prototype.removeAt = function (index: number) {
|
|
643
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'removeAt', 'splice');
|
|
644
|
+
this.splice(index, 1);
|
|
645
|
+
return this;
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
IdentifierArray.prototype.insertAt = function (index: number, obj: RecordInstance) {
|
|
649
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'insertAt', 'splice');
|
|
650
|
+
this.splice(index, 0, obj);
|
|
651
|
+
return this;
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
IdentifierArray.prototype.removeObject = function (obj: RecordInstance) {
|
|
655
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'removeObject', 'splice');
|
|
656
|
+
this.splice(this.indexOf(obj), 1);
|
|
657
|
+
return this;
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
IdentifierArray.prototype.removeObjects = function (objs: RecordInstance[]) {
|
|
661
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'removeObjects', 'splice');
|
|
662
|
+
objs.forEach((obj) => this.splice(this.indexOf(obj), 1));
|
|
663
|
+
return this;
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
IdentifierArray.prototype.toArray = function () {
|
|
667
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'unshiftObjects', 'unshift');
|
|
668
|
+
return this.slice();
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
IdentifierArray.prototype.replace = function (idx: number, amt: number, objects?: RecordInstance[]) {
|
|
672
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'replace', 'splice');
|
|
673
|
+
if (objects) {
|
|
674
|
+
this.splice(idx, amt, ...objects);
|
|
675
|
+
} else {
|
|
676
|
+
this.splice(idx, amt);
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
IdentifierArray.prototype.clear = function () {
|
|
681
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'clear', 'length = 0');
|
|
682
|
+
this.splice(0, this.length);
|
|
683
|
+
return this;
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
IdentifierArray.prototype.setObjects = function (objects: RecordInstance[]) {
|
|
687
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'clear', 'length = 0');
|
|
688
|
+
assert(
|
|
689
|
+
`${this.DEPRECATED_CLASS_NAME}.setObjects expects to receive an array as its argument`,
|
|
690
|
+
Array.isArray(objects)
|
|
691
|
+
);
|
|
692
|
+
this.splice(0, this.length);
|
|
693
|
+
this.push(...objects);
|
|
694
|
+
return this;
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
IdentifierArray.prototype.reverseObjects = function () {
|
|
698
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'reverseObjects', 'reverse');
|
|
699
|
+
this.reverse();
|
|
700
|
+
return this;
|
|
701
|
+
};
|
|
702
|
+
|
|
703
|
+
IdentifierArray.prototype.compact = function () {
|
|
704
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'compact', 'filter');
|
|
705
|
+
return this.filter((v) => v !== null && v !== undefined);
|
|
706
|
+
};
|
|
707
|
+
|
|
708
|
+
IdentifierArray.prototype.any = function (callback, target) {
|
|
709
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'any', 'some');
|
|
710
|
+
return this.some(callback, target);
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
IdentifierArray.prototype.isAny = function (prop, value) {
|
|
714
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'isAny', 'some');
|
|
715
|
+
let hasValue = arguments.length === 2;
|
|
716
|
+
return this.some((v) => (hasValue ? v[prop] === value : v[prop] === true));
|
|
717
|
+
};
|
|
718
|
+
|
|
719
|
+
IdentifierArray.prototype.isEvery = function (prop, value) {
|
|
720
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'isEvery', 'every');
|
|
721
|
+
let hasValue = arguments.length === 2;
|
|
722
|
+
return this.every((v) => (hasValue ? v[prop] === value : v[prop] === true));
|
|
723
|
+
};
|
|
724
|
+
|
|
725
|
+
IdentifierArray.prototype.getEach = function (key: string) {
|
|
726
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'getEach', 'map');
|
|
727
|
+
return this.map((value) => get(value, key));
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
IdentifierArray.prototype.mapBy = function (key: string) {
|
|
731
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'mapBy', 'map');
|
|
732
|
+
return this.map((value) => get(value, key));
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
IdentifierArray.prototype.findBy = function (key: string, value?: unknown) {
|
|
736
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'findBy', 'find');
|
|
737
|
+
if (arguments.length === 2) {
|
|
738
|
+
return this.find((val) => {
|
|
739
|
+
return get(val, key) === value;
|
|
740
|
+
});
|
|
741
|
+
} else {
|
|
742
|
+
return this.find((val) => Boolean(get(val, key)));
|
|
743
|
+
}
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
IdentifierArray.prototype.filterBy = function (key: string, value?: unknown) {
|
|
747
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'filterBy', 'filter');
|
|
748
|
+
if (arguments.length === 2) {
|
|
749
|
+
return this.filter((value) => {
|
|
750
|
+
return Boolean(get(value, key));
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
return this.filter((value) => {
|
|
754
|
+
return Boolean(get(value, key));
|
|
755
|
+
});
|
|
756
|
+
};
|
|
757
|
+
|
|
758
|
+
IdentifierArray.prototype.sortBy = function (...sortKeys: string[]) {
|
|
759
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'sortBy', '.slice().sort');
|
|
760
|
+
return this.slice().sort((a, b) => {
|
|
761
|
+
for (let i = 0; i < sortKeys.length; i++) {
|
|
762
|
+
let key = sortKeys[i];
|
|
763
|
+
let propA = get(a, key);
|
|
764
|
+
let propB = get(b, key);
|
|
765
|
+
// return 1 or -1 else continue to the next sortKey
|
|
766
|
+
let compareValue = compare(propA, propB);
|
|
767
|
+
|
|
768
|
+
if (compareValue) {
|
|
769
|
+
return compareValue;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return 0;
|
|
773
|
+
});
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
// @ts-expect-error
|
|
777
|
+
IdentifierArray.prototype.invoke = function (key: string, ...args: unknown[]) {
|
|
778
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'invoke', 'forEach');
|
|
779
|
+
return this.map((value) => (value[key] as (...args: unknown[]) => unknown)(...args));
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
// @ts-expect-error
|
|
783
|
+
IdentifierArray.prototype.addArrayObserver = function () {
|
|
784
|
+
deprecateArrayLike(
|
|
785
|
+
this.DEPRECATED_CLASS_NAME,
|
|
786
|
+
'addArrayObserver',
|
|
787
|
+
'derived state or reacting at the change source'
|
|
788
|
+
);
|
|
789
|
+
};
|
|
790
|
+
|
|
791
|
+
// @ts-expect-error
|
|
792
|
+
IdentifierArray.prototype.removeArrayObserver = function () {
|
|
793
|
+
deprecateArrayLike(
|
|
794
|
+
this.DEPRECATED_CLASS_NAME,
|
|
795
|
+
'removeArrayObserver',
|
|
796
|
+
'derived state or reacting at the change source'
|
|
797
|
+
);
|
|
798
|
+
};
|
|
799
|
+
|
|
800
|
+
// @ts-expect-error
|
|
801
|
+
IdentifierArray.prototype.arrayContentWillChange = function () {
|
|
802
|
+
deprecateArrayLike(
|
|
803
|
+
this.DEPRECATED_CLASS_NAME,
|
|
804
|
+
'arrayContentWillChange',
|
|
805
|
+
'derived state or reacting at the change source'
|
|
806
|
+
);
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
// @ts-expect-error
|
|
810
|
+
IdentifierArray.prototype.arrayContentDidChange = function () {
|
|
811
|
+
deprecateArrayLike(
|
|
812
|
+
this.DEPRECATED_CLASS_NAME,
|
|
813
|
+
'arrayContentDidChange',
|
|
814
|
+
'derived state or reacting at the change source.'
|
|
815
|
+
);
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
// @ts-expect-error
|
|
819
|
+
IdentifierArray.prototype.reject = function (key: string, value?: unknown) {
|
|
820
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'reject', 'filter');
|
|
821
|
+
if (arguments.length === 2) {
|
|
822
|
+
return this.filter((value) => {
|
|
823
|
+
return !get(value, key);
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
return this.filter((value) => {
|
|
827
|
+
return !get(value, key);
|
|
828
|
+
});
|
|
829
|
+
};
|
|
830
|
+
|
|
831
|
+
IdentifierArray.prototype.rejectBy = function (key: string, value?: unknown) {
|
|
832
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'rejectBy', 'filter');
|
|
833
|
+
if (arguments.length === 2) {
|
|
834
|
+
return this.filter((value) => {
|
|
835
|
+
return !get(value, key);
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
return this.filter((value) => {
|
|
839
|
+
return !get(value, key);
|
|
840
|
+
});
|
|
841
|
+
};
|
|
842
|
+
|
|
843
|
+
IdentifierArray.prototype.setEach = function (key: string, value: unknown) {
|
|
844
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'setEach', 'forEach');
|
|
845
|
+
this.forEach((item) => set(item, key, value));
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
IdentifierArray.prototype.uniq = function () {
|
|
849
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'uniq', 'filter');
|
|
850
|
+
// all current managed arrays are already enforced as unique
|
|
851
|
+
return this.slice();
|
|
852
|
+
};
|
|
853
|
+
|
|
854
|
+
// @ts-expect-error
|
|
855
|
+
IdentifierArray.prototype.uniqBy = function (key: string) {
|
|
856
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'uniqBy', 'filter');
|
|
857
|
+
// all current managed arrays are already enforced as unique
|
|
858
|
+
let seen = new Set();
|
|
859
|
+
let result: RecordInstance[] = [];
|
|
860
|
+
this.forEach((item) => {
|
|
861
|
+
let value = get(item, key);
|
|
862
|
+
if (seen.has(value)) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
seen.add(value);
|
|
866
|
+
result.push(item);
|
|
867
|
+
});
|
|
868
|
+
return result;
|
|
869
|
+
};
|
|
870
|
+
|
|
871
|
+
IdentifierArray.prototype.without = function (value: RecordInstance) {
|
|
872
|
+
deprecateArrayLike(this.DEPRECATED_CLASS_NAME, 'without', 'slice');
|
|
873
|
+
const newArr = this.slice();
|
|
874
|
+
const index = this.indexOf(value);
|
|
875
|
+
if (index !== -1) {
|
|
876
|
+
newArr.splice(index, 1);
|
|
877
|
+
}
|
|
878
|
+
return newArr;
|
|
879
|
+
};
|
|
880
|
+
|
|
881
|
+
// @ts-expect-error
|
|
882
|
+
IdentifierArray.prototype.firstObject = null;
|
|
883
|
+
// @ts-expect-error
|
|
884
|
+
IdentifierArray.prototype.lastObject = null;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
type PromiseProxyRecord = { then(): void; content: RecordInstance | null | undefined };
|
|
888
|
+
|
|
889
|
+
function assertRecordPassedToHasMany(record: RecordInstance | PromiseProxyRecord) {
|
|
890
|
+
assert(
|
|
891
|
+
`All elements of a hasMany relationship must be instances of Model, you passed $${typeof record}`,
|
|
892
|
+
(function () {
|
|
893
|
+
try {
|
|
894
|
+
recordIdentifierFor(record);
|
|
895
|
+
return true;
|
|
896
|
+
} catch {
|
|
897
|
+
return false;
|
|
898
|
+
}
|
|
899
|
+
})()
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
function extractIdentifierFromRecord(recordOrPromiseRecord: PromiseProxyRecord | RecordInstance | null) {
|
|
904
|
+
if (!recordOrPromiseRecord) {
|
|
905
|
+
return null;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
if (isPromiseRecord(recordOrPromiseRecord)) {
|
|
909
|
+
let content = recordOrPromiseRecord.content;
|
|
910
|
+
assert(
|
|
911
|
+
'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo relationship.',
|
|
912
|
+
content !== undefined && content !== null
|
|
913
|
+
);
|
|
914
|
+
assertRecordPassedToHasMany(content);
|
|
915
|
+
return recordIdentifierFor(content);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
assertRecordPassedToHasMany(recordOrPromiseRecord);
|
|
919
|
+
return recordIdentifierFor(recordOrPromiseRecord);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
function isPromiseRecord(record: PromiseProxyRecord | RecordInstance): record is PromiseProxyRecord {
|
|
923
|
+
return !!record.then;
|
|
924
|
+
}
|