@warp-drive/core 5.7.0-alpha.13 → 5.7.0-alpha.14
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/declarations/reactive/-private/symbols.d.ts +0 -1
- package/declarations/request/-private/fetch.d.ts +2 -2
- package/declarations/request/-private/utils.d.ts +44 -2
- package/declarations/store/-private/cache-handler/types.d.ts +1 -1
- package/declarations/store/-private/managers/notification-manager.d.ts +4 -7
- package/declarations/store/-private/managers/record-array-manager.d.ts +72 -21
- package/declarations/store/-private/new-core-tmp/reactivity/signal.d.ts +1 -0
- package/declarations/store/-private/record-arrays/-utils.d.ts +82 -0
- package/declarations/store/-private/record-arrays/legacy-live-array.d.ts +89 -0
- package/declarations/store/-private/record-arrays/{many-array.d.ts → legacy-many-array.d.ts} +43 -101
- package/declarations/store/-private/record-arrays/legacy-query.d.ts +103 -0
- package/declarations/store/-private/record-arrays/resource-array.d.ts +82 -0
- package/declarations/store/-private/store-service.d.ts +3 -3
- package/declarations/store/-private.d.ts +4 -2
- package/declarations/store/deprecated/store.d.ts +8 -9
- package/declarations/types/-private.d.ts +1 -1
- package/declarations/types/cache/operations.d.ts +97 -14
- package/declarations/types/request.d.ts +21 -0
- package/declarations/types/schema/fields.d.ts +1 -1
- package/dist/{context-COmAnXUQ.js → context-kQXhkeBj.js} +13 -0
- package/dist/graph/-private.js +4 -4
- package/dist/index.js +6 -2
- package/dist/reactive/-private.js +1 -1
- package/dist/reactive.js +3 -3
- package/dist/{request-state-BWYju5O9.js → request-state-CCrTjb0Z.js} +861 -799
- package/dist/request.js +1 -1
- package/dist/store/-private.js +1 -1
- package/dist/store.js +2 -1
- package/dist/{symbols-BoONANuz.js → symbols-C5p2hcy9.js} +0 -1
- package/dist/types/-private.js +1 -1
- package/dist/types/request.js +27 -0
- package/dist/types/schema/fields.js +2 -0
- package/package.json +3 -3
- package/declarations/store/-private/record-arrays/identifier-array.d.ts +0 -147
|
@@ -5,10 +5,10 @@ import { setLogging, getRuntimeConfig } from './types/runtime.js';
|
|
|
5
5
|
import { getOrSetGlobal, peekTransient, setTransient } from './types/-private.js';
|
|
6
6
|
import { CACHE_OWNER, DEBUG_STALE_CACHE_OWNER, DEBUG_IDENTIFIER_BUCKET, DEBUG_CLIENT_ORIGINATED } from './types/identifier.js';
|
|
7
7
|
import { dasherize } from './utils/string.js';
|
|
8
|
+
import { S as SOURCE, C as Context, D as Destroy, a as Checkout } from "./symbols-C5p2hcy9.js";
|
|
8
9
|
import { a as createSignal, b as consumeSignal, n as notifySignal, c as createMemo, A as ARRAY_SIGNAL, O as OBJECT_SIGNAL, d as willSyncFlushWatchers } from "./configure-B48bFHOl.js";
|
|
9
|
-
import { g as getPromiseResult, s as setPromiseResult } from "./context-
|
|
10
|
+
import { g as getPromiseResult, s as setPromiseResult } from "./context-kQXhkeBj.js";
|
|
10
11
|
import { RecordStore } from './types/symbols.js';
|
|
11
|
-
import { S as SOURCE$1, C as Context, D as Destroy, a as Checkout } from "./symbols-BoONANuz.js";
|
|
12
12
|
function coerceId(id) {
|
|
13
13
|
if (macroCondition(getGlobalConfig().WarpDrive.deprecations.DEPRECATE_NON_STRICT_ID)) {
|
|
14
14
|
let normalized;
|
|
@@ -1001,7 +1001,7 @@ const Signals = getOrSetGlobal('Signals', Symbol('Signals'));
|
|
|
1001
1001
|
* @internal
|
|
1002
1002
|
*/
|
|
1003
1003
|
function withSignalStore(obj) {
|
|
1004
|
-
if (obj[Signals]
|
|
1004
|
+
if (!obj[Signals]) {
|
|
1005
1005
|
initializeSignalStore(obj);
|
|
1006
1006
|
}
|
|
1007
1007
|
return obj[Signals];
|
|
@@ -1021,7 +1021,7 @@ function initializeSignalStore(obj) {
|
|
|
1021
1021
|
if (!test) {
|
|
1022
1022
|
throw new Error(`Signal store already exists on object`);
|
|
1023
1023
|
}
|
|
1024
|
-
})(obj[Signals]
|
|
1024
|
+
})(!obj[Signals]) : {};
|
|
1025
1025
|
obj[Signals] = new Map();
|
|
1026
1026
|
}
|
|
1027
1027
|
function createInternalSignal(signals, obj, key, initialValue) {
|
|
@@ -1437,11 +1437,11 @@ defineGate(ReactiveDocument.prototype, 'data', {
|
|
|
1437
1437
|
})(doc) : {};
|
|
1438
1438
|
const data = 'data' in doc ? doc.data : undefined;
|
|
1439
1439
|
if (Array.isArray(data)) {
|
|
1440
|
-
return this._store.recordArrayManager.getCollection({
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1440
|
+
return identifier ? this._store.recordArrayManager.getCollection({
|
|
1441
|
+
source: data.slice(),
|
|
1442
|
+
requestKey: identifier
|
|
1443
|
+
}) : this._store.recordArrayManager.getCollection({
|
|
1444
|
+
source: data.slice()
|
|
1445
1445
|
});
|
|
1446
1446
|
} else if (data) {
|
|
1447
1447
|
return this._store.peekRecord(data);
|
|
@@ -1637,7 +1637,7 @@ function performArrayExtensionGet(receiver, extensions, signals, prop, _SIGNAL,
|
|
|
1637
1637
|
}
|
|
1638
1638
|
const ARRAY_GETTER_METHODS$1 = new Set([Symbol.iterator, 'concat', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'flat', 'flatMap', 'forEach', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'map', 'reduce', 'reduceRight', 'slice', 'some', 'values']);
|
|
1639
1639
|
// const ARRAY_SETTER_METHODS = new Set<KeyType>(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
|
|
1640
|
-
const SYNC_PROPS
|
|
1640
|
+
const SYNC_PROPS = new Set(['[]', 'length']);
|
|
1641
1641
|
function isArrayGetter$1(prop) {
|
|
1642
1642
|
return ARRAY_GETTER_METHODS$1.has(prop);
|
|
1643
1643
|
}
|
|
@@ -1684,7 +1684,7 @@ class ManagedArray {
|
|
|
1684
1684
|
constructor(context, owner, data) {
|
|
1685
1685
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1686
1686
|
const self = this;
|
|
1687
|
-
this[SOURCE
|
|
1687
|
+
this[SOURCE] = data?.slice();
|
|
1688
1688
|
const IS_EDITABLE = context.editable ?? false;
|
|
1689
1689
|
this[Context] = context;
|
|
1690
1690
|
const schema = context.store.schema;
|
|
@@ -1711,7 +1711,7 @@ class ManagedArray {
|
|
|
1711
1711
|
Map;
|
|
1712
1712
|
const ManagedRecordRefs = field.kind === 'schema-array' ? new RefStorage() : null;
|
|
1713
1713
|
const extensions = context.legacy ? schema.CAUTION_MEGA_DANGER_ZONE_arrayExtensions(field) : null;
|
|
1714
|
-
const proxy = new Proxy(this[SOURCE
|
|
1714
|
+
const proxy = new Proxy(this[SOURCE], {
|
|
1715
1715
|
get(target, prop, receiver) {
|
|
1716
1716
|
if (prop === ARRAY_SIGNAL) {
|
|
1717
1717
|
return _SIGNAL;
|
|
@@ -1723,12 +1723,12 @@ class ManagedArray {
|
|
|
1723
1723
|
return self.owner;
|
|
1724
1724
|
}
|
|
1725
1725
|
const index = convertToInt$1(prop);
|
|
1726
|
-
if (_SIGNAL.isStale && (index !== null || SYNC_PROPS
|
|
1726
|
+
if (_SIGNAL.isStale && (index !== null || SYNC_PROPS.has(prop) || isArrayGetter$1(prop))) {
|
|
1727
1727
|
_SIGNAL.isStale = false;
|
|
1728
1728
|
const newData = cache.getAttr(context.resourceKey, context.path);
|
|
1729
|
-
if (newData && newData !== self[SOURCE
|
|
1730
|
-
self[SOURCE
|
|
1731
|
-
self[SOURCE
|
|
1729
|
+
if (newData && newData !== self[SOURCE]) {
|
|
1730
|
+
self[SOURCE].length = 0;
|
|
1731
|
+
self[SOURCE].push(...newData);
|
|
1732
1732
|
}
|
|
1733
1733
|
}
|
|
1734
1734
|
if (prop === 'length') {
|
|
@@ -1834,7 +1834,7 @@ class ManagedArray {
|
|
|
1834
1834
|
}
|
|
1835
1835
|
schemaObjectKeyValue = KeyMode === '@identity' ? rawValue : KeyMode === '@index' ? index : rawValue[KeyMode];
|
|
1836
1836
|
}
|
|
1837
|
-
if (!schemaObjectKeyValue) {
|
|
1837
|
+
if (!schemaObjectKeyValue && schemaObjectKeyValue !== 0) {
|
|
1838
1838
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1839
1839
|
{
|
|
1840
1840
|
throw new Error(`Unexpected out of bounds access on SchemaArray`);
|
|
@@ -1952,17 +1952,17 @@ class ManagedArray {
|
|
|
1952
1952
|
const reflect = Reflect.set(target, prop, value, receiver);
|
|
1953
1953
|
if (reflect) {
|
|
1954
1954
|
if (!field.type) {
|
|
1955
|
-
cache.setAttr(context.resourceKey, context.path, self[SOURCE
|
|
1955
|
+
cache.setAttr(context.resourceKey, context.path, self[SOURCE]);
|
|
1956
1956
|
_SIGNAL.isStale = true;
|
|
1957
1957
|
return true;
|
|
1958
1958
|
}
|
|
1959
|
-
let rawValue = self[SOURCE
|
|
1959
|
+
let rawValue = self[SOURCE];
|
|
1960
1960
|
if (field.kind !== 'schema-array') {
|
|
1961
1961
|
const transform = schema.transformation(field);
|
|
1962
1962
|
if (!transform) {
|
|
1963
1963
|
throw new Error(`No '${field.type}' transform defined for use by ${context.resourceKey.type}.${String(prop)}`);
|
|
1964
1964
|
}
|
|
1965
|
-
rawValue = self[SOURCE
|
|
1965
|
+
rawValue = self[SOURCE].map(item => transform.serialize(item, field.options ?? null, self.owner));
|
|
1966
1966
|
}
|
|
1967
1967
|
cache.setAttr(context.resourceKey, context.path, rawValue);
|
|
1968
1968
|
_SIGNAL.isStale = true;
|
|
@@ -1988,7 +1988,7 @@ class ManagedArray {
|
|
|
1988
1988
|
// A(identifierArray) since it is not configurable
|
|
1989
1989
|
// which is preferable to the `meta` override we used
|
|
1990
1990
|
// before which required importing all of Ember
|
|
1991
|
-
const desc
|
|
1991
|
+
const desc = {
|
|
1992
1992
|
enumerable: true,
|
|
1993
1993
|
configurable: false,
|
|
1994
1994
|
get: function () {
|
|
@@ -2000,7 +2000,7 @@ const desc$1 = {
|
|
|
2000
2000
|
}
|
|
2001
2001
|
};
|
|
2002
2002
|
// compat(desc);
|
|
2003
|
-
Object.defineProperty(ManagedArray.prototype, '[]', desc
|
|
2003
|
+
Object.defineProperty(ManagedArray.prototype, '[]', desc);
|
|
2004
2004
|
function getArrayField(context) {
|
|
2005
2005
|
const signal = entangleSignal(context.signals, context.record, context.path.at(-1), null);
|
|
2006
2006
|
// the thing we hand out needs to know its owner and path in a private manner
|
|
@@ -2210,7 +2210,7 @@ class ManyArrayManager {
|
|
|
2210
2210
|
if (rawValue.links) {
|
|
2211
2211
|
array.links = rawValue.links;
|
|
2212
2212
|
}
|
|
2213
|
-
const currentState = array[
|
|
2213
|
+
const currentState = array[Context].source;
|
|
2214
2214
|
|
|
2215
2215
|
// unlike in the normal RecordArray case, we don't need to divorce the reference
|
|
2216
2216
|
// because we don't need to worry about associate/disassociate since the graph
|
|
@@ -2303,26 +2303,19 @@ function getHasManyField(context) {
|
|
|
2303
2303
|
if (!rawValue) {
|
|
2304
2304
|
return null;
|
|
2305
2305
|
}
|
|
2306
|
-
const managedArray =
|
|
2306
|
+
const managedArray = createLegacyManyArray({
|
|
2307
2307
|
store,
|
|
2308
|
+
manager: new ManyArrayManager(record, editable),
|
|
2309
|
+
source: rawValue.data?.slice() ?? [],
|
|
2308
2310
|
type: field.type,
|
|
2311
|
+
isLoaded: true,
|
|
2312
|
+
editable,
|
|
2313
|
+
isAsync: field.options.async ?? false,
|
|
2314
|
+
isPolymorphic: field.options.polymorphic ?? false,
|
|
2315
|
+
field,
|
|
2309
2316
|
identifier: resourceKey,
|
|
2310
|
-
cache,
|
|
2311
|
-
field: context.legacy ? field : undefined,
|
|
2312
|
-
// we divorce the reference here because ManyArray mutates the target directly
|
|
2313
|
-
// before sending the mutation op to the cache. We may be able to avoid this in the future
|
|
2314
|
-
identifiers: rawValue.data?.slice(),
|
|
2315
|
-
key: field.name,
|
|
2316
|
-
meta: rawValue.meta || null,
|
|
2317
2317
|
links: rawValue.links || null,
|
|
2318
|
-
|
|
2319
|
-
isAsync: field.options.async ?? false,
|
|
2320
|
-
// TODO: Grab the proper value
|
|
2321
|
-
_inverseIsAsync: false,
|
|
2322
|
-
// @ts-expect-error Typescript doesn't have a way for us to thread the generic backwards so it infers unknown instead of T
|
|
2323
|
-
manager: new ManyArrayManager(record, editable),
|
|
2324
|
-
isLoaded: true,
|
|
2325
|
-
allowMutation: editable
|
|
2318
|
+
meta: rawValue.meta || null
|
|
2326
2319
|
});
|
|
2327
2320
|
signal.value = managedArray;
|
|
2328
2321
|
return managedArray;
|
|
@@ -2402,7 +2395,7 @@ function setIdentityField(context) {
|
|
|
2402
2395
|
})(!didChange || resourceKey.id === null) : {};
|
|
2403
2396
|
if (normalizedId !== null && didChange) {
|
|
2404
2397
|
store._instanceCache.setRecordId(resourceKey, normalizedId);
|
|
2405
|
-
store.notifications.notify(resourceKey, 'identity');
|
|
2398
|
+
store.notifications.notify(resourceKey, 'identity', null);
|
|
2406
2399
|
}
|
|
2407
2400
|
return true;
|
|
2408
2401
|
}
|
|
@@ -2425,7 +2418,7 @@ function setLocalField(context) {
|
|
|
2425
2418
|
}
|
|
2426
2419
|
return true;
|
|
2427
2420
|
}
|
|
2428
|
-
const ObjectSymbols = new Set([OBJECT_SIGNAL, Context, SOURCE
|
|
2421
|
+
const ObjectSymbols = new Set([OBJECT_SIGNAL, Context, SOURCE]);
|
|
2429
2422
|
|
|
2430
2423
|
// const ignoredGlobalFields = new Set<string>(['setInterval', 'nodeType', 'nodeName', 'length', 'document', STRUCTURED]);
|
|
2431
2424
|
|
|
@@ -2438,7 +2431,7 @@ class ManagedObject {
|
|
|
2438
2431
|
} = context;
|
|
2439
2432
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
2440
2433
|
const self = this;
|
|
2441
|
-
this[SOURCE
|
|
2434
|
+
this[SOURCE] = Object.assign({}, context.value);
|
|
2442
2435
|
const signals = withSignalStore(this);
|
|
2443
2436
|
const _SIGNAL = this[OBJECT_SIGNAL] = entangleSignal(signals, this, OBJECT_SIGNAL, undefined);
|
|
2444
2437
|
this[Context] = context;
|
|
@@ -2450,12 +2443,12 @@ class ManagedObject {
|
|
|
2450
2443
|
|
|
2451
2444
|
// prettier-ignore
|
|
2452
2445
|
const extensions = !context.legacy ? null : schema.CAUTION_MEGA_DANGER_ZONE_objectExtensions(field, null);
|
|
2453
|
-
const proxy = new Proxy(this[SOURCE
|
|
2446
|
+
const proxy = new Proxy(this[SOURCE], {
|
|
2454
2447
|
ownKeys() {
|
|
2455
|
-
return Object.keys(self[SOURCE
|
|
2448
|
+
return Object.keys(self[SOURCE]);
|
|
2456
2449
|
},
|
|
2457
2450
|
has(target, prop) {
|
|
2458
|
-
return prop in self[SOURCE
|
|
2451
|
+
return prop in self[SOURCE];
|
|
2459
2452
|
},
|
|
2460
2453
|
getOwnPropertyDescriptor(target, prop) {
|
|
2461
2454
|
return {
|
|
@@ -2490,26 +2483,26 @@ class ManagedObject {
|
|
|
2490
2483
|
if (_SIGNAL.isStale) {
|
|
2491
2484
|
_SIGNAL.isStale = false;
|
|
2492
2485
|
let newData = cache.getAttr(identifier, path);
|
|
2493
|
-
if (newData && newData !== self[SOURCE
|
|
2486
|
+
if (newData && newData !== self[SOURCE]) {
|
|
2494
2487
|
if (field.type) {
|
|
2495
2488
|
const transform = schema.transformation(field);
|
|
2496
2489
|
newData = transform.hydrate(newData, field.options ?? null, context.record);
|
|
2497
2490
|
}
|
|
2498
|
-
self[SOURCE
|
|
2491
|
+
self[SOURCE] = Object.assign({}, newData); // Add type assertion for newData
|
|
2499
2492
|
}
|
|
2500
2493
|
}
|
|
2501
2494
|
|
|
2502
2495
|
// toJSON and extensions need to come after we update data if stale
|
|
2503
2496
|
if (prop === 'toJSON') {
|
|
2504
2497
|
return function () {
|
|
2505
|
-
return structuredClone(self[SOURCE
|
|
2498
|
+
return structuredClone(self[SOURCE]);
|
|
2506
2499
|
};
|
|
2507
2500
|
}
|
|
2508
2501
|
|
|
2509
2502
|
// we always defer to data before extensions
|
|
2510
|
-
if (prop in self[SOURCE
|
|
2503
|
+
if (prop in self[SOURCE]) {
|
|
2511
2504
|
consumeInternalSignal(_SIGNAL);
|
|
2512
|
-
return self[SOURCE
|
|
2505
|
+
return self[SOURCE][prop];
|
|
2513
2506
|
}
|
|
2514
2507
|
if (isExtensionProp(extensions, prop)) {
|
|
2515
2508
|
return performObjectExtensionGet(receiver, extensions, signals, prop);
|
|
@@ -2525,7 +2518,7 @@ class ManagedObject {
|
|
|
2525
2518
|
|
|
2526
2519
|
// since objects function as dictionaries, we can't defer to schema/data before extensions
|
|
2527
2520
|
// unless the prop is in the existing data.
|
|
2528
|
-
if (!(prop in self[SOURCE
|
|
2521
|
+
if (!(prop in self[SOURCE]) && isExtensionProp(extensions, prop)) {
|
|
2529
2522
|
return performExtensionSet(receiver, extensions, signals, prop, value);
|
|
2530
2523
|
}
|
|
2531
2524
|
const reflect = Reflect.set(target, prop, value, receiver);
|
|
@@ -2533,10 +2526,10 @@ class ManagedObject {
|
|
|
2533
2526
|
return false;
|
|
2534
2527
|
}
|
|
2535
2528
|
if (!field.type) {
|
|
2536
|
-
cache.setAttr(identifier, path, self[SOURCE
|
|
2529
|
+
cache.setAttr(identifier, path, self[SOURCE]);
|
|
2537
2530
|
} else {
|
|
2538
2531
|
const transform = schema.transformation(field);
|
|
2539
|
-
const val = transform.serialize(self[SOURCE
|
|
2532
|
+
const val = transform.serialize(self[SOURCE], field.options ?? null, context.record);
|
|
2540
2533
|
cache.setAttr(identifier, path, val);
|
|
2541
2534
|
}
|
|
2542
2535
|
_SIGNAL.isStale = true;
|
|
@@ -3101,7 +3094,7 @@ class ReactiveResource {
|
|
|
3101
3094
|
if (signal) {
|
|
3102
3095
|
const peeked = signal.value;
|
|
3103
3096
|
if (peeked) {
|
|
3104
|
-
notifyInternalSignal(peeked[
|
|
3097
|
+
notifyInternalSignal(peeked[Context].signal);
|
|
3105
3098
|
}
|
|
3106
3099
|
}
|
|
3107
3100
|
return;
|
|
@@ -3177,6 +3170,16 @@ class ReactiveResource {
|
|
|
3177
3170
|
enumerable: true,
|
|
3178
3171
|
configurable: true
|
|
3179
3172
|
};
|
|
3173
|
+
case '@hash':
|
|
3174
|
+
return schemaForField.name ? {
|
|
3175
|
+
writable: false,
|
|
3176
|
+
enumerable: true,
|
|
3177
|
+
configurable: true
|
|
3178
|
+
} : {
|
|
3179
|
+
writable: false,
|
|
3180
|
+
enumerable: false,
|
|
3181
|
+
configurable: false
|
|
3182
|
+
};
|
|
3180
3183
|
case '@local':
|
|
3181
3184
|
case 'field':
|
|
3182
3185
|
case 'attribute':
|
|
@@ -3916,41 +3919,7 @@ class InstanceCache {
|
|
|
3916
3919
|
|
|
3917
3920
|
// TODO is this join still necessary?
|
|
3918
3921
|
this.store._join(() => {
|
|
3919
|
-
|
|
3920
|
-
const cache = this.cache;
|
|
3921
|
-
if (record) {
|
|
3922
|
-
this.store.teardownRecord(record);
|
|
3923
|
-
this.__instances.record.delete(identifier);
|
|
3924
|
-
StoreMap.delete(record);
|
|
3925
|
-
RecordCache.delete(record);
|
|
3926
|
-
if (macroCondition(getGlobalConfig().WarpDrive.activeLogging.LOG_INSTANCE_CACHE)) {
|
|
3927
|
-
if (getGlobalConfig().WarpDrive.debug.LOG_INSTANCE_CACHE || globalThis.getWarpDriveRuntimeConfig().debug.LOG_INSTANCE_CACHE) {
|
|
3928
|
-
// eslint-disable-next-line no-console
|
|
3929
|
-
console.log(`InstanceCache: destroyed record for ${String(identifier)}`);
|
|
3930
|
-
}
|
|
3931
|
-
}
|
|
3932
|
-
}
|
|
3933
|
-
if (cache) {
|
|
3934
|
-
cache.unloadRecord(identifier);
|
|
3935
|
-
StoreMap.delete(identifier);
|
|
3936
|
-
if (macroCondition(getGlobalConfig().WarpDrive.activeLogging.LOG_INSTANCE_CACHE)) {
|
|
3937
|
-
if (getGlobalConfig().WarpDrive.debug.LOG_INSTANCE_CACHE || globalThis.getWarpDriveRuntimeConfig().debug.LOG_INSTANCE_CACHE) {
|
|
3938
|
-
// eslint-disable-next-line no-console
|
|
3939
|
-
console.log(`InstanceCache: destroyed cache for ${String(identifier)}`);
|
|
3940
|
-
}
|
|
3941
|
-
}
|
|
3942
|
-
} else {
|
|
3943
|
-
this.disconnect(identifier);
|
|
3944
|
-
}
|
|
3945
|
-
this.store._requestCache._clearEntries(identifier);
|
|
3946
|
-
if (macroCondition(getGlobalConfig().WarpDrive.activeLogging.LOG_INSTANCE_CACHE)) {
|
|
3947
|
-
if (getGlobalConfig().WarpDrive.debug.LOG_INSTANCE_CACHE || globalThis.getWarpDriveRuntimeConfig().debug.LOG_INSTANCE_CACHE) {
|
|
3948
|
-
// eslint-disable-next-line no-console
|
|
3949
|
-
console.log(`InstanceCache: unloaded RecordData for ${String(identifier)}`);
|
|
3950
|
-
// eslint-disable-next-line no-console
|
|
3951
|
-
console.groupEnd();
|
|
3952
|
-
}
|
|
3953
|
-
}
|
|
3922
|
+
unloadRecord(this, identifier);
|
|
3954
3923
|
});
|
|
3955
3924
|
}
|
|
3956
3925
|
clear(type) {
|
|
@@ -4029,7 +3998,7 @@ class InstanceCache {
|
|
|
4029
3998
|
|
|
4030
3999
|
// TODO update resource cache if needed ?
|
|
4031
4000
|
// TODO handle consequences of identifier merge for notifications
|
|
4032
|
-
this.store.notifications.notify(identifier, 'identity');
|
|
4001
|
+
this.store.notifications.notify(identifier, 'identity', null);
|
|
4033
4002
|
}
|
|
4034
4003
|
}
|
|
4035
4004
|
function getNewRecord(instances, identifier, properties) {
|
|
@@ -4073,6 +4042,43 @@ function _clearCaches() {
|
|
|
4073
4042
|
RecordCache.clear();
|
|
4074
4043
|
StoreMap.clear();
|
|
4075
4044
|
}
|
|
4045
|
+
function unloadRecord(instances, identifier) {
|
|
4046
|
+
const record = instances.__instances.record.get(identifier);
|
|
4047
|
+
const cache = instances.cache;
|
|
4048
|
+
if (record) {
|
|
4049
|
+
instances.store.teardownRecord(record);
|
|
4050
|
+
instances.__instances.record.delete(identifier);
|
|
4051
|
+
StoreMap.delete(record);
|
|
4052
|
+
RecordCache.delete(record);
|
|
4053
|
+
if (macroCondition(getGlobalConfig().WarpDrive.activeLogging.LOG_INSTANCE_CACHE)) {
|
|
4054
|
+
if (getGlobalConfig().WarpDrive.debug.LOG_INSTANCE_CACHE || globalThis.getWarpDriveRuntimeConfig().debug.LOG_INSTANCE_CACHE) {
|
|
4055
|
+
// eslint-disable-next-line no-console
|
|
4056
|
+
console.log(`InstanceCache: destroyed record for ${String(identifier)}`);
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
}
|
|
4060
|
+
if (cache) {
|
|
4061
|
+
cache.unloadRecord(identifier);
|
|
4062
|
+
StoreMap.delete(identifier);
|
|
4063
|
+
if (macroCondition(getGlobalConfig().WarpDrive.activeLogging.LOG_INSTANCE_CACHE)) {
|
|
4064
|
+
if (getGlobalConfig().WarpDrive.debug.LOG_INSTANCE_CACHE || globalThis.getWarpDriveRuntimeConfig().debug.LOG_INSTANCE_CACHE) {
|
|
4065
|
+
// eslint-disable-next-line no-console
|
|
4066
|
+
console.log(`InstanceCache: destroyed cache for ${String(identifier)}`);
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
} else {
|
|
4070
|
+
instances.disconnect(identifier);
|
|
4071
|
+
}
|
|
4072
|
+
instances.store._requestCache._clearEntries(identifier);
|
|
4073
|
+
if (macroCondition(getGlobalConfig().WarpDrive.activeLogging.LOG_INSTANCE_CACHE)) {
|
|
4074
|
+
if (getGlobalConfig().WarpDrive.debug.LOG_INSTANCE_CACHE || globalThis.getWarpDriveRuntimeConfig().debug.LOG_INSTANCE_CACHE) {
|
|
4075
|
+
// eslint-disable-next-line no-console
|
|
4076
|
+
console.log(`InstanceCache: unloaded RecordData for ${String(identifier)}`);
|
|
4077
|
+
// eslint-disable-next-line no-console
|
|
4078
|
+
console.groupEnd();
|
|
4079
|
+
}
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4076
4082
|
|
|
4077
4083
|
/**
|
|
4078
4084
|
* The CacheManager wraps a Cache enforcing that only
|
|
@@ -4716,6 +4722,11 @@ class NotificationManager {
|
|
|
4716
4722
|
*/
|
|
4717
4723
|
|
|
4718
4724
|
subscribe(identifier, callback) {
|
|
4725
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4726
|
+
if (!test) {
|
|
4727
|
+
throw new Error(`Expected not to be destroyed`);
|
|
4728
|
+
}
|
|
4729
|
+
})(!this.isDestroyed) : {};
|
|
4719
4730
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4720
4731
|
if (!test) {
|
|
4721
4732
|
throw new Error(`Expected to receive a stable Identifier to subscribe to`);
|
|
@@ -4761,6 +4772,9 @@ class NotificationManager {
|
|
|
4761
4772
|
*/
|
|
4762
4773
|
|
|
4763
4774
|
notify(identifier, value, key) {
|
|
4775
|
+
if (this.isDestroyed) {
|
|
4776
|
+
return false;
|
|
4777
|
+
}
|
|
4764
4778
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4765
4779
|
if (!test) {
|
|
4766
4780
|
throw new Error(`Notify does not accept a key argument for the namespace '${value}'. Received key '${key || ''}'.`);
|
|
@@ -4775,14 +4789,14 @@ class NotificationManager {
|
|
|
4775
4789
|
}
|
|
4776
4790
|
return false;
|
|
4777
4791
|
}
|
|
4778
|
-
const
|
|
4779
|
-
if (
|
|
4792
|
+
const _hasSubscribers = hasSubscribers(this._cache, identifier, value);
|
|
4793
|
+
if (_hasSubscribers) {
|
|
4780
4794
|
let buffer = this._buffered.get(identifier);
|
|
4781
4795
|
if (!buffer) {
|
|
4782
4796
|
buffer = [];
|
|
4783
4797
|
this._buffered.set(identifier, buffer);
|
|
4784
4798
|
}
|
|
4785
|
-
buffer.push([value, key]);
|
|
4799
|
+
buffer.push([value, key || null]);
|
|
4786
4800
|
if (macroCondition(getGlobalConfig().WarpDrive.activeLogging.LOG_METRIC_COUNTS)) {
|
|
4787
4801
|
if (getGlobalConfig().WarpDrive.debug.LOG_METRIC_COUNTS || globalThis.getWarpDriveRuntimeConfig().debug.LOG_METRIC_COUNTS) {
|
|
4788
4802
|
count(`notify ${'type' in identifier ? identifier.type : '<document>'} ${value} ${key}`);
|
|
@@ -4807,7 +4821,7 @@ class NotificationManager {
|
|
|
4807
4821
|
}
|
|
4808
4822
|
}
|
|
4809
4823
|
}
|
|
4810
|
-
return
|
|
4824
|
+
return _hasSubscribers;
|
|
4811
4825
|
}
|
|
4812
4826
|
|
|
4813
4827
|
/** @internal */
|
|
@@ -4834,43 +4848,17 @@ class NotificationManager {
|
|
|
4834
4848
|
const buffered = this._buffered;
|
|
4835
4849
|
if (buffered.size) {
|
|
4836
4850
|
this._buffered = new Map();
|
|
4837
|
-
|
|
4838
|
-
states.
|
|
4851
|
+
for (const [identifier, states] of buffered) {
|
|
4852
|
+
for (let i = 0; i < states.length; i++) {
|
|
4839
4853
|
// @ts-expect-error
|
|
4840
|
-
this.
|
|
4841
|
-
}
|
|
4842
|
-
}
|
|
4854
|
+
_flushNotification(this._cache, identifier, states[i][0], states[i][1]);
|
|
4855
|
+
}
|
|
4856
|
+
}
|
|
4843
4857
|
}
|
|
4844
4858
|
this._hasFlush = false;
|
|
4845
4859
|
this._onFlushCB?.();
|
|
4846
4860
|
this._onFlushCB = undefined;
|
|
4847
4861
|
}
|
|
4848
|
-
_flushNotification(identifier, value, key) {
|
|
4849
|
-
if (macroCondition(getGlobalConfig().WarpDrive.activeLogging.LOG_NOTIFICATIONS)) {
|
|
4850
|
-
if (getGlobalConfig().WarpDrive.debug.LOG_NOTIFICATIONS || globalThis.getWarpDriveRuntimeConfig().debug.LOG_NOTIFICATIONS) {
|
|
4851
|
-
log('notify', '', `${'type' in identifier ? identifier.type : 'document'}`, identifier.lid, `${value}`, key || '');
|
|
4852
|
-
}
|
|
4853
|
-
}
|
|
4854
|
-
|
|
4855
|
-
// TODO for documents this will need to switch based on Identifier kind
|
|
4856
|
-
if (isCacheOperationValue(value)) {
|
|
4857
|
-
const callbackMap = this._cache.get(isDocumentIdentifier(identifier) ? 'document' : 'resource');
|
|
4858
|
-
if (callbackMap) {
|
|
4859
|
-
callbackMap.forEach(cb => {
|
|
4860
|
-
cb(identifier, value);
|
|
4861
|
-
});
|
|
4862
|
-
}
|
|
4863
|
-
}
|
|
4864
|
-
const callbacks = this._cache.get(identifier);
|
|
4865
|
-
if (!callbacks || !callbacks.length) {
|
|
4866
|
-
return false;
|
|
4867
|
-
}
|
|
4868
|
-
callbacks.forEach(cb => {
|
|
4869
|
-
// @ts-expect-error overload doesn't narrow within body
|
|
4870
|
-
cb(identifier, value, key);
|
|
4871
|
-
});
|
|
4872
|
-
return true;
|
|
4873
|
-
}
|
|
4874
4862
|
|
|
4875
4863
|
/** @internal */
|
|
4876
4864
|
destroy() {
|
|
@@ -4878,31 +4866,72 @@ class NotificationManager {
|
|
|
4878
4866
|
this._cache.clear();
|
|
4879
4867
|
}
|
|
4880
4868
|
}
|
|
4869
|
+
function _flushNotification(cache, identifier, value, key) {
|
|
4870
|
+
if (macroCondition(getGlobalConfig().WarpDrive.activeLogging.LOG_NOTIFICATIONS)) {
|
|
4871
|
+
if (getGlobalConfig().WarpDrive.debug.LOG_NOTIFICATIONS || globalThis.getWarpDriveRuntimeConfig().debug.LOG_NOTIFICATIONS) {
|
|
4872
|
+
log('notify', '', `${'type' in identifier ? identifier.type : 'document'}`, identifier.lid, `${value}`, key || '');
|
|
4873
|
+
}
|
|
4874
|
+
}
|
|
4881
4875
|
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4876
|
+
// TODO for documents this will need to switch based on Identifier kind
|
|
4877
|
+
if (isCacheOperationValue(value)) {
|
|
4878
|
+
const callbackMap = cache.get(isDocumentIdentifier(identifier) ? 'document' : 'resource');
|
|
4879
|
+
if (callbackMap) {
|
|
4880
|
+
callbackMap.forEach(cb => {
|
|
4881
|
+
cb(identifier, value);
|
|
4882
|
+
});
|
|
4883
|
+
}
|
|
4884
|
+
}
|
|
4885
|
+
const callbacks = cache.get(identifier);
|
|
4886
|
+
if (!callbacks || !callbacks.length) {
|
|
4887
|
+
return false;
|
|
4888
|
+
}
|
|
4889
|
+
callbacks.forEach(cb => {
|
|
4890
|
+
// @ts-expect-error overload doesn't narrow within body
|
|
4891
|
+
cb(identifier, value, key);
|
|
4892
|
+
});
|
|
4893
|
+
return true;
|
|
4894
|
+
}
|
|
4895
|
+
function hasSubscribers(cache, identifier, value) {
|
|
4896
|
+
const hasSubscriber = Boolean(cache.get(identifier)?.length);
|
|
4897
|
+
if (hasSubscriber || !isCacheOperationValue(value)) {
|
|
4898
|
+
return hasSubscriber;
|
|
4899
|
+
}
|
|
4900
|
+
const callbackMap = cache.get(isDocumentIdentifier(identifier) ? 'document' : 'resource');
|
|
4901
|
+
return Boolean(callbackMap?.length);
|
|
4902
|
+
}
|
|
4903
|
+
function update() {
|
|
4904
|
+
if (this.isUpdating) {
|
|
4905
|
+
return this._updatingPromise;
|
|
4906
|
+
}
|
|
4907
|
+
this.isUpdating = true;
|
|
4889
4908
|
|
|
4890
|
-
|
|
4909
|
+
// @ts-expect-error
|
|
4910
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
4911
|
+
const updatingPromise = this._update();
|
|
4912
|
+
void updatingPromise.finally(() => {
|
|
4913
|
+
this._updatingPromise = null;
|
|
4914
|
+
if (this.isDestroying || this.isDestroyed) {
|
|
4915
|
+
return;
|
|
4916
|
+
}
|
|
4917
|
+
this.isUpdating = false;
|
|
4918
|
+
});
|
|
4919
|
+
this._updatingPromise = updatingPromise;
|
|
4920
|
+
return updatingPromise;
|
|
4921
|
+
}
|
|
4922
|
+
function save() {
|
|
4923
|
+
const context = this[Context];
|
|
4924
|
+
const promise = Promise.all(this.map(record => context.store.saveRecord(record))).then(() => this);
|
|
4925
|
+
return promise;
|
|
4926
|
+
}
|
|
4891
4927
|
const ARRAY_GETTER_METHODS = new Set([Symbol.iterator, 'concat', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'flat', 'flatMap', 'forEach', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'map', 'reduce', 'reduceRight', 'slice', 'some', 'values']);
|
|
4892
4928
|
const ARRAY_SETTER_METHODS = new Set(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
|
|
4893
|
-
const SYNC_PROPS = new Set(['[]', 'length', 'links', 'meta']);
|
|
4894
4929
|
function isArrayGetter(prop) {
|
|
4895
4930
|
return ARRAY_GETTER_METHODS.has(prop);
|
|
4896
4931
|
}
|
|
4897
4932
|
function isArraySetter(prop) {
|
|
4898
4933
|
return ARRAY_SETTER_METHODS.has(prop);
|
|
4899
4934
|
}
|
|
4900
|
-
function isSelfProp(self, prop) {
|
|
4901
|
-
return prop in self;
|
|
4902
|
-
}
|
|
4903
|
-
const SOURCE = getOrSetGlobal('#source', Symbol('#source'));
|
|
4904
|
-
const MUTATE = getOrSetGlobal('#update', Symbol('#update'));
|
|
4905
|
-
const IS_COLLECTION = getOrSetGlobal('IS_COLLECTION', Symbol.for('Collection'));
|
|
4906
4935
|
function convertToInt(prop) {
|
|
4907
4936
|
if (typeof prop === 'symbol') return null;
|
|
4908
4937
|
const num = Number(prop);
|
|
@@ -4933,388 +4962,30 @@ function safeForEach(instance, arr, store, callback, target) {
|
|
|
4933
4962
|
return instance;
|
|
4934
4963
|
}
|
|
4935
4964
|
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
`RecordArray` or its subclasses will be returned by your application's store
|
|
4941
|
-
in response to queries.
|
|
4942
|
-
|
|
4943
|
-
This class should not be imported and instantiated by consuming applications.
|
|
4965
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4966
|
+
/*
|
|
4967
|
+
We redefine Proxy because the native Proxy type treats the `target` and
|
|
4968
|
+
`receiver` as the same type incorrectly.
|
|
4944
4969
|
|
|
4945
|
-
|
|
4946
|
-
@public
|
|
4970
|
+
We ported this from Typescript's own Proxy types on 3/10/2024.
|
|
4947
4971
|
*/
|
|
4948
4972
|
|
|
4973
|
+
const NativeProxy = Proxy;
|
|
4974
|
+
const IS_COLLECTION = getOrSetGlobal('IS_COLLECTION', Symbol.for('Collection'));
|
|
4975
|
+
function isContextProp(prop) {
|
|
4976
|
+
return prop === 'destroy' || prop === 'isDestroying' || prop === 'isDestroyed';
|
|
4977
|
+
}
|
|
4949
4978
|
// these are "internally" mutable, they should not be mutated by consumers
|
|
4950
4979
|
// though this is not currently enforced.
|
|
4951
4980
|
//
|
|
4952
4981
|
// all of these should become gated by field-type as they shouldn't be available
|
|
4953
4982
|
// on request results or non-legacy relationships.
|
|
4954
|
-
const MUTABLE_PROPS = ['_updatingPromise', 'isDestroying', 'isDestroyed', 'query', 'isUpdating', 'isLoaded', 'meta', 'links', 'isAsync', 'isPolymorphic', 'identifier', 'cache', '
|
|
4955
|
-
class IdentifierArray {
|
|
4956
|
-
/**
|
|
4957
|
-
The flag to signal a `RecordArray` is currently loading data.
|
|
4958
|
-
Example
|
|
4959
|
-
```javascript
|
|
4960
|
-
let people = store.peekAll('person');
|
|
4961
|
-
people.isUpdating; // false
|
|
4962
|
-
people.update();
|
|
4963
|
-
people.isUpdating; // true
|
|
4964
|
-
```
|
|
4965
|
-
@property isUpdating
|
|
4966
|
-
@public
|
|
4967
|
-
@type Boolean
|
|
4968
|
-
*/
|
|
4969
|
-
|
|
4970
|
-
isLoaded = true;
|
|
4971
|
-
isDestroying = false;
|
|
4972
|
-
isDestroyed = false;
|
|
4973
|
-
_updatingPromise = null;
|
|
4974
|
-
identifier;
|
|
4975
|
-
|
|
4976
|
-
/**
|
|
4977
|
-
The store that created this record array.
|
|
4978
|
-
@property store
|
|
4979
|
-
@private
|
|
4980
|
-
@type Store
|
|
4981
|
-
*/
|
|
4982
|
-
|
|
4983
|
-
destroy(clear) {
|
|
4984
|
-
this.isDestroying = !clear;
|
|
4985
|
-
// changing the reference breaks the Proxy
|
|
4986
|
-
// this[SOURCE] = [];
|
|
4987
|
-
this[SOURCE].length = 0;
|
|
4988
|
-
notifyInternalSignal(this[ARRAY_SIGNAL]);
|
|
4989
|
-
this.isDestroyed = !clear;
|
|
4990
|
-
}
|
|
4991
|
-
constructor(options) {
|
|
4992
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
4993
|
-
const self = this;
|
|
4994
|
-
this.modelName = options.type;
|
|
4995
|
-
this.store = options.store;
|
|
4996
|
-
this._manager = options.manager;
|
|
4997
|
-
this.identifier = options.identifier || null;
|
|
4998
|
-
this[SOURCE] = options.identifiers;
|
|
4999
|
-
this[IS_COLLECTION] = true;
|
|
5000
|
-
|
|
5001
|
-
// we attach the signal storage to the class
|
|
5002
|
-
// so that its easier to find debugging.
|
|
5003
|
-
const signals = withSignalStore(this);
|
|
5004
|
-
const store = options.store;
|
|
5005
|
-
const boundFns = new Map();
|
|
5006
|
-
const PrivateState = {
|
|
5007
|
-
links: options.links || null,
|
|
5008
|
-
meta: options.meta || null
|
|
5009
|
-
};
|
|
5010
|
-
let transaction = false;
|
|
5011
|
-
|
|
5012
|
-
// when a mutation occurs
|
|
5013
|
-
// we track all mutations within the call
|
|
5014
|
-
// and forward them as one
|
|
5015
|
-
let _SIGNAL = null;
|
|
5016
|
-
const extensions = options.field && this.store.schema.CAUTION_MEGA_DANGER_ZONE_arrayExtensions ? this.store.schema.CAUTION_MEGA_DANGER_ZONE_arrayExtensions(options.field) : null;
|
|
5017
|
-
const proxy = new NativeProxy(this[SOURCE], {
|
|
5018
|
-
get(target, prop, receiver) {
|
|
5019
|
-
const index = convertToInt(prop);
|
|
5020
|
-
if (_SIGNAL.isStale && (index !== null || SYNC_PROPS.has(prop) || isArrayGetter(prop))) {
|
|
5021
|
-
options.manager._syncArray(receiver);
|
|
5022
|
-
_SIGNAL.isStale = false;
|
|
5023
|
-
}
|
|
5024
|
-
if (index !== null) {
|
|
5025
|
-
const identifier = target[index];
|
|
5026
|
-
if (!transaction) {
|
|
5027
|
-
consumeInternalSignal(_SIGNAL);
|
|
5028
|
-
}
|
|
5029
|
-
return identifier && store._instanceCache.getRecord(identifier);
|
|
5030
|
-
}
|
|
5031
|
-
if (prop === ARRAY_SIGNAL) {
|
|
5032
|
-
return _SIGNAL;
|
|
5033
|
-
}
|
|
5034
|
-
if (prop === 'length') {
|
|
5035
|
-
return consumeInternalSignal(_SIGNAL), target.length;
|
|
5036
|
-
}
|
|
5037
|
-
if (prop === 'meta') return consumeInternalSignal(_SIGNAL), PrivateState.meta;
|
|
5038
|
-
if (prop === 'links') return consumeInternalSignal(_SIGNAL), PrivateState.links;
|
|
5039
|
-
if (prop === '[]') return consumeInternalSignal(_SIGNAL), receiver;
|
|
5040
|
-
if (isArrayGetter(prop)) {
|
|
5041
|
-
let fn = boundFns.get(prop);
|
|
5042
|
-
if (fn === undefined) {
|
|
5043
|
-
if (prop === 'forEach') {
|
|
5044
|
-
fn = function () {
|
|
5045
|
-
consumeInternalSignal(_SIGNAL);
|
|
5046
|
-
transaction = true;
|
|
5047
|
-
const result = safeForEach(receiver, target, store, arguments[0], arguments[1]);
|
|
5048
|
-
transaction = false;
|
|
5049
|
-
return result;
|
|
5050
|
-
};
|
|
5051
|
-
} else {
|
|
5052
|
-
fn = function () {
|
|
5053
|
-
consumeInternalSignal(_SIGNAL);
|
|
5054
|
-
// array functions must run through Reflect to work properly
|
|
5055
|
-
// binding via other means will not work.
|
|
5056
|
-
transaction = true;
|
|
5057
|
-
const result = Reflect.apply(target[prop], receiver, arguments);
|
|
5058
|
-
transaction = false;
|
|
5059
|
-
return result;
|
|
5060
|
-
};
|
|
5061
|
-
}
|
|
5062
|
-
boundFns.set(prop, fn);
|
|
5063
|
-
}
|
|
5064
|
-
return fn;
|
|
5065
|
-
}
|
|
5066
|
-
if (isArraySetter(prop)) {
|
|
5067
|
-
let fn = boundFns.get(prop);
|
|
5068
|
-
if (fn === undefined) {
|
|
5069
|
-
fn = function () {
|
|
5070
|
-
// array functions must run through Reflect to work properly
|
|
5071
|
-
// binding via other means will not work.
|
|
5072
|
-
if (!options.allowMutation) {
|
|
5073
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5074
|
-
if (!test) {
|
|
5075
|
-
throw new Error(`Mutating this array of records via ${String(prop)} is not allowed.`);
|
|
5076
|
-
}
|
|
5077
|
-
})(options.allowMutation) : {};
|
|
5078
|
-
return;
|
|
5079
|
-
}
|
|
5080
|
-
const args = Array.prototype.slice.call(arguments);
|
|
5081
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5082
|
-
if (!test) {
|
|
5083
|
-
throw new Error(`Cannot start a new array transaction while a previous transaction is underway`);
|
|
5084
|
-
}
|
|
5085
|
-
})(!transaction) : {};
|
|
5086
|
-
transaction = true;
|
|
5087
|
-
const result = options[MUTATE](target, receiver, prop, args, _SIGNAL);
|
|
5088
|
-
transaction = false;
|
|
5089
|
-
return result;
|
|
5090
|
-
};
|
|
5091
|
-
boundFns.set(prop, fn);
|
|
5092
|
-
}
|
|
5093
|
-
return fn;
|
|
5094
|
-
}
|
|
5095
|
-
if (isSelfProp(self, prop)) {
|
|
5096
|
-
if (prop === SOURCE) {
|
|
5097
|
-
return self[prop];
|
|
5098
|
-
}
|
|
5099
|
-
let fn = boundFns.get(prop);
|
|
5100
|
-
if (fn) return fn;
|
|
5101
|
-
const outcome = self[prop];
|
|
5102
|
-
if (typeof outcome === 'function') {
|
|
5103
|
-
fn = function () {
|
|
5104
|
-
consumeInternalSignal(_SIGNAL);
|
|
5105
|
-
// array functions must run through Reflect to work properly
|
|
5106
|
-
// binding via other means will not work.
|
|
5107
|
-
return Reflect.apply(outcome, receiver, arguments);
|
|
5108
|
-
};
|
|
5109
|
-
boundFns.set(prop, fn);
|
|
5110
|
-
return fn;
|
|
5111
|
-
}
|
|
5112
|
-
return consumeInternalSignal(_SIGNAL), outcome;
|
|
5113
|
-
}
|
|
5114
|
-
if (isExtensionProp(extensions, prop)) {
|
|
5115
|
-
return performArrayExtensionGet(receiver, extensions, signals, prop, _SIGNAL, boundFns, v => void (transaction = v));
|
|
5116
|
-
}
|
|
5117
|
-
return target[prop];
|
|
5118
|
-
},
|
|
5119
|
-
// FIXME: Should this get a generic like get above?
|
|
5120
|
-
set(target, prop, value, receiver) {
|
|
5121
|
-
if (!options.allowMutation && !MUTABLE_PROPS.includes(prop)) {
|
|
5122
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5123
|
-
if (!test) {
|
|
5124
|
-
throw new Error(`Mutating ${String(prop)} on this Array is not allowed.`);
|
|
5125
|
-
}
|
|
5126
|
-
})(options.allowMutation) : {};
|
|
5127
|
-
return false;
|
|
5128
|
-
}
|
|
5129
|
-
if (prop === 'length') {
|
|
5130
|
-
if (!transaction && value === 0) {
|
|
5131
|
-
transaction = true;
|
|
5132
|
-
options[MUTATE](target, receiver, 'length 0', [], _SIGNAL);
|
|
5133
|
-
transaction = false;
|
|
5134
|
-
return true;
|
|
5135
|
-
} else if (transaction) {
|
|
5136
|
-
return Reflect.set(target, prop, value);
|
|
5137
|
-
} else {
|
|
5138
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5139
|
-
{
|
|
5140
|
-
throw new Error(`unexpected length set`);
|
|
5141
|
-
}
|
|
5142
|
-
})() : {};
|
|
5143
|
-
}
|
|
5144
|
-
}
|
|
5145
|
-
if (prop === 'links') {
|
|
5146
|
-
PrivateState.links = value || null;
|
|
5147
|
-
return true;
|
|
5148
|
-
}
|
|
5149
|
-
if (prop === 'meta') {
|
|
5150
|
-
PrivateState.meta = value || null;
|
|
5151
|
-
return true;
|
|
5152
|
-
}
|
|
5153
|
-
if (isExtensionProp(extensions, prop)) {
|
|
5154
|
-
return performExtensionSet(receiver, extensions, signals, prop, value);
|
|
5155
|
-
}
|
|
5156
|
-
const index = convertToInt(prop);
|
|
5157
|
-
|
|
5158
|
-
// we do not allow "holey" arrays and so if the index is
|
|
5159
|
-
// greater than length then we will disallow setting it.
|
|
5160
|
-
// however, there is a special case for "unshift" with more than
|
|
5161
|
-
// one item being inserted since current items will be moved to the
|
|
5162
|
-
// new indices first.
|
|
5163
|
-
// we "loosely" detect this by just checking whether we are in
|
|
5164
|
-
// a transaction.
|
|
5165
|
-
if (index === null || index > target.length) {
|
|
5166
|
-
if (index !== null && transaction) {
|
|
5167
|
-
const identifier = recordIdentifierFor(value);
|
|
5168
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5169
|
-
if (!test) {
|
|
5170
|
-
throw new Error(`Cannot set index ${index} past the end of the array.`);
|
|
5171
|
-
}
|
|
5172
|
-
})(isStableIdentifier(identifier)) : {};
|
|
5173
|
-
target[index] = identifier;
|
|
5174
|
-
return true;
|
|
5175
|
-
} else if (isSelfProp(self, prop)) {
|
|
5176
|
-
// @ts-expect-error not all properties are indeces and we can't safely cast
|
|
5177
|
-
self[prop] = value;
|
|
5178
|
-
return true;
|
|
5179
|
-
}
|
|
5180
|
-
return false;
|
|
5181
|
-
}
|
|
5182
|
-
const original = target[index];
|
|
5183
|
-
const newIdentifier = extractIdentifierFromRecord$2(value);
|
|
5184
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5185
|
-
if (!test) {
|
|
5186
|
-
throw new Error(`Expected a record`);
|
|
5187
|
-
}
|
|
5188
|
-
})(isStableIdentifier(newIdentifier)) : {};
|
|
5189
|
-
// We generate "transactions" whenever a setter method on the array
|
|
5190
|
-
// is called and might bulk update multiple array cells. Fundamentally,
|
|
5191
|
-
// all array operations decompose into individual cell replacements.
|
|
5192
|
-
// e.g. a push is really a "replace cell at next index with new value"
|
|
5193
|
-
// or a splice is "shift all values left/right by X and set out of new
|
|
5194
|
-
// bounds cells to undefined"
|
|
5195
|
-
//
|
|
5196
|
-
// so, if we are in a transaction, then this is not a user generated change
|
|
5197
|
-
// but one generated by a setter method. In this case we want to only apply
|
|
5198
|
-
// the change to the target array and not call the MUTATE method.
|
|
5199
|
-
// If there is no transaction though, then this means the user themselves has
|
|
5200
|
-
// directly changed the value of a specific index and we need to thus generate
|
|
5201
|
-
// a mutation for that change.
|
|
5202
|
-
// e.g. "arr.push(newVal)" is handled by a "addToRelatedRecords" mutation within
|
|
5203
|
-
// a transaction.
|
|
5204
|
-
// while "arr[arr.length] = newVal;" is handled by this replace cell code path.
|
|
5205
|
-
if (!transaction) {
|
|
5206
|
-
options[MUTATE](target, receiver, 'replace cell', [index, original, newIdentifier], _SIGNAL);
|
|
5207
|
-
} else {
|
|
5208
|
-
target[index] = newIdentifier;
|
|
5209
|
-
}
|
|
5210
|
-
return true;
|
|
5211
|
-
},
|
|
5212
|
-
deleteProperty(target, prop) {
|
|
5213
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5214
|
-
if (!test) {
|
|
5215
|
-
throw new Error(`Deleting keys on managed arrays is disallowed`);
|
|
5216
|
-
}
|
|
5217
|
-
})(transaction) : {};
|
|
5218
|
-
if (!transaction) {
|
|
5219
|
-
return false;
|
|
5220
|
-
}
|
|
5221
|
-
return Reflect.deleteProperty(target, prop);
|
|
5222
|
-
},
|
|
5223
|
-
getPrototypeOf() {
|
|
5224
|
-
return Array.prototype;
|
|
5225
|
-
}
|
|
5226
|
-
});
|
|
5227
|
-
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
5228
|
-
Object.defineProperty(this, '__SHOW_ME_THE_DATA_(debug mode only)__', {
|
|
5229
|
-
enumerable: false,
|
|
5230
|
-
configurable: true,
|
|
5231
|
-
get() {
|
|
5232
|
-
return proxy.slice();
|
|
5233
|
-
}
|
|
5234
|
-
});
|
|
5235
|
-
}
|
|
5236
|
-
|
|
5237
|
-
// we entangle the signal on the returned proxy since that is
|
|
5238
|
-
// the object that other code will be interfacing with.
|
|
5239
|
-
_SIGNAL = entangleSignal(signals, proxy, ARRAY_SIGNAL, undefined);
|
|
5240
|
-
return proxy;
|
|
5241
|
-
}
|
|
5242
|
-
|
|
5243
|
-
/**
|
|
5244
|
-
Used to get the latest version of all of the records in this array
|
|
5245
|
-
from the adapter.
|
|
5246
|
-
Example
|
|
5247
|
-
```javascript
|
|
5248
|
-
let people = store.peekAll('person');
|
|
5249
|
-
people.isUpdating; // false
|
|
5250
|
-
people.update().then(function() {
|
|
5251
|
-
people.isUpdating; // false
|
|
5252
|
-
});
|
|
5253
|
-
people.isUpdating; // true
|
|
5254
|
-
```
|
|
5255
|
-
@public
|
|
5256
|
-
*/
|
|
5257
|
-
update() {
|
|
5258
|
-
if (this.isUpdating) {
|
|
5259
|
-
return this._updatingPromise;
|
|
5260
|
-
}
|
|
5261
|
-
this.isUpdating = true;
|
|
5262
|
-
const updatingPromise = this._update();
|
|
5263
|
-
void updatingPromise.finally(() => {
|
|
5264
|
-
this._updatingPromise = null;
|
|
5265
|
-
if (this.isDestroying || this.isDestroyed) {
|
|
5266
|
-
return;
|
|
5267
|
-
}
|
|
5268
|
-
this.isUpdating = false;
|
|
5269
|
-
});
|
|
5270
|
-
this._updatingPromise = updatingPromise;
|
|
5271
|
-
return updatingPromise;
|
|
5272
|
-
}
|
|
5273
|
-
|
|
5274
|
-
/*
|
|
5275
|
-
Update this Array and return a promise which resolves once the update
|
|
5276
|
-
is finished.
|
|
5277
|
-
*/
|
|
5278
|
-
_update() {
|
|
5279
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5280
|
-
if (!test) {
|
|
5281
|
-
throw new Error(`_update cannot be used with this array`);
|
|
5282
|
-
}
|
|
5283
|
-
})(this.modelName) : {};
|
|
5284
|
-
// @ts-expect-error typescript is unable to handle the complexity of
|
|
5285
|
-
// T = unknown, modelName = string
|
|
5286
|
-
// T extends TypedRecordInstance, modelName = TypeFromInstance<T>
|
|
5287
|
-
// both being valid options to pass through here.
|
|
5288
|
-
return this.store.findAll(this.modelName, {
|
|
5289
|
-
reload: true
|
|
5290
|
-
});
|
|
5291
|
-
}
|
|
5292
|
-
|
|
5293
|
-
// TODO deprecate
|
|
5294
|
-
/**
|
|
5295
|
-
Saves all of the records in the `RecordArray`.
|
|
5296
|
-
Example
|
|
5297
|
-
```javascript
|
|
5298
|
-
let messages = store.peekAll('message');
|
|
5299
|
-
messages.forEach(function(message) {
|
|
5300
|
-
message.hasBeenSeen = true;
|
|
5301
|
-
});
|
|
5302
|
-
messages.save();
|
|
5303
|
-
```
|
|
5304
|
-
@public
|
|
5305
|
-
@return {Promise<IdentifierArray>} promise
|
|
5306
|
-
*/
|
|
5307
|
-
save() {
|
|
5308
|
-
const promise = Promise.all(this.map(record => this.store.saveRecord(record))).then(() => this);
|
|
5309
|
-
return promise;
|
|
5310
|
-
}
|
|
5311
|
-
}
|
|
5312
|
-
|
|
4983
|
+
const MUTABLE_PROPS = ['_updatingPromise', 'isDestroying', 'isDestroyed', 'query', 'isUpdating', 'isLoaded', 'meta', 'links', 'isAsync', 'isPolymorphic', 'identifier', 'cache', 'key', 'DEPRECATED_CLASS_NAME'];
|
|
5313
4984
|
// this will error if someone tries to call
|
|
5314
4985
|
// A(identifierArray) since it is not configurable
|
|
5315
4986
|
// which is preferable to the `meta` override we used
|
|
5316
4987
|
// before which required importing all of Ember
|
|
5317
|
-
const
|
|
4988
|
+
const ARR_BRACKET_DESC = {
|
|
5318
4989
|
enumerable: true,
|
|
5319
4990
|
configurable: false,
|
|
5320
4991
|
get: function () {
|
|
@@ -5325,58 +4996,312 @@ const desc = {
|
|
|
5325
4996
|
}
|
|
5326
4997
|
}
|
|
5327
4998
|
};
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
}
|
|
4999
|
+
const IS_UPDATING_DESC = createSignalDescriptor('isUpdating', false);
|
|
5000
|
+
const ArrayHandler = {
|
|
5001
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
5002
|
+
if (prop === '[]') {
|
|
5003
|
+
// proxies do not allow you to report a descriptor as non-configurable
|
|
5004
|
+
// if there is no descriptor or the underlying descriptor is configurable
|
|
5005
|
+
const underlying = Reflect.getOwnPropertyDescriptor(target, prop);
|
|
5006
|
+
if (!underlying) {
|
|
5007
|
+
Object.defineProperty(target, prop, ARR_BRACKET_DESC);
|
|
5008
|
+
}
|
|
5009
|
+
return ARR_BRACKET_DESC;
|
|
5010
|
+
}
|
|
5011
|
+
if (prop === 'isUpdating') {
|
|
5012
|
+
return IS_UPDATING_DESC;
|
|
5013
|
+
}
|
|
5014
|
+
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
5015
|
+
},
|
|
5016
|
+
get(target, prop, receiver) {
|
|
5017
|
+
const CONTEXT = target[Context];
|
|
5018
|
+
|
|
5019
|
+
// we place this prop first as it needs initialized
|
|
5020
|
+
// prior to the signal check below
|
|
5021
|
+
if (prop === Signals) return CONTEXT.signals;
|
|
5022
|
+
const index = convertToInt(prop);
|
|
5023
|
+
if (
|
|
5024
|
+
// prettier-ignore
|
|
5025
|
+
CONTEXT.signal.isStale && (index !== null || prop === 'length' || prop === '[]' || CONTEXT.data && prop in CONTEXT.data || isArrayGetter(prop))) {
|
|
5026
|
+
CONTEXT.manager._syncArray(receiver);
|
|
5027
|
+
CONTEXT.signal.isStale = false;
|
|
5028
|
+
}
|
|
5029
|
+
if (index !== null) {
|
|
5030
|
+
const identifier = target[index];
|
|
5031
|
+
if (!CONTEXT.transaction) {
|
|
5032
|
+
consumeInternalSignal(CONTEXT.signal);
|
|
5033
|
+
}
|
|
5034
|
+
return identifier && CONTEXT.store._instanceCache.getRecord(identifier);
|
|
5035
|
+
}
|
|
5036
|
+
if (prop === 'length') return consumeInternalSignal(CONTEXT.signal), target.length;
|
|
5037
|
+
if (prop === '[]') return consumeInternalSignal(CONTEXT.signal), receiver;
|
|
5038
|
+
// TODO move this to ?? so its only on subclasses
|
|
5039
|
+
if (prop === 'isUpdating') return IS_UPDATING_DESC.get.call(receiver);
|
|
5040
|
+
if (prop === IS_COLLECTION) return true;
|
|
5041
|
+
if (prop === Context) return CONTEXT;
|
|
5042
|
+
if (isContextProp(prop)) {
|
|
5043
|
+
return CONTEXT[prop];
|
|
5044
|
+
}
|
|
5045
|
+
if (CONTEXT.data && prop in CONTEXT.data) {
|
|
5046
|
+
// all props in data are reactive props.
|
|
5047
|
+
return consumeInternalSignal(CONTEXT.signal), CONTEXT.data[prop];
|
|
5048
|
+
}
|
|
5049
|
+
if (isArrayGetter(prop)) {
|
|
5050
|
+
let fn = CONTEXT.boundFns.get(prop);
|
|
5051
|
+
if (fn === undefined) {
|
|
5052
|
+
if (prop === 'forEach') {
|
|
5053
|
+
fn = function () {
|
|
5054
|
+
consumeInternalSignal(CONTEXT.signal);
|
|
5055
|
+
CONTEXT.transaction = true;
|
|
5056
|
+
const result = safeForEach(receiver, target, CONTEXT.store, arguments[0], arguments[1]);
|
|
5057
|
+
CONTEXT.transaction = false;
|
|
5058
|
+
return result;
|
|
5059
|
+
};
|
|
5060
|
+
} else {
|
|
5061
|
+
fn = function () {
|
|
5062
|
+
consumeInternalSignal(CONTEXT.signal);
|
|
5063
|
+
// array functions must run through Reflect to work properly
|
|
5064
|
+
// binding via other means will not work.
|
|
5065
|
+
CONTEXT.transaction = true;
|
|
5066
|
+
const result = Reflect.apply(target[prop], receiver, arguments);
|
|
5067
|
+
CONTEXT.transaction = false;
|
|
5068
|
+
return result;
|
|
5069
|
+
};
|
|
5070
|
+
}
|
|
5071
|
+
CONTEXT.boundFns.set(prop, fn);
|
|
5072
|
+
}
|
|
5073
|
+
return fn;
|
|
5074
|
+
}
|
|
5075
|
+
if (isArraySetter(prop)) {
|
|
5076
|
+
let fn = CONTEXT.boundFns.get(prop);
|
|
5077
|
+
if (fn === undefined) {
|
|
5078
|
+
fn = function () {
|
|
5079
|
+
// array functions must run through Reflect to work properly
|
|
5080
|
+
// binding via other means will not work.
|
|
5081
|
+
if (!CONTEXT.editable) {
|
|
5082
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5083
|
+
if (!test) {
|
|
5084
|
+
throw new Error(`Mutating this array of records via ${String(prop)} is not allowed.`);
|
|
5085
|
+
}
|
|
5086
|
+
})(CONTEXT.editable) : {};
|
|
5087
|
+
return;
|
|
5088
|
+
}
|
|
5089
|
+
const args = Array.prototype.slice.call(arguments);
|
|
5090
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5091
|
+
if (!test) {
|
|
5092
|
+
throw new Error(`Cannot start a new array transaction while a previous transaction is underway`);
|
|
5093
|
+
}
|
|
5094
|
+
})(!CONTEXT.transaction) : {};
|
|
5095
|
+
CONTEXT.transaction = true;
|
|
5096
|
+
const result = CONTEXT.mutate(target, receiver, prop, args, CONTEXT.signal);
|
|
5097
|
+
CONTEXT.transaction = false;
|
|
5098
|
+
return result;
|
|
5099
|
+
};
|
|
5100
|
+
CONTEXT.boundFns.set(prop, fn);
|
|
5101
|
+
}
|
|
5102
|
+
return fn;
|
|
5103
|
+
}
|
|
5104
|
+
if (CONTEXT.features && prop in CONTEXT.features) {
|
|
5105
|
+
let fn = CONTEXT.boundFns.get(prop);
|
|
5106
|
+
if (fn) return fn;
|
|
5107
|
+
|
|
5108
|
+
// @ts-expect-error
|
|
5109
|
+
const outcome = CONTEXT.features[prop];
|
|
5110
|
+
if (typeof outcome === 'function') {
|
|
5111
|
+
fn = function () {
|
|
5112
|
+
consumeInternalSignal(CONTEXT.signal);
|
|
5113
|
+
// array functions must run through Reflect to work properly
|
|
5114
|
+
// binding via other means will not work.
|
|
5115
|
+
return Reflect.apply(outcome, receiver, arguments);
|
|
5116
|
+
};
|
|
5117
|
+
CONTEXT.boundFns.set(prop, fn);
|
|
5118
|
+
return fn;
|
|
5119
|
+
}
|
|
5120
|
+
return consumeInternalSignal(CONTEXT.signal), outcome;
|
|
5121
|
+
}
|
|
5122
|
+
if (isExtensionProp(CONTEXT.extensions, prop)) {
|
|
5123
|
+
return performArrayExtensionGet(receiver, CONTEXT.extensions, CONTEXT.signals, prop, CONTEXT.signal, CONTEXT.boundFns, v => void (CONTEXT.transaction = v));
|
|
5124
|
+
}
|
|
5125
|
+
return target[prop];
|
|
5126
|
+
},
|
|
5127
|
+
set(target, prop, value, receiver) {
|
|
5128
|
+
const CONTEXT = target[Context];
|
|
5129
|
+
if (prop === Signals) {
|
|
5130
|
+
CONTEXT.signals = value;
|
|
5131
|
+
return true;
|
|
5132
|
+
}
|
|
5133
|
+
if (!CONTEXT.editable && !MUTABLE_PROPS.includes(prop)) {
|
|
5134
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5135
|
+
if (!test) {
|
|
5136
|
+
throw new Error(`Mutating ${String(prop)} on this Array is not allowed.`);
|
|
5137
|
+
}
|
|
5138
|
+
})(CONTEXT.editable) : {};
|
|
5139
|
+
return false;
|
|
5140
|
+
}
|
|
5141
|
+
if (prop === 'length') {
|
|
5142
|
+
if (!CONTEXT.transaction && value === 0) {
|
|
5143
|
+
CONTEXT.transaction = true;
|
|
5144
|
+
CONTEXT.mutate(target, receiver, 'length 0', [], CONTEXT.signal);
|
|
5145
|
+
CONTEXT.transaction = false;
|
|
5146
|
+
return true;
|
|
5147
|
+
} else if (CONTEXT.transaction) {
|
|
5148
|
+
return Reflect.set(target, prop, value);
|
|
5149
|
+
} else {
|
|
5150
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5151
|
+
{
|
|
5152
|
+
throw new Error(`unexpected length set`);
|
|
5153
|
+
}
|
|
5154
|
+
})() : {};
|
|
5155
|
+
}
|
|
5156
|
+
}
|
|
5157
|
+
if (isContextProp(prop)) {
|
|
5158
|
+
// @ts-expect-error
|
|
5159
|
+
CONTEXT[prop] = value;
|
|
5160
|
+
return true;
|
|
5161
|
+
}
|
|
5162
|
+
if (CONTEXT.data && prop in CONTEXT.data) {
|
|
5163
|
+
CONTEXT.data[prop] = value || null;
|
|
5164
|
+
return true;
|
|
5165
|
+
}
|
|
5343
5166
|
|
|
5344
|
-
// TODO
|
|
5167
|
+
// TODO move this to subclass
|
|
5168
|
+
if (prop === 'isUpdating') {
|
|
5169
|
+
IS_UPDATING_DESC.set.call(receiver, value);
|
|
5170
|
+
return true;
|
|
5171
|
+
}
|
|
5172
|
+
if (isExtensionProp(CONTEXT.extensions, prop)) {
|
|
5173
|
+
return performExtensionSet(receiver, CONTEXT.extensions, CONTEXT.signals, prop, value);
|
|
5174
|
+
}
|
|
5175
|
+
const index = convertToInt(prop);
|
|
5176
|
+
|
|
5177
|
+
// we do not allow "holey" arrays and so if the index is
|
|
5178
|
+
// greater than length then we will disallow setting it.
|
|
5179
|
+
// however, there is a special case for "unshift" with more than
|
|
5180
|
+
// one item being inserted since current items will be moved to the
|
|
5181
|
+
// new indices first.
|
|
5182
|
+
// we "loosely" detect this by just checking whether we are in
|
|
5183
|
+
// a transaction.
|
|
5184
|
+
if (index === null || index > target.length) {
|
|
5185
|
+
if (index !== null && CONTEXT.transaction) {
|
|
5186
|
+
const identifier = recordIdentifierFor(value);
|
|
5187
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5188
|
+
if (!test) {
|
|
5189
|
+
throw new Error(`Cannot set index ${index} past the end of the array.`);
|
|
5190
|
+
}
|
|
5191
|
+
})(isStableIdentifier(identifier)) : {};
|
|
5192
|
+
target[index] = identifier;
|
|
5193
|
+
return true;
|
|
5194
|
+
} else if (CONTEXT.features && prop in CONTEXT.features) {
|
|
5195
|
+
CONTEXT.features[prop] = value;
|
|
5196
|
+
return true;
|
|
5197
|
+
}
|
|
5198
|
+
return false;
|
|
5199
|
+
}
|
|
5200
|
+
const original = target[index];
|
|
5201
|
+
const newIdentifier = extractIdentifierFromRecord$2(value);
|
|
5345
5202
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5346
5203
|
if (!test) {
|
|
5347
|
-
throw new Error(`
|
|
5348
|
-
}
|
|
5349
|
-
})(
|
|
5204
|
+
throw new Error(`Expected a record`);
|
|
5205
|
+
}
|
|
5206
|
+
})(newIdentifier && isStableIdentifier(newIdentifier)) : {};
|
|
5207
|
+
// We generate "transactions" whenever a setter method on the array
|
|
5208
|
+
// is called and might bulk update multiple array cells. Fundamentally,
|
|
5209
|
+
// all array operations decompose into individual cell replacements.
|
|
5210
|
+
// e.g. a push is really a "replace cell at next index with new value"
|
|
5211
|
+
// or a splice is "shift all values left/right by X and set out of new
|
|
5212
|
+
// bounds cells to undefined"
|
|
5213
|
+
//
|
|
5214
|
+
// so, if we are in a transaction, then this is not a user generated change
|
|
5215
|
+
// but one generated by a setter method. In this case we want to only apply
|
|
5216
|
+
// the change to the target array and not call the MUTATE method.
|
|
5217
|
+
// If there is no transaction though, then this means the user themselves has
|
|
5218
|
+
// directly changed the value of a specific index and we need to thus generate
|
|
5219
|
+
// a mutation for that change.
|
|
5220
|
+
// e.g. "arr.push(newVal)" is handled by a "addToRelatedRecords" mutation within
|
|
5221
|
+
// a transaction.
|
|
5222
|
+
// while "arr[arr.length] = newVal;" is handled by this replace cell code path.
|
|
5223
|
+
if (!CONTEXT.transaction) {
|
|
5224
|
+
CONTEXT.mutate(target, receiver, 'replace cell', [index, original, newIdentifier], CONTEXT.signal);
|
|
5225
|
+
} else {
|
|
5226
|
+
target[index] = newIdentifier;
|
|
5227
|
+
}
|
|
5228
|
+
return true;
|
|
5229
|
+
},
|
|
5230
|
+
deleteProperty(target, prop) {
|
|
5231
|
+
const CONTEXT = target[Context];
|
|
5350
5232
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5351
5233
|
if (!test) {
|
|
5352
|
-
throw new Error(`
|
|
5234
|
+
throw new Error(`Deleting keys on managed arrays is disallowed`);
|
|
5353
5235
|
}
|
|
5354
|
-
})(
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
return promise;
|
|
5236
|
+
})(CONTEXT.transaction) : {};
|
|
5237
|
+
if (!CONTEXT.transaction) {
|
|
5238
|
+
return false;
|
|
5239
|
+
}
|
|
5240
|
+
return Reflect.deleteProperty(target, prop);
|
|
5241
|
+
},
|
|
5242
|
+
getPrototypeOf() {
|
|
5243
|
+
return Array.prototype;
|
|
5363
5244
|
}
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5245
|
+
};
|
|
5246
|
+
const ILLEGAL_MUTATION = () => {
|
|
5247
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5248
|
+
{
|
|
5249
|
+
throw new Error(`ILLEGAL OPERATION: This ReactiveResourceArray is immutable`);
|
|
5250
|
+
}
|
|
5251
|
+
})() : {};
|
|
5252
|
+
};
|
|
5253
|
+
function createReactiveResourceArray(options) {
|
|
5254
|
+
const TARGET = options.source;
|
|
5255
|
+
const context = {
|
|
5256
|
+
store: options.store,
|
|
5257
|
+
manager: options.manager,
|
|
5258
|
+
editable: options.editable,
|
|
5259
|
+
source: options.source,
|
|
5260
|
+
data: options.data,
|
|
5261
|
+
features: options.features,
|
|
5262
|
+
extensions: options.extensions,
|
|
5263
|
+
options: options.options,
|
|
5264
|
+
destroy: options.destroy || destroy,
|
|
5265
|
+
mutate: options.mutate || ILLEGAL_MUTATION,
|
|
5266
|
+
signals: null,
|
|
5267
|
+
signal: null,
|
|
5268
|
+
isDestroying: false,
|
|
5269
|
+
isDestroyed: false,
|
|
5270
|
+
transaction: false,
|
|
5271
|
+
boundFns: new Map()
|
|
5272
|
+
};
|
|
5273
|
+
TARGET[Context] = context;
|
|
5274
|
+
const proxy = new NativeProxy(TARGET, ArrayHandler);
|
|
5275
|
+
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
5276
|
+
Object.defineProperty(TARGET, '__SHOW_ME_THE_DATA_(debug mode only)__', {
|
|
5277
|
+
enumerable: false,
|
|
5278
|
+
configurable: true,
|
|
5279
|
+
get() {
|
|
5280
|
+
return proxy.slice();
|
|
5281
|
+
}
|
|
5282
|
+
});
|
|
5368
5283
|
}
|
|
5284
|
+
|
|
5285
|
+
// we entangle the signal on the returned proxy since that is
|
|
5286
|
+
// the object that other code will be interfacing with.
|
|
5287
|
+
// when a mutation occurs
|
|
5288
|
+
// we track all mutations within the call
|
|
5289
|
+
// and forward them as one
|
|
5290
|
+
withSignalStore(proxy);
|
|
5291
|
+
context.signal = createInternalSignal(context.signals, proxy, ARRAY_SIGNAL, undefined);
|
|
5292
|
+
return proxy;
|
|
5369
5293
|
}
|
|
5370
|
-
// trick the proxy "in" check
|
|
5371
|
-
Collection.prototype.query = null;
|
|
5372
5294
|
|
|
5373
5295
|
// Ensure instanceof works correctly
|
|
5374
5296
|
// Object.setPrototypeOf(IdentifierArray.prototype, Array.prototype);
|
|
5375
5297
|
|
|
5376
|
-
function
|
|
5298
|
+
function extractIdentifierFromRecord$2(record) {
|
|
5299
|
+
if (!record) {
|
|
5300
|
+
return null;
|
|
5301
|
+
}
|
|
5377
5302
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5378
5303
|
if (!test) {
|
|
5379
|
-
throw new Error(`All elements of a
|
|
5304
|
+
throw new Error(`All elements of a ReactiveResourceArray must be instances of a ReactiveResource, you passed $${typeof record}`);
|
|
5380
5305
|
}
|
|
5381
5306
|
})(function () {
|
|
5382
5307
|
try {
|
|
@@ -5386,14 +5311,155 @@ function assertRecordPassedToHasMany$1(record) {
|
|
|
5386
5311
|
return false;
|
|
5387
5312
|
}
|
|
5388
5313
|
}()) : {};
|
|
5389
|
-
}
|
|
5390
|
-
function extractIdentifierFromRecord$2(record) {
|
|
5391
|
-
if (!record) {
|
|
5392
|
-
return null;
|
|
5393
|
-
}
|
|
5394
|
-
assertRecordPassedToHasMany$1(record);
|
|
5395
5314
|
return recordIdentifierFor(record);
|
|
5396
5315
|
}
|
|
5316
|
+
function destroy(clear) {
|
|
5317
|
+
const context = this[Context];
|
|
5318
|
+
this.isDestroying = !clear;
|
|
5319
|
+
// changing the reference breaks the Proxy
|
|
5320
|
+
// this[SOURCE] = [];
|
|
5321
|
+
context.source.length = 0;
|
|
5322
|
+
notifyInternalSignal(context.signal);
|
|
5323
|
+
this.isDestroyed = !clear;
|
|
5324
|
+
}
|
|
5325
|
+
function createRequestCollection(config) {
|
|
5326
|
+
return createReactiveResourceArray({
|
|
5327
|
+
store: config.store,
|
|
5328
|
+
manager: config.manager,
|
|
5329
|
+
editable: false,
|
|
5330
|
+
source: config.source,
|
|
5331
|
+
data: null,
|
|
5332
|
+
features: null,
|
|
5333
|
+
extensions: null,
|
|
5334
|
+
options: config.options,
|
|
5335
|
+
destroy: null,
|
|
5336
|
+
mutate: null
|
|
5337
|
+
});
|
|
5338
|
+
}
|
|
5339
|
+
|
|
5340
|
+
/**
|
|
5341
|
+
* The options for {@link createLegacyLiveArray}
|
|
5342
|
+
*
|
|
5343
|
+
* @internal
|
|
5344
|
+
*/
|
|
5345
|
+
/**
|
|
5346
|
+
* Creates a {@link LegacyLiveArray}
|
|
5347
|
+
*
|
|
5348
|
+
* @internal
|
|
5349
|
+
*/
|
|
5350
|
+
function createLegacyLiveArray(options) {
|
|
5351
|
+
return createReactiveResourceArray({
|
|
5352
|
+
store: options.store,
|
|
5353
|
+
manager: options.manager,
|
|
5354
|
+
editable: false,
|
|
5355
|
+
source: options.source,
|
|
5356
|
+
data: null,
|
|
5357
|
+
features: {
|
|
5358
|
+
modelName: options.type,
|
|
5359
|
+
update,
|
|
5360
|
+
_update: _updateLiveArray,
|
|
5361
|
+
save,
|
|
5362
|
+
DEPRECATED_CLASS_NAME: 'LiveArray',
|
|
5363
|
+
isUpdating: false,
|
|
5364
|
+
isLoaded: true,
|
|
5365
|
+
_updatingPromise: null
|
|
5366
|
+
},
|
|
5367
|
+
extensions: null,
|
|
5368
|
+
options: null,
|
|
5369
|
+
destroy: null,
|
|
5370
|
+
mutate: null
|
|
5371
|
+
});
|
|
5372
|
+
}
|
|
5373
|
+
function _updateLiveArray() {
|
|
5374
|
+
const context = this[Context];
|
|
5375
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5376
|
+
if (!test) {
|
|
5377
|
+
throw new Error(`_update cannot be used with this array`);
|
|
5378
|
+
}
|
|
5379
|
+
})(this.modelName) : {};
|
|
5380
|
+
// @ts-expect-error typescript is unable to handle the complexity of
|
|
5381
|
+
// T = unknown, modelName = string
|
|
5382
|
+
// T extends TypedRecordInstance, modelName = TypeFromInstance<T>
|
|
5383
|
+
// both being valid options to pass through here.
|
|
5384
|
+
return context.store.findAll(this.modelName, {
|
|
5385
|
+
reload: true
|
|
5386
|
+
});
|
|
5387
|
+
}
|
|
5388
|
+
|
|
5389
|
+
/**
|
|
5390
|
+
* The options for {@link createLegacyQueryArray}
|
|
5391
|
+
*
|
|
5392
|
+
* See also {@link LegacyLiveArrayCreateOptions} which
|
|
5393
|
+
* this extends.
|
|
5394
|
+
*
|
|
5395
|
+
* @internal
|
|
5396
|
+
*/
|
|
5397
|
+
/**
|
|
5398
|
+
* Creates a {@link LegacyQueryArray}
|
|
5399
|
+
*
|
|
5400
|
+
* Options: {@link LegacyQueryArrayCreateOptions}
|
|
5401
|
+
*
|
|
5402
|
+
* @internal
|
|
5403
|
+
*/
|
|
5404
|
+
function createLegacyQueryArray(options) {
|
|
5405
|
+
return createReactiveResourceArray({
|
|
5406
|
+
store: options.store,
|
|
5407
|
+
manager: options.manager,
|
|
5408
|
+
editable: false,
|
|
5409
|
+
source: options.source,
|
|
5410
|
+
data: {
|
|
5411
|
+
links: options.links,
|
|
5412
|
+
meta: options.meta
|
|
5413
|
+
},
|
|
5414
|
+
features: {
|
|
5415
|
+
query: options.query,
|
|
5416
|
+
modelName: options.type,
|
|
5417
|
+
update,
|
|
5418
|
+
_update: _updateCollection,
|
|
5419
|
+
save,
|
|
5420
|
+
DEPRECATED_CLASS_NAME: 'LegacyQueryArray',
|
|
5421
|
+
isUpdating: false,
|
|
5422
|
+
isLoaded: options.isLoaded,
|
|
5423
|
+
_updatingPromise: null
|
|
5424
|
+
},
|
|
5425
|
+
extensions: null,
|
|
5426
|
+
options: null,
|
|
5427
|
+
destroy: destroyCollection,
|
|
5428
|
+
mutate: null
|
|
5429
|
+
});
|
|
5430
|
+
}
|
|
5431
|
+
function _updateCollection() {
|
|
5432
|
+
const context = this[Context];
|
|
5433
|
+
const {
|
|
5434
|
+
query
|
|
5435
|
+
} = this;
|
|
5436
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5437
|
+
if (!test) {
|
|
5438
|
+
throw new Error(`update cannot be used with this array`);
|
|
5439
|
+
}
|
|
5440
|
+
})(this.modelName) : {};
|
|
5441
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5442
|
+
if (!test) {
|
|
5443
|
+
throw new Error(`update cannot be used with no query`);
|
|
5444
|
+
}
|
|
5445
|
+
})(query) : {};
|
|
5446
|
+
// @ts-expect-error typescript is unable to handle the complexity of
|
|
5447
|
+
// T = unknown, modelName = string
|
|
5448
|
+
// T extends TypedRecordInstance, modelName = TypeFromInstance<T>
|
|
5449
|
+
// both being valid options to pass through here.
|
|
5450
|
+
const promise = context.store.query(this.modelName, query, {
|
|
5451
|
+
_recordArray: this
|
|
5452
|
+
});
|
|
5453
|
+
return promise;
|
|
5454
|
+
}
|
|
5455
|
+
function destroyCollection(clear) {
|
|
5456
|
+
destroy.call(this, clear ?? false);
|
|
5457
|
+
const {
|
|
5458
|
+
manager
|
|
5459
|
+
} = this[Context];
|
|
5460
|
+
manager._managed.delete(this);
|
|
5461
|
+
manager._pending.delete(this);
|
|
5462
|
+
}
|
|
5397
5463
|
const FAKE_ARR = getOrSetGlobal('FAKE_ARR', {});
|
|
5398
5464
|
const SLICE_BATCH_SIZE = 4761;
|
|
5399
5465
|
/**
|
|
@@ -5429,7 +5495,6 @@ const SLICE_BATCH_SIZE = 4761;
|
|
|
5429
5495
|
* Sincerely,
|
|
5430
5496
|
* - runspired (Chris Thoburn) 08/21/2022
|
|
5431
5497
|
*
|
|
5432
|
-
* @function fastPush
|
|
5433
5498
|
* @internal
|
|
5434
5499
|
* @param target the array to push into
|
|
5435
5500
|
* @param source the items to push into target
|
|
@@ -5447,6 +5512,54 @@ function fastPush(target, source) {
|
|
|
5447
5512
|
@internal
|
|
5448
5513
|
*/
|
|
5449
5514
|
class RecordArrayManager {
|
|
5515
|
+
/**
|
|
5516
|
+
*
|
|
5517
|
+
*/
|
|
5518
|
+
|
|
5519
|
+
/**
|
|
5520
|
+
* LiveArray (peekAll/findAll) array instances
|
|
5521
|
+
* keyed by their ResourceType.
|
|
5522
|
+
*/
|
|
5523
|
+
|
|
5524
|
+
/**
|
|
5525
|
+
*
|
|
5526
|
+
*/
|
|
5527
|
+
|
|
5528
|
+
/**
|
|
5529
|
+
* Buffered changes to apply keyed by the array to
|
|
5530
|
+
* which to apply them to.
|
|
5531
|
+
*/
|
|
5532
|
+
|
|
5533
|
+
/**
|
|
5534
|
+
* An inverse map from StableRecordIdentifier to the list
|
|
5535
|
+
* of arrays it can be found in, useful for fast updates
|
|
5536
|
+
* when state changes to a resource occur.
|
|
5537
|
+
*/
|
|
5538
|
+
|
|
5539
|
+
/**
|
|
5540
|
+
* When we do not yet have a LiveArray, this keeps track of
|
|
5541
|
+
* the added/removed identifiers to enable us to more efficiently
|
|
5542
|
+
* produce the LiveArray later.
|
|
5543
|
+
*
|
|
5544
|
+
* It's possible that using a Set and only storing additions instead of
|
|
5545
|
+
* additions and deletes would be more efficient.
|
|
5546
|
+
*/
|
|
5547
|
+
|
|
5548
|
+
/**
|
|
5549
|
+
* KeyedArrays are arrays associated to a specific RequestKey.
|
|
5550
|
+
*/
|
|
5551
|
+
|
|
5552
|
+
/**
|
|
5553
|
+
* The visibility set tracks whether a given identifier should
|
|
5554
|
+
* be shown in RecordArrays. It is used to dedupe added/removed
|
|
5555
|
+
* and state change events.
|
|
5556
|
+
*
|
|
5557
|
+
* As a Map, it grows to be very large - there may be ways to
|
|
5558
|
+
* reduce its size by instead migrating to it functioning as
|
|
5559
|
+
* an exclusion list. Any entry not in the list would be considered
|
|
5560
|
+
* visible.
|
|
5561
|
+
*/
|
|
5562
|
+
|
|
5450
5563
|
constructor(options) {
|
|
5451
5564
|
this.store = options.store;
|
|
5452
5565
|
this.isDestroying = false;
|
|
@@ -5459,12 +5572,15 @@ class RecordArrayManager {
|
|
|
5459
5572
|
this._identifiers = new Map();
|
|
5460
5573
|
this._set = new Map();
|
|
5461
5574
|
this._visibilitySet = new Map();
|
|
5462
|
-
this.
|
|
5575
|
+
this._documentSubscription = this.store.notifications.subscribe('document', (identifier, type) => {
|
|
5463
5576
|
if (type === 'updated' && this._keyedArrays.has(identifier.lid)) {
|
|
5464
5577
|
const array = this._keyedArrays.get(identifier.lid);
|
|
5465
5578
|
this.dirtyArray(array, 0, true);
|
|
5466
5579
|
}
|
|
5467
5580
|
});
|
|
5581
|
+
this._subscribeToResourceChanges();
|
|
5582
|
+
}
|
|
5583
|
+
_subscribeToResourceChanges() {
|
|
5468
5584
|
this._subscription = this.store.notifications.subscribe('resource', (identifier, type) => {
|
|
5469
5585
|
const schema = this.store.schema.resource?.(identifier);
|
|
5470
5586
|
// If we are a polaris mode schema
|
|
@@ -5488,8 +5604,8 @@ class RecordArrayManager {
|
|
|
5488
5604
|
}
|
|
5489
5605
|
_syncArray(array) {
|
|
5490
5606
|
const pending = this._pending.get(array);
|
|
5491
|
-
const
|
|
5492
|
-
if (
|
|
5607
|
+
const isLegacyQuery = isLegacyQueryArray(array);
|
|
5608
|
+
if (isLegacyQuery && !pending || this.isDestroying || this.isDestroyed) {
|
|
5493
5609
|
return;
|
|
5494
5610
|
}
|
|
5495
5611
|
|
|
@@ -5500,16 +5616,18 @@ class RecordArrayManager {
|
|
|
5500
5616
|
}
|
|
5501
5617
|
|
|
5502
5618
|
// then pull new state if required
|
|
5503
|
-
if (
|
|
5504
|
-
const
|
|
5619
|
+
if (!isLegacyQuery && !isLegacyLiveArray(array)) {
|
|
5620
|
+
const context = array[Context];
|
|
5621
|
+
const signal = context.signal;
|
|
5622
|
+
const identifier = context.options.requestKey;
|
|
5505
5623
|
|
|
5506
5624
|
// we only need to rebuild the array from cache if a full sync is required
|
|
5507
5625
|
// due to notification that the cache has changed
|
|
5508
5626
|
if (signal.value === 'cache-sync') {
|
|
5509
|
-
const doc = this.store.cache.peek(
|
|
5627
|
+
const doc = this.store.cache.peek(identifier);
|
|
5510
5628
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5511
5629
|
if (!test) {
|
|
5512
|
-
throw new Error(`Expected to find a document for ${
|
|
5630
|
+
throw new Error(`Expected to find a document for ${identifier.lid} but found none`);
|
|
5513
5631
|
}
|
|
5514
5632
|
})(doc) : {};
|
|
5515
5633
|
const data = !('data' in doc) || !Array.isArray(doc.data) ? [] : doc.data;
|
|
@@ -5544,12 +5662,11 @@ class RecordArrayManager {
|
|
|
5544
5662
|
this._staged.delete(type);
|
|
5545
5663
|
}
|
|
5546
5664
|
if (!array) {
|
|
5547
|
-
array =
|
|
5548
|
-
type,
|
|
5549
|
-
identifiers,
|
|
5665
|
+
array = createLegacyLiveArray({
|
|
5550
5666
|
store: this.store,
|
|
5551
|
-
|
|
5552
|
-
|
|
5667
|
+
manager: this,
|
|
5668
|
+
source: identifiers,
|
|
5669
|
+
type
|
|
5553
5670
|
});
|
|
5554
5671
|
this._live.set(type, array);
|
|
5555
5672
|
this._set.set(array, new Set(identifiers));
|
|
@@ -5557,37 +5674,55 @@ class RecordArrayManager {
|
|
|
5557
5674
|
return array;
|
|
5558
5675
|
}
|
|
5559
5676
|
getCollection(config) {
|
|
5560
|
-
if (config
|
|
5561
|
-
return this._keyedArrays.get(config.
|
|
5562
|
-
}
|
|
5563
|
-
const options = {
|
|
5564
|
-
type: config.type,
|
|
5565
|
-
identifier: config.identifier || null,
|
|
5566
|
-
links: config.doc?.links || null,
|
|
5567
|
-
meta: config.doc?.meta || null,
|
|
5568
|
-
query: config.query || null,
|
|
5569
|
-
identifiers: config.identifiers || [],
|
|
5570
|
-
isLoaded: !!config.identifiers?.length,
|
|
5571
|
-
allowMutation: false,
|
|
5572
|
-
store: this.store,
|
|
5573
|
-
manager: this
|
|
5574
|
-
};
|
|
5575
|
-
const array = new Collection(options);
|
|
5576
|
-
this._managed.add(array);
|
|
5577
|
-
this._set.set(array, new Set(options.identifiers || []));
|
|
5578
|
-
if (config.identifier) {
|
|
5579
|
-
this._keyedArrays.set(config.identifier.lid, array);
|
|
5677
|
+
if ('requestKey' in config && this._keyedArrays.has(config.requestKey.lid)) {
|
|
5678
|
+
return this._keyedArrays.get(config.requestKey.lid);
|
|
5580
5679
|
}
|
|
5581
|
-
|
|
5582
|
-
|
|
5680
|
+
let array = null;
|
|
5681
|
+
if ('requestKey' in config) {
|
|
5682
|
+
const options = {
|
|
5683
|
+
store: this.store,
|
|
5684
|
+
manager: this,
|
|
5685
|
+
source: config.source,
|
|
5686
|
+
options: {
|
|
5687
|
+
requestKey: config.requestKey
|
|
5688
|
+
}
|
|
5689
|
+
};
|
|
5690
|
+
array = createRequestCollection(options);
|
|
5691
|
+
this._keyedArrays.set(config.requestKey.lid, array);
|
|
5692
|
+
this._set.set(array, new Set(config.source));
|
|
5693
|
+
associate(this._identifiers, array, config.source);
|
|
5694
|
+
} else if ('query' in config) {
|
|
5695
|
+
const options = {
|
|
5696
|
+
store: this.store,
|
|
5697
|
+
manager: this,
|
|
5698
|
+
source: [],
|
|
5699
|
+
type: config.type,
|
|
5700
|
+
query: config.query,
|
|
5701
|
+
isLoaded: false,
|
|
5702
|
+
links: null,
|
|
5703
|
+
meta: null
|
|
5704
|
+
};
|
|
5705
|
+
array = createLegacyQueryArray(options);
|
|
5706
|
+
this._set.set(array, new Set());
|
|
5707
|
+
} else {
|
|
5708
|
+
const options = {
|
|
5709
|
+
store: this.store,
|
|
5710
|
+
manager: this,
|
|
5711
|
+
source: config.source,
|
|
5712
|
+
options: null
|
|
5713
|
+
};
|
|
5714
|
+
array = createRequestCollection(options);
|
|
5715
|
+
this._set.set(array, new Set(config.source));
|
|
5716
|
+
associate(this._identifiers, array, config.source);
|
|
5583
5717
|
}
|
|
5718
|
+
this._managed.add(array);
|
|
5584
5719
|
return array;
|
|
5585
5720
|
}
|
|
5586
5721
|
dirtyArray(array, delta, shouldSyncFromCache) {
|
|
5587
5722
|
if (array === FAKE_ARR) {
|
|
5588
5723
|
return;
|
|
5589
5724
|
}
|
|
5590
|
-
const signal = array[
|
|
5725
|
+
const signal = array[Context].signal;
|
|
5591
5726
|
if (!signal.isStale || delta > 0) {
|
|
5592
5727
|
notifyInternalSignal(signal);
|
|
5593
5728
|
|
|
@@ -5619,7 +5754,7 @@ class RecordArrayManager {
|
|
|
5619
5754
|
|
|
5620
5755
|
// during unloadAll we can ignore removes since we've already
|
|
5621
5756
|
// cleared the array.
|
|
5622
|
-
if (liveArray && liveArray[
|
|
5757
|
+
if (liveArray && liveArray[Context].source.length === 0 && isRemove) {
|
|
5623
5758
|
const pendingLive = allPending.get(liveArray);
|
|
5624
5759
|
if (!pendingLive || pendingLive.size === 0) {
|
|
5625
5760
|
return pending;
|
|
@@ -5646,7 +5781,7 @@ class RecordArrayManager {
|
|
|
5646
5781
|
}
|
|
5647
5782
|
populateManagedArray(array, identifiers, payload) {
|
|
5648
5783
|
this._pending.delete(array);
|
|
5649
|
-
const source = array[
|
|
5784
|
+
const source = array[Context].source;
|
|
5650
5785
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5651
5786
|
if (!test) {
|
|
5652
5787
|
throw new Error(`The new state of the collection should not be using the same array reference as the original state.`);
|
|
@@ -5656,12 +5791,12 @@ class RecordArrayManager {
|
|
|
5656
5791
|
source.length = 0;
|
|
5657
5792
|
fastPush(source, identifiers);
|
|
5658
5793
|
this._set.set(array, new Set(identifiers));
|
|
5659
|
-
if (
|
|
5660
|
-
notifyInternalSignal(array[
|
|
5794
|
+
if (isLegacyQueryArray(array)) {
|
|
5795
|
+
notifyInternalSignal(array[Context].signal);
|
|
5661
5796
|
array.meta = payload?.meta || null;
|
|
5662
5797
|
array.links = payload?.links || null;
|
|
5798
|
+
array.isLoaded = true;
|
|
5663
5799
|
}
|
|
5664
|
-
array.isLoaded = true;
|
|
5665
5800
|
disassociate(this._identifiers, array, old);
|
|
5666
5801
|
associate(this._identifiers, array, identifiers);
|
|
5667
5802
|
}
|
|
@@ -5707,21 +5842,34 @@ class RecordArrayManager {
|
|
|
5707
5842
|
this.identifierRemoved(identifier);
|
|
5708
5843
|
}
|
|
5709
5844
|
}
|
|
5845
|
+
pause() {
|
|
5846
|
+
this.store.notifications.unsubscribe(this._subscription);
|
|
5847
|
+
}
|
|
5848
|
+
resume() {
|
|
5849
|
+
this._subscribeToResourceChanges();
|
|
5850
|
+
}
|
|
5710
5851
|
clear(isClear = true) {
|
|
5711
|
-
|
|
5712
|
-
|
|
5852
|
+
for (const array of this._live.values()) {
|
|
5853
|
+
array.destroy(isClear);
|
|
5854
|
+
}
|
|
5855
|
+
for (const array of this._managed.values()) {
|
|
5856
|
+
array.destroy(isClear);
|
|
5857
|
+
}
|
|
5713
5858
|
this._managed.clear();
|
|
5714
5859
|
this._identifiers.clear();
|
|
5715
5860
|
this._pending.clear();
|
|
5716
|
-
|
|
5861
|
+
for (const set of this._set.values()) {
|
|
5862
|
+
set.clear();
|
|
5863
|
+
}
|
|
5717
5864
|
this._visibilitySet.clear();
|
|
5718
5865
|
}
|
|
5719
5866
|
destroy() {
|
|
5720
5867
|
this.isDestroying = true;
|
|
5721
5868
|
this.clear(false);
|
|
5722
5869
|
this._live.clear();
|
|
5723
|
-
this.isDestroyed = true;
|
|
5724
5870
|
this.store.notifications.unsubscribe(this._subscription);
|
|
5871
|
+
this.store.notifications.unsubscribe(this._documentSubscription);
|
|
5872
|
+
this.isDestroyed = true;
|
|
5725
5873
|
}
|
|
5726
5874
|
}
|
|
5727
5875
|
function associate(ArraysCache, array, identifiers) {
|
|
@@ -5747,7 +5895,7 @@ function disassociateIdentifier(ArraysCache, array, identifier) {
|
|
|
5747
5895
|
}
|
|
5748
5896
|
}
|
|
5749
5897
|
function sync(array, changes, arraySet) {
|
|
5750
|
-
const state = array[
|
|
5898
|
+
const state = array[Context].source;
|
|
5751
5899
|
const adds = [];
|
|
5752
5900
|
const removes = [];
|
|
5753
5901
|
changes.forEach((value, key) => {
|
|
@@ -5793,8 +5941,13 @@ function sync(array, changes, arraySet) {
|
|
|
5793
5941
|
*/
|
|
5794
5942
|
}
|
|
5795
5943
|
}
|
|
5796
|
-
function
|
|
5797
|
-
|
|
5944
|
+
function isLegacyQueryArray(array) {
|
|
5945
|
+
const context = array[Context];
|
|
5946
|
+
return context.features !== null && context.features.DEPRECATED_CLASS_NAME === 'LegacyQueryArray';
|
|
5947
|
+
}
|
|
5948
|
+
function isLegacyLiveArray(array) {
|
|
5949
|
+
const context = array[Context];
|
|
5950
|
+
return context.features !== null && context.features.DEPRECATED_CLASS_NAME === 'LiveArray';
|
|
5798
5951
|
}
|
|
5799
5952
|
const Touching = getOrSetGlobal('Touching', Symbol('touching'));
|
|
5800
5953
|
const RequestPromise = getOrSetGlobal('RequestPromise', Symbol('promise'));
|
|
@@ -6846,7 +6999,9 @@ class Store extends BaseClass {
|
|
|
6846
6999
|
}
|
|
6847
7000
|
})(!type || typeof type === 'string') : {};
|
|
6848
7001
|
this._join(() => {
|
|
7002
|
+
this._enableAsyncFlush = true;
|
|
6849
7003
|
if (type === undefined) {
|
|
7004
|
+
this.recordArrayManager.pause();
|
|
6850
7005
|
// destroy the graph before unloadAll
|
|
6851
7006
|
// since then we avoid churning relationships
|
|
6852
7007
|
// during unload
|
|
@@ -6856,6 +7011,11 @@ class Store extends BaseClass {
|
|
|
6856
7011
|
} else {
|
|
6857
7012
|
this._instanceCache.clear(normalizeModelName(type));
|
|
6858
7013
|
}
|
|
7014
|
+
this._enableAsyncFlush = null;
|
|
7015
|
+
this.notifications._flush();
|
|
7016
|
+
if (type === undefined) {
|
|
7017
|
+
this.recordArrayManager.resume();
|
|
7018
|
+
}
|
|
6859
7019
|
});
|
|
6860
7020
|
}
|
|
6861
7021
|
|
|
@@ -7058,7 +7218,7 @@ class Store extends BaseClass {
|
|
|
7058
7218
|
this.notifications.destroy();
|
|
7059
7219
|
this.recordArrayManager.destroy();
|
|
7060
7220
|
this.identifierCache.destroy();
|
|
7061
|
-
this.
|
|
7221
|
+
this._instanceCache.clear();
|
|
7062
7222
|
this.isDestroyed = true;
|
|
7063
7223
|
}
|
|
7064
7224
|
|
|
@@ -8027,7 +8187,7 @@ const CacheHandler = {
|
|
|
8027
8187
|
if (identifier) {
|
|
8028
8188
|
promise = promise.finally(() => {
|
|
8029
8189
|
DEDUPE.delete(identifier);
|
|
8030
|
-
store.notifications.notify(identifier, 'state');
|
|
8190
|
+
store.notifications.notify(identifier, 'state', null);
|
|
8031
8191
|
});
|
|
8032
8192
|
DEDUPE.set(identifier, {
|
|
8033
8193
|
priority: {
|
|
@@ -8035,7 +8195,7 @@ const CacheHandler = {
|
|
|
8035
8195
|
},
|
|
8036
8196
|
promise
|
|
8037
8197
|
});
|
|
8038
|
-
store.notifications.notify(identifier, 'state');
|
|
8198
|
+
store.notifications.notify(identifier, 'state', null);
|
|
8039
8199
|
}
|
|
8040
8200
|
return promise;
|
|
8041
8201
|
}
|
|
@@ -8048,7 +8208,7 @@ const CacheHandler = {
|
|
|
8048
8208
|
if (identifier && !activeRequest) {
|
|
8049
8209
|
promise = promise.finally(() => {
|
|
8050
8210
|
DEDUPE.delete(identifier);
|
|
8051
|
-
store.notifications.notify(identifier, 'state');
|
|
8211
|
+
store.notifications.notify(identifier, 'state', null);
|
|
8052
8212
|
});
|
|
8053
8213
|
DEDUPE.set(identifier, {
|
|
8054
8214
|
priority: {
|
|
@@ -8056,7 +8216,7 @@ const CacheHandler = {
|
|
|
8056
8216
|
},
|
|
8057
8217
|
promise
|
|
8058
8218
|
});
|
|
8059
|
-
store.notifications.notify(identifier, 'state');
|
|
8219
|
+
store.notifications.notify(identifier, 'state', null);
|
|
8060
8220
|
}
|
|
8061
8221
|
store.requestManager._pending.set(context.id, promise);
|
|
8062
8222
|
}
|
|
@@ -8287,6 +8447,47 @@ function constructResource(type, id, lid) {
|
|
|
8287
8447
|
};
|
|
8288
8448
|
}
|
|
8289
8449
|
}
|
|
8450
|
+
|
|
8451
|
+
/**
|
|
8452
|
+
* The options for {@link createLegacyManyArray}
|
|
8453
|
+
*
|
|
8454
|
+
* @internal
|
|
8455
|
+
*/
|
|
8456
|
+
/**
|
|
8457
|
+
* Creates a {@link LegacyManyArray}
|
|
8458
|
+
*
|
|
8459
|
+
* @internal
|
|
8460
|
+
*/
|
|
8461
|
+
function createLegacyManyArray(options) {
|
|
8462
|
+
const extensions = options.store.schema.CAUTION_MEGA_DANGER_ZONE_arrayExtensions ? options.store.schema.CAUTION_MEGA_DANGER_ZONE_arrayExtensions(options.field) : null;
|
|
8463
|
+
return createReactiveResourceArray({
|
|
8464
|
+
store: options.store,
|
|
8465
|
+
manager: options.manager,
|
|
8466
|
+
editable: options.editable,
|
|
8467
|
+
source: options.source,
|
|
8468
|
+
data: {
|
|
8469
|
+
links: options.links,
|
|
8470
|
+
meta: options.meta
|
|
8471
|
+
},
|
|
8472
|
+
features: {
|
|
8473
|
+
modelName: options.type,
|
|
8474
|
+
save,
|
|
8475
|
+
DEPRECATED_CLASS_NAME: 'ManyArray',
|
|
8476
|
+
isLoaded: options.isLoaded,
|
|
8477
|
+
isAsync: options.isAsync,
|
|
8478
|
+
isPolymorphic: options.isPolymorphic,
|
|
8479
|
+
identifier: options.identifier,
|
|
8480
|
+
key: options.field.name,
|
|
8481
|
+
reload,
|
|
8482
|
+
createRecord,
|
|
8483
|
+
notify
|
|
8484
|
+
},
|
|
8485
|
+
extensions,
|
|
8486
|
+
options: null,
|
|
8487
|
+
destroy: destroyLegacyManyArray,
|
|
8488
|
+
mutate: _MUTATE
|
|
8489
|
+
});
|
|
8490
|
+
}
|
|
8290
8491
|
function _MUTATE(target, receiver, prop, args, _SIGNAL) {
|
|
8291
8492
|
const collection = receiver;
|
|
8292
8493
|
switch (prop) {
|
|
@@ -8409,7 +8610,7 @@ function _MUTATE(target, receiver, prop, args, _SIGNAL) {
|
|
|
8409
8610
|
const [start, deleteCount, ...adds] = args;
|
|
8410
8611
|
|
|
8411
8612
|
// detect a full replace
|
|
8412
|
-
if (start === 0 && deleteCount === collection[
|
|
8613
|
+
if (start === 0 && deleteCount === collection[Context].source.length) {
|
|
8413
8614
|
const newValues = extractIdentifiersFromRecords(adds);
|
|
8414
8615
|
assertNoDuplicates(collection, target, currentState => currentState.splice(start, deleteCount, ...newValues), `Cannot replace a hasMany's state with a new state that contains duplicates.`);
|
|
8415
8616
|
if (macroCondition(getGlobalConfig().WarpDrive.deprecations.DEPRECATE_MANY_ARRAY_DUPLICATES)) {
|
|
@@ -8483,190 +8684,37 @@ function _MUTATE(target, receiver, prop, args, _SIGNAL) {
|
|
|
8483
8684
|
})() : {};
|
|
8484
8685
|
}
|
|
8485
8686
|
}
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
Often, the relationships in Ember Data applications will have
|
|
8498
|
-
an inverse. For example, imagine the following models are
|
|
8499
|
-
defined:
|
|
8500
|
-
|
|
8501
|
-
```js [app/models/post.js]
|
|
8502
|
-
import Model, { hasMany } from '@ember-data/model';
|
|
8503
|
-
|
|
8504
|
-
export default class PostModel extends Model {
|
|
8505
|
-
@hasMany('comment') comments;
|
|
8506
|
-
}
|
|
8507
|
-
```
|
|
8508
|
-
|
|
8509
|
-
```js [app/models/comment.js]
|
|
8510
|
-
import { Model, belongsTo } from '@warp-drive/legacy/model';
|
|
8511
|
-
|
|
8512
|
-
export default class CommentModel extends Model {
|
|
8513
|
-
@belongsTo('post') post;
|
|
8514
|
-
}
|
|
8515
|
-
```
|
|
8516
|
-
|
|
8517
|
-
If you created a new instance of `Post` and added
|
|
8518
|
-
a `Comment` record to its `comments` has-many
|
|
8519
|
-
relationship, you would expect the comment's `post`
|
|
8520
|
-
property to be set to the post that contained
|
|
8521
|
-
the has-many.
|
|
8522
|
-
|
|
8523
|
-
We call the record to which a relationship belongs-to the
|
|
8524
|
-
relationship's _owner_.
|
|
8525
|
-
|
|
8526
|
-
@class ManyArray
|
|
8527
|
-
@public
|
|
8528
|
-
*/
|
|
8529
|
-
class RelatedCollection extends IdentifierArray {
|
|
8530
|
-
/**
|
|
8531
|
-
The loading state of this array
|
|
8532
|
-
@property isLoaded
|
|
8533
|
-
@type {Boolean}
|
|
8534
|
-
@public
|
|
8535
|
-
*/
|
|
8536
|
-
|
|
8537
|
-
/**
|
|
8538
|
-
`true` if the relationship is polymorphic, `false` otherwise.
|
|
8539
|
-
@property isPolymorphic
|
|
8540
|
-
@type {Boolean}
|
|
8541
|
-
@private
|
|
8542
|
-
*/
|
|
8543
|
-
|
|
8544
|
-
/**
|
|
8545
|
-
Metadata associated with the request for async hasMany relationships.
|
|
8546
|
-
Example
|
|
8547
|
-
Given that the server returns the following JSON payload when fetching a
|
|
8548
|
-
hasMany relationship:
|
|
8549
|
-
```js
|
|
8550
|
-
{
|
|
8551
|
-
"comments": [{
|
|
8552
|
-
"id": 1,
|
|
8553
|
-
"comment": "This is the first comment",
|
|
8554
|
-
}, {
|
|
8555
|
-
// ...
|
|
8556
|
-
}],
|
|
8557
|
-
"meta": {
|
|
8558
|
-
"page": 1,
|
|
8559
|
-
"total": 5
|
|
8560
|
-
}
|
|
8687
|
+
function notify() {
|
|
8688
|
+
notifyInternalSignal(this[Context].signal);
|
|
8689
|
+
}
|
|
8690
|
+
function reload(options) {
|
|
8691
|
+
const {
|
|
8692
|
+
manager
|
|
8693
|
+
} = this[Context];
|
|
8694
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
8695
|
+
if (!test) {
|
|
8696
|
+
throw new Error(`Expected the manager for ManyArray to implement reloadHasMany`);
|
|
8561
8697
|
}
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
|
|
8580
|
-
|
|
8581
|
-
*/
|
|
8582
|
-
|
|
8583
|
-
constructor(options) {
|
|
8584
|
-
options[MUTATE] = _MUTATE;
|
|
8585
|
-
super(options);
|
|
8586
|
-
this.isLoaded = options.isLoaded || false;
|
|
8587
|
-
this.isAsync = options.isAsync || false;
|
|
8588
|
-
this.isPolymorphic = options.isPolymorphic || false;
|
|
8589
|
-
this.identifier = options.identifier;
|
|
8590
|
-
this.key = options.key;
|
|
8591
|
-
}
|
|
8592
|
-
notify() {
|
|
8593
|
-
notifyInternalSignal(this[ARRAY_SIGNAL]);
|
|
8594
|
-
}
|
|
8595
|
-
|
|
8596
|
-
/**
|
|
8597
|
-
Reloads all of the records in the manyArray. If the manyArray
|
|
8598
|
-
holds a relationship that was originally fetched using a links url
|
|
8599
|
-
WarpDrive will revisit the original links url to repopulate the
|
|
8600
|
-
relationship.
|
|
8601
|
-
If the ManyArray holds the result of a `store.query()` reload will
|
|
8602
|
-
re-run the original query.
|
|
8603
|
-
Example
|
|
8604
|
-
```javascript
|
|
8605
|
-
let user = store.peekRecord('user', '1')
|
|
8606
|
-
await login(user);
|
|
8607
|
-
let permissions = await user.permissions;
|
|
8608
|
-
await permissions.reload();
|
|
8609
|
-
```
|
|
8610
|
-
@public
|
|
8611
|
-
*/
|
|
8612
|
-
reload(options) {
|
|
8613
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
8614
|
-
if (!test) {
|
|
8615
|
-
throw new Error(`Expected the manager for ManyArray to implement reloadHasMany`);
|
|
8616
|
-
}
|
|
8617
|
-
})(typeof this._manager.reloadHasMany === 'function') : {};
|
|
8618
|
-
// TODO this is odd, we don't ask the store for anything else like this?
|
|
8619
|
-
return this._manager.reloadHasMany(this.key, options);
|
|
8620
|
-
}
|
|
8621
|
-
|
|
8622
|
-
/**
|
|
8623
|
-
Create a child record within the owner
|
|
8624
|
-
@public
|
|
8625
|
-
@param {Object} hash
|
|
8626
|
-
@return {Model} record
|
|
8627
|
-
*/
|
|
8628
|
-
createRecord(hash) {
|
|
8629
|
-
const {
|
|
8630
|
-
store
|
|
8631
|
-
} = this;
|
|
8632
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
8633
|
-
if (!test) {
|
|
8634
|
-
throw new Error(`Expected modelName to be set`);
|
|
8635
|
-
}
|
|
8636
|
-
})(this.modelName) : {};
|
|
8637
|
-
const record = store.createRecord(this.modelName, hash);
|
|
8638
|
-
this.push(record);
|
|
8639
|
-
return record;
|
|
8640
|
-
}
|
|
8641
|
-
|
|
8642
|
-
/**
|
|
8643
|
-
Saves all of the records in the `ManyArray`.
|
|
8644
|
-
Note: this API can only be used in legacy mode with a configured Adapter.
|
|
8645
|
-
Example
|
|
8646
|
-
```javascript
|
|
8647
|
-
const { content: { data: inbox } } = await store.request(findRecord({ type: 'inbox', id: '1' }));
|
|
8648
|
-
let messages = await inbox.messages;
|
|
8649
|
-
messages.forEach((message) => {
|
|
8650
|
-
message.isRead = true;
|
|
8651
|
-
});
|
|
8652
|
-
messages.save();
|
|
8653
|
-
```
|
|
8654
|
-
@public
|
|
8655
|
-
@return {PromiseArray} promise
|
|
8656
|
-
*/
|
|
8657
|
-
|
|
8658
|
-
/** @internal */
|
|
8659
|
-
destroy() {
|
|
8660
|
-
super.destroy(false);
|
|
8661
|
-
}
|
|
8698
|
+
})(typeof manager.reloadHasMany === 'function') : {};
|
|
8699
|
+
// TODO this is odd, we don't ask the store for anything else like this?
|
|
8700
|
+
return manager.reloadHasMany(this.key, options);
|
|
8701
|
+
}
|
|
8702
|
+
function createRecord(hash) {
|
|
8703
|
+
const {
|
|
8704
|
+
store
|
|
8705
|
+
} = this[Context];
|
|
8706
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
8707
|
+
if (!test) {
|
|
8708
|
+
throw new Error(`Expected modelName to be set`);
|
|
8709
|
+
}
|
|
8710
|
+
})(this.modelName) : {};
|
|
8711
|
+
const record = store.createRecord(this.modelName, hash);
|
|
8712
|
+
this.push(record);
|
|
8713
|
+
return record;
|
|
8714
|
+
}
|
|
8715
|
+
function destroyLegacyManyArray() {
|
|
8716
|
+
destroy.call(this, false);
|
|
8662
8717
|
}
|
|
8663
|
-
RelatedCollection.prototype.isAsync = false;
|
|
8664
|
-
RelatedCollection.prototype.isPolymorphic = false;
|
|
8665
|
-
RelatedCollection.prototype.identifier = null;
|
|
8666
|
-
RelatedCollection.prototype.cache = null;
|
|
8667
|
-
RelatedCollection.prototype._inverseIsAsync = false;
|
|
8668
|
-
RelatedCollection.prototype.key = '';
|
|
8669
|
-
RelatedCollection.prototype.DEPRECATED_CLASS_NAME = 'ManyArray';
|
|
8670
8718
|
function assertRecordPassedToHasMany(record) {
|
|
8671
8719
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
8672
8720
|
if (!test) {
|
|
@@ -8689,12 +8737,13 @@ function extractIdentifierFromRecord(recordOrPromiseRecord) {
|
|
|
8689
8737
|
return recordIdentifierFor(recordOrPromiseRecord);
|
|
8690
8738
|
}
|
|
8691
8739
|
function assertNoDuplicates(collection, target, callback, reason) {
|
|
8740
|
+
const identifier = collection[Context].features.identifier;
|
|
8692
8741
|
const state = target.slice();
|
|
8693
8742
|
callback(state);
|
|
8694
8743
|
if (state.length !== new Set(state).size) {
|
|
8695
8744
|
const duplicates = state.filter((currentValue, currentIndex) => state.indexOf(currentValue) !== currentIndex);
|
|
8696
8745
|
if (macroCondition(getGlobalConfig().WarpDrive.deprecations.DEPRECATE_MANY_ARRAY_DUPLICATES)) {
|
|
8697
|
-
deprecate(`${reason} This behavior is deprecated. Found duplicates for the following records within the new state provided to \`<${
|
|
8746
|
+
deprecate(`${reason} This behavior is deprecated. Found duplicates for the following records within the new state provided to \`<${identifier.type}:${identifier.id || identifier.lid}>.${collection.key}\`\n\t- ${Array.from(new Set(duplicates)).map(r => isStableIdentifier(r) ? r.lid : recordIdentifierFor(r).lid).sort((a, b) => a.localeCompare(b)).join('\n\t- ')}`, false, {
|
|
8698
8747
|
id: 'ember-data:deprecate-many-array-duplicates',
|
|
8699
8748
|
for: 'ember-data',
|
|
8700
8749
|
until: '6.0',
|
|
@@ -8704,62 +8753,75 @@ function assertNoDuplicates(collection, target, callback, reason) {
|
|
|
8704
8753
|
}
|
|
8705
8754
|
});
|
|
8706
8755
|
} else {
|
|
8707
|
-
throw new Error(`${reason} Found duplicates for the following records within the new state provided to \`<${
|
|
8756
|
+
throw new Error(`${reason} Found duplicates for the following records within the new state provided to \`<${identifier.type}:${identifier.id || identifier.lid}>.${collection.key}\`\n\t- ${Array.from(new Set(duplicates)).map(r => isStableIdentifier(r) ? r.lid : recordIdentifierFor(r).lid).sort((a, b) => a.localeCompare(b)).join('\n\t- ')}`);
|
|
8708
8757
|
}
|
|
8709
8758
|
}
|
|
8710
8759
|
}
|
|
8711
8760
|
function mutateAddToRelatedRecords(collection, operationInfo, _SIGNAL) {
|
|
8761
|
+
const identifier = collection[Context].features.identifier;
|
|
8762
|
+
|
|
8712
8763
|
// FIXME field needs to use sourceKey
|
|
8713
8764
|
mutate(collection, {
|
|
8714
8765
|
op: 'add',
|
|
8715
|
-
record:
|
|
8766
|
+
record: identifier,
|
|
8716
8767
|
field: collection.key,
|
|
8717
8768
|
...operationInfo
|
|
8718
8769
|
}, _SIGNAL);
|
|
8719
8770
|
}
|
|
8720
8771
|
function mutateRemoveFromRelatedRecords(collection, operationInfo, _SIGNAL) {
|
|
8772
|
+
const identifier = collection[Context].features.identifier;
|
|
8773
|
+
|
|
8721
8774
|
// FIXME field needs to use sourceKey
|
|
8722
8775
|
mutate(collection, {
|
|
8723
8776
|
op: 'remove',
|
|
8724
|
-
record:
|
|
8777
|
+
record: identifier,
|
|
8725
8778
|
field: collection.key,
|
|
8726
8779
|
...operationInfo
|
|
8727
8780
|
}, _SIGNAL);
|
|
8728
8781
|
}
|
|
8729
8782
|
function mutateReplaceRelatedRecord(collection, operationInfo, _SIGNAL) {
|
|
8783
|
+
const identifier = collection[Context].features.identifier;
|
|
8784
|
+
|
|
8730
8785
|
// FIXME field needs to use sourceKey
|
|
8731
8786
|
mutate(collection, {
|
|
8732
8787
|
op: 'replaceRelatedRecord',
|
|
8733
|
-
record:
|
|
8788
|
+
record: identifier,
|
|
8734
8789
|
field: collection.key,
|
|
8735
8790
|
...operationInfo
|
|
8736
8791
|
}, _SIGNAL);
|
|
8737
8792
|
}
|
|
8738
8793
|
function mutateReplaceRelatedRecords(collection, value, _SIGNAL) {
|
|
8794
|
+
const identifier = collection[Context].features.identifier;
|
|
8795
|
+
|
|
8739
8796
|
// FIXME field needs to use sourceKey
|
|
8740
8797
|
mutate(collection, {
|
|
8741
8798
|
op: 'replaceRelatedRecords',
|
|
8742
|
-
record:
|
|
8799
|
+
record: identifier,
|
|
8743
8800
|
field: collection.key,
|
|
8744
8801
|
value
|
|
8745
8802
|
}, _SIGNAL);
|
|
8746
8803
|
}
|
|
8747
8804
|
function mutateSortRelatedRecords(collection, value, _SIGNAL) {
|
|
8805
|
+
const identifier = collection[Context].features.identifier;
|
|
8806
|
+
|
|
8748
8807
|
// FIXME field needs to use sourceKey
|
|
8749
8808
|
mutate(collection, {
|
|
8750
8809
|
op: 'sortRelatedRecords',
|
|
8751
|
-
record:
|
|
8810
|
+
record: identifier,
|
|
8752
8811
|
field: collection.key,
|
|
8753
8812
|
value
|
|
8754
8813
|
}, _SIGNAL);
|
|
8755
8814
|
}
|
|
8756
8815
|
function mutate(collection, mutation, _SIGNAL) {
|
|
8816
|
+
const {
|
|
8817
|
+
manager
|
|
8818
|
+
} = collection[Context];
|
|
8757
8819
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
8758
8820
|
if (!test) {
|
|
8759
8821
|
throw new Error(`Expected the manager for ManyArray to implement mutate`);
|
|
8760
8822
|
}
|
|
8761
|
-
})(typeof
|
|
8762
|
-
|
|
8823
|
+
})(typeof manager.mutate === 'function') : {};
|
|
8824
|
+
manager.mutate(mutation);
|
|
8763
8825
|
notifyInternalSignal(_SIGNAL);
|
|
8764
8826
|
}
|
|
8765
8827
|
const PromiseCache = new WeakMap();
|
|
@@ -9941,4 +10003,4 @@ function getRequestState(future) {
|
|
|
9941
10003
|
}
|
|
9942
10004
|
return state;
|
|
9943
10005
|
}
|
|
9944
|
-
export {
|
|
10006
|
+
export { notifyInternalSignal as A, consumeInternalSignal as B, CacheHandler as C, DISPOSE as D, getOrCreateInternalSignal as E, ReactiveResource as F, isNonIdentityCacheableField as G, getFieldCacheKeyStrict as H, setIdentifierGenerationMethod as I, setIdentifierUpdateMethod as J, setIdentifierForgetMethod as K, setIdentifierResetMethod as L, setKeyInfoForResource as M, RecordArrayManager as R, Store as S, _clearCaches as _, isDocumentIdentifier as a, coerceId as b, constructResource as c, setRecordIdentifier as d, ensureStringId as e, fastPush as f, StoreMap as g, createLegacyManyArray as h, isStableIdentifier as i, logGroup as j, getPromiseState as k, log as l, createRequestSubscription as m, normalizeModelName as n, getRequestState as o, memoized as p, gate as q, recordIdentifierFor as r, storeFor as s, entangleSignal as t, defineSignal as u, defineGate as v, defineNonEnumerableSignal as w, Signals as x, peekInternalSignal as y, withSignalStore as z };
|