@warp-drive/schema-record 5.4.1-beta.1 → 5.4.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -9
- package/dist/-private.js +1 -1
- package/dist/index.js +96 -86
- package/dist/index.js.map +1 -1
- package/dist/{symbols-DqoS4ybV.js → symbols-B_60yPO2.js} +1 -4
- package/dist/symbols-B_60yPO2.js.map +1 -0
- package/package.json +13 -16
- package/unstable-preview-types/-private/fields/compute.d.ts.map +1 -1
- package/unstable-preview-types/-private/fields/managed-array.d.ts +5 -5
- package/unstable-preview-types/-private/fields/managed-array.d.ts.map +1 -1
- package/unstable-preview-types/-private/fields/managed-object.d.ts +4 -4
- package/unstable-preview-types/-private/fields/managed-object.d.ts.map +1 -1
- package/unstable-preview-types/-private/fields/many-array-manager.d.ts +2 -3
- package/unstable-preview-types/-private/fields/many-array-manager.d.ts.map +1 -1
- package/unstable-preview-types/-private/record.d.ts +0 -2
- package/unstable-preview-types/-private/record.d.ts.map +1 -1
- package/unstable-preview-types/-private/schema.d.ts +19 -6
- package/unstable-preview-types/-private/schema.d.ts.map +1 -1
- package/unstable-preview-types/-private/symbols.d.ts +0 -3
- package/unstable-preview-types/-private/symbols.d.ts.map +1 -1
- package/unstable-preview-types/index.d.ts +5 -3
- package/unstable-preview-types/index.d.ts.map +1 -1
- package/dist/symbols-DqoS4ybV.js.map +0 -1
package/README.md
CHANGED
|
@@ -23,15 +23,9 @@
|
|
|
23
23
|
- ⚛️ Universal
|
|
24
24
|
- ☢️ Reactive
|
|
25
25
|
|
|
26
|
-
SchemaRecord is a reactive object that transforms raw data from an [associated cache](https://github.com/emberjs/data/blob/main/packages/core-types/src/cache.ts) into reactive data backed by Signals.
|
|
26
|
+
SchemaRecord is a reactive object that transforms raw data from an [associated cache](https://github.com/emberjs/data/blob/main/packages/core-types/src/cache.ts) into reactive data backed by Signals. The shape of the object and the transformation of raw cache data into its reactive form is controlled by a resource schema. Resource schemas are simple JSON, allowing them to be defined and delivered from anywhere.
|
|
27
27
|
|
|
28
|
-
The
|
|
29
|
-
reactive form is controlled by a resource schema.
|
|
30
|
-
|
|
31
|
-
Resource schemas are simple JSON, allowing them to be defined and delivered from anywhere.
|
|
32
|
-
|
|
33
|
-
The capabilities that SchemaRecord brings to [*Warp***Drive**](https://github.com/emberjs/data/)
|
|
34
|
-
will simplify even the most complex parts of your app's state management.
|
|
28
|
+
The capabilities that SchemaRecord brings to [*Warp***Drive**](https://github.com/emberjs/data/) will simplify even the most complex parts of your app's state management.
|
|
35
29
|
|
|
36
30
|
## Installation
|
|
37
31
|
|
|
@@ -266,7 +260,9 @@ store.schema.registerResources([
|
|
|
266
260
|
options: {
|
|
267
261
|
async: false,
|
|
268
262
|
inverse: 'owner',
|
|
269
|
-
polymorphic: true
|
|
263
|
+
polymorphic: true,
|
|
264
|
+
linksMode: true,
|
|
265
|
+
resetOnRemoteUpdate: false
|
|
270
266
|
}
|
|
271
267
|
}
|
|
272
268
|
]
|
|
@@ -283,6 +279,8 @@ store.schema.registerResources([
|
|
|
283
279
|
async: false,
|
|
284
280
|
inverse: 'pets',
|
|
285
281
|
as: 'pet',
|
|
282
|
+
linksMode: true,
|
|
283
|
+
resetOnRemoteUpdate: false
|
|
286
284
|
}
|
|
287
285
|
}
|
|
288
286
|
]
|
package/dist/-private.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { E as Editable, L as Legacy } from "./symbols-
|
|
1
|
+
export { E as Editable, L as Legacy } from "./symbols-B_60yPO2.js";
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { isResourceSchema } from '@warp-drive/core-types/schema/fields';
|
|
2
2
|
import { macroCondition, getGlobalConfig, dependencySatisfies, importSync } from '@embroider/macros';
|
|
3
|
-
import { SOURCE as SOURCE$1, fastPush, RelatedCollection, setRecordIdentifier, recordIdentifierFor } from '@ember-data/store/-private';
|
|
4
|
-
import { createSignal, subscribe, defineSignal, peekSignal, getSignal, Signals, addToTransaction, entangleSignal } from '@ember-data/tracking/-private';
|
|
3
|
+
import { withSignalStore, entangleSignal, ARRAY_SIGNAL, consumeInternalSignal, OBJECT_SIGNAL, SOURCE as SOURCE$1, fastPush, defineSignal, RelatedCollection, getOrCreateInternalSignal, notifyInternalSignal, Signals, setRecordIdentifier, recordIdentifierFor, createMemo } from '@ember-data/store/-private';
|
|
5
4
|
import { EnableHydration, STRUCTURED } from '@warp-drive/core-types/request';
|
|
6
5
|
import { RecordStore, Type } from '@warp-drive/core-types/symbols';
|
|
7
6
|
import { getOrSetGlobal } from '@warp-drive/core-types/-private';
|
|
8
|
-
import { S as SOURCE,
|
|
7
|
+
import { S as SOURCE, E as Editable, L as Legacy, I as Identifier, P as Parent, a as EmbeddedPath, D as Destroy, C as Checkout, b as EmbeddedType } from "./symbols-B_60yPO2.js";
|
|
9
8
|
import { deprecate } from '@ember/debug';
|
|
10
9
|
import { recordIdentifierFor as recordIdentifierFor$1 } from '@ember-data/store';
|
|
11
|
-
import { createCache, getValue } from '@ember-data/tracking';
|
|
12
10
|
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']);
|
|
13
11
|
// const ARRAY_SETTER_METHODS = new Set<KeyType>(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
|
|
14
12
|
const SYNC_PROPS = new Set(['[]', 'length']);
|
|
@@ -59,10 +57,13 @@ class ManagedArray {
|
|
|
59
57
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
60
58
|
const self = this;
|
|
61
59
|
this[SOURCE] = data?.slice();
|
|
62
|
-
this[ARRAY_SIGNAL] = createSignal(this, 'length');
|
|
63
60
|
const IS_EDITABLE = this[Editable] = editable ?? false;
|
|
64
61
|
this[Legacy] = legacy;
|
|
65
|
-
|
|
62
|
+
|
|
63
|
+
// FIXME probably can get rid of the manual ARRAY_SIGNAL storage
|
|
64
|
+
// FIXME probably the storage should be on the proxy/receiver not this class
|
|
65
|
+
const signals = withSignalStore(this);
|
|
66
|
+
const _SIGNAL = this[ARRAY_SIGNAL] = entangleSignal(signals, this, ARRAY_SIGNAL, undefined);
|
|
66
67
|
const boundFns = new Map();
|
|
67
68
|
this.identifier = identifier;
|
|
68
69
|
this.path = path;
|
|
@@ -90,9 +91,8 @@ class ManagedArray {
|
|
|
90
91
|
return self.owner;
|
|
91
92
|
}
|
|
92
93
|
const index = convertToInt(prop);
|
|
93
|
-
if (_SIGNAL.
|
|
94
|
-
_SIGNAL.
|
|
95
|
-
_SIGNAL.shouldReset = false;
|
|
94
|
+
if (_SIGNAL.isStale && (index !== null || SYNC_PROPS.has(prop) || isArrayGetter(prop))) {
|
|
95
|
+
_SIGNAL.isStale = false;
|
|
96
96
|
const newData = cache.getAttr(identifier, path);
|
|
97
97
|
if (newData && newData !== self[SOURCE]) {
|
|
98
98
|
self[SOURCE].length = 0;
|
|
@@ -139,7 +139,7 @@ class ManagedArray {
|
|
|
139
139
|
}
|
|
140
140
|
if (isSchemaArray) {
|
|
141
141
|
if (!transaction) {
|
|
142
|
-
|
|
142
|
+
consumeInternalSignal(_SIGNAL);
|
|
143
143
|
}
|
|
144
144
|
if (val) {
|
|
145
145
|
const recordRef = ManagedRecordRefs.get(val);
|
|
@@ -171,7 +171,7 @@ class ManagedArray {
|
|
|
171
171
|
return val;
|
|
172
172
|
}
|
|
173
173
|
if (!transaction) {
|
|
174
|
-
|
|
174
|
+
consumeInternalSignal(_SIGNAL);
|
|
175
175
|
}
|
|
176
176
|
if (field.type) {
|
|
177
177
|
const transform = schema.transformation(field);
|
|
@@ -184,7 +184,7 @@ class ManagedArray {
|
|
|
184
184
|
if (fn === undefined) {
|
|
185
185
|
if (prop === 'forEach') {
|
|
186
186
|
fn = function () {
|
|
187
|
-
|
|
187
|
+
consumeInternalSignal(_SIGNAL);
|
|
188
188
|
transaction = true;
|
|
189
189
|
const result = safeForEach(receiver, target, store, arguments[0], arguments[1]);
|
|
190
190
|
transaction = false;
|
|
@@ -192,7 +192,7 @@ class ManagedArray {
|
|
|
192
192
|
};
|
|
193
193
|
} else {
|
|
194
194
|
fn = function () {
|
|
195
|
-
|
|
195
|
+
consumeInternalSignal(_SIGNAL);
|
|
196
196
|
// array functions must run through Reflect to work properly
|
|
197
197
|
// binding via other means will not work.
|
|
198
198
|
transaction = true;
|
|
@@ -212,7 +212,7 @@ class ManagedArray {
|
|
|
212
212
|
if (!IS_EDITABLE) {
|
|
213
213
|
throw new Error(`Mutating this array via ${String(prop)} is not allowed because the record is not editable`);
|
|
214
214
|
}
|
|
215
|
-
|
|
215
|
+
consumeInternalSignal(_SIGNAL);
|
|
216
216
|
transaction = true;
|
|
217
217
|
const result = Reflect.apply(target[prop], receiver, arguments);
|
|
218
218
|
transaction = false;
|
|
@@ -246,7 +246,7 @@ class ManagedArray {
|
|
|
246
246
|
if (reflect) {
|
|
247
247
|
if (!field.type) {
|
|
248
248
|
cache.setAttr(identifier, path, self[SOURCE]);
|
|
249
|
-
_SIGNAL.
|
|
249
|
+
_SIGNAL.isStale = true;
|
|
250
250
|
return true;
|
|
251
251
|
}
|
|
252
252
|
let rawValue = self[SOURCE];
|
|
@@ -258,7 +258,7 @@ class ManagedArray {
|
|
|
258
258
|
rawValue = self[SOURCE].map(item => transform.serialize(item, field.options ?? null, self.owner));
|
|
259
259
|
}
|
|
260
260
|
cache.setAttr(identifier, path, rawValue);
|
|
261
|
-
_SIGNAL.
|
|
261
|
+
_SIGNAL.isStale = true;
|
|
262
262
|
}
|
|
263
263
|
return reflect;
|
|
264
264
|
},
|
|
@@ -283,12 +283,12 @@ class ManagedObject {
|
|
|
283
283
|
this[SOURCE] = {
|
|
284
284
|
...data
|
|
285
285
|
};
|
|
286
|
-
|
|
286
|
+
const signals = withSignalStore(this);
|
|
287
|
+
const _SIGNAL = this[OBJECT_SIGNAL] = entangleSignal(signals, this, OBJECT_SIGNAL, undefined);
|
|
287
288
|
this[Editable] = editable;
|
|
288
289
|
this[Legacy] = legacy;
|
|
289
290
|
this[Parent] = identifier;
|
|
290
291
|
this[EmbeddedPath] = path;
|
|
291
|
-
const _SIGNAL = this[OBJECT_SIGNAL];
|
|
292
292
|
const proxy = new Proxy(this[SOURCE], {
|
|
293
293
|
ownKeys() {
|
|
294
294
|
return Object.keys(self[SOURCE]);
|
|
@@ -331,9 +331,8 @@ class ManagedObject {
|
|
|
331
331
|
return structuredClone(self[SOURCE]);
|
|
332
332
|
};
|
|
333
333
|
}
|
|
334
|
-
if (_SIGNAL.
|
|
335
|
-
_SIGNAL.
|
|
336
|
-
_SIGNAL.shouldReset = false;
|
|
334
|
+
if (_SIGNAL.isStale) {
|
|
335
|
+
_SIGNAL.isStale = false;
|
|
337
336
|
let newData = cache.getAttr(identifier, path);
|
|
338
337
|
if (newData && newData !== self[SOURCE]) {
|
|
339
338
|
if (field.type) {
|
|
@@ -346,7 +345,7 @@ class ManagedObject {
|
|
|
346
345
|
}
|
|
347
346
|
}
|
|
348
347
|
if (prop in self[SOURCE]) {
|
|
349
|
-
|
|
348
|
+
consumeInternalSignal(_SIGNAL);
|
|
350
349
|
return self[SOURCE][prop];
|
|
351
350
|
}
|
|
352
351
|
return Reflect.get(target, prop, receiver);
|
|
@@ -368,7 +367,7 @@ class ManagedObject {
|
|
|
368
367
|
const val = transform.serialize(self[SOURCE], field.options ?? null, owner);
|
|
369
368
|
cache.setAttr(identifier, path, val);
|
|
370
369
|
}
|
|
371
|
-
_SIGNAL.
|
|
370
|
+
_SIGNAL.isStale = true;
|
|
372
371
|
return true;
|
|
373
372
|
}
|
|
374
373
|
});
|
|
@@ -376,13 +375,15 @@ class ManagedObject {
|
|
|
376
375
|
}
|
|
377
376
|
}
|
|
378
377
|
class ManyArrayManager {
|
|
379
|
-
constructor(record) {
|
|
378
|
+
constructor(record, editable) {
|
|
380
379
|
this.record = record;
|
|
381
380
|
this.store = record[RecordStore];
|
|
382
381
|
this.identifier = record[Identifier];
|
|
382
|
+
this.editable = editable;
|
|
383
383
|
}
|
|
384
384
|
_syncArray(array) {
|
|
385
|
-
const
|
|
385
|
+
const method = this.editable ? 'getRelationship' : 'getRemoteRelationship';
|
|
386
|
+
const rawValue = this.store.cache[method](this.identifier, array.key);
|
|
386
387
|
if (rawValue.meta) {
|
|
387
388
|
array.meta = rawValue.meta;
|
|
388
389
|
}
|
|
@@ -428,7 +429,7 @@ class ManyArrayManager {
|
|
|
428
429
|
return this.store.request(req);
|
|
429
430
|
}
|
|
430
431
|
mutate(mutation) {
|
|
431
|
-
this.cache.mutate(mutation);
|
|
432
|
+
this.store.cache.mutate(mutation);
|
|
432
433
|
}
|
|
433
434
|
}
|
|
434
435
|
function getRelatedLink(resource) {
|
|
@@ -453,12 +454,10 @@ function extractCacheOptions(options) {
|
|
|
453
454
|
const ManagedArrayMap = getOrSetGlobal('ManagedArrayMap', new Map());
|
|
454
455
|
const ManagedObjectMap = getOrSetGlobal('ManagedObjectMap', new Map());
|
|
455
456
|
function computeLocal(record, field, prop) {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
}
|
|
461
|
-
return signal.lastValue;
|
|
457
|
+
const signals = withSignalStore(record);
|
|
458
|
+
const signal = getOrCreateInternalSignal(signals, record, prop, field.options?.defaultValue ?? null);
|
|
459
|
+
consumeInternalSignal(signal);
|
|
460
|
+
return signal.value;
|
|
462
461
|
}
|
|
463
462
|
function peekManagedArray(record, field) {
|
|
464
463
|
const managedArrayMapForRecord = ManagedArrayMap.get(record);
|
|
@@ -602,9 +601,9 @@ class ResourceRelationship {
|
|
|
602
601
|
return this[RecordStore].request(request);
|
|
603
602
|
}
|
|
604
603
|
}
|
|
605
|
-
defineSignal(ResourceRelationship.prototype, 'data');
|
|
606
|
-
defineSignal(ResourceRelationship.prototype, 'links');
|
|
607
|
-
defineSignal(ResourceRelationship.prototype, 'meta');
|
|
604
|
+
defineSignal(ResourceRelationship.prototype, 'data', null);
|
|
605
|
+
defineSignal(ResourceRelationship.prototype, 'links', null);
|
|
606
|
+
defineSignal(ResourceRelationship.prototype, 'meta', null);
|
|
608
607
|
function getHref(link) {
|
|
609
608
|
if (!link) {
|
|
610
609
|
return null;
|
|
@@ -644,7 +643,9 @@ function computeHasMany(store, schema, cache, record, identifier, field, path, e
|
|
|
644
643
|
type: field.type,
|
|
645
644
|
identifier,
|
|
646
645
|
cache,
|
|
647
|
-
|
|
646
|
+
// we divorce the reference here because ManyArray mutates the target directly
|
|
647
|
+
// before sending the mutation op to the cache. We may be able to avoid this in the future
|
|
648
|
+
identifiers: rawValue.data?.slice(),
|
|
648
649
|
key: field.name,
|
|
649
650
|
meta: rawValue.meta || null,
|
|
650
651
|
links: rawValue.links || null,
|
|
@@ -653,7 +654,7 @@ function computeHasMany(store, schema, cache, record, identifier, field, path, e
|
|
|
653
654
|
// TODO: Grab the proper value
|
|
654
655
|
_inverseIsAsync: false,
|
|
655
656
|
// @ts-expect-error Typescript doesn't have a way for us to thread the generic backwards so it infers unknown instead of T
|
|
656
|
-
manager: new ManyArrayManager(record),
|
|
657
|
+
manager: new ManyArrayManager(record, editable),
|
|
657
658
|
isLoaded: true,
|
|
658
659
|
allowMutation: editable
|
|
659
660
|
});
|
|
@@ -668,7 +669,7 @@ function computeHasMany(store, schema, cache, record, identifier, field, path, e
|
|
|
668
669
|
const HAS_MODEL_PACKAGE = dependencySatisfies('@ember-data/model', '*');
|
|
669
670
|
const getLegacySupport = macroCondition(dependencySatisfies('@ember-data/model', '*')) ? importSync('@ember-data/model/-private').lookupLegacySupport : null;
|
|
670
671
|
const IgnoredGlobalFields = new Set(['length', 'nodeType', 'then', 'setInterval', 'document', STRUCTURED]);
|
|
671
|
-
const symbolList = [Destroy, RecordStore, Identifier, Editable, Parent, Checkout, Legacy,
|
|
672
|
+
const symbolList = [Destroy, RecordStore, Identifier, Editable, Parent, Checkout, Legacy, EmbeddedPath, EmbeddedType];
|
|
672
673
|
const RecordSymbols = new Set(symbolList);
|
|
673
674
|
function isPathMatch(a, b) {
|
|
674
675
|
return a.length === b.length && a.every((v, i) => v === b[i]);
|
|
@@ -700,8 +701,7 @@ class SchemaRecord {
|
|
|
700
701
|
const fields = isEmbedded ? schema.fields({
|
|
701
702
|
type: embeddedType
|
|
702
703
|
}) : schema.fields(identifier);
|
|
703
|
-
const signals =
|
|
704
|
-
this[Signals] = signals;
|
|
704
|
+
const signals = withSignalStore(this);
|
|
705
705
|
const proxy = new Proxy(this, {
|
|
706
706
|
ownKeys() {
|
|
707
707
|
const identityKey = identityField?.name;
|
|
@@ -773,6 +773,9 @@ class SchemaRecord {
|
|
|
773
773
|
if (RecordSymbols.has(prop)) {
|
|
774
774
|
return target[prop];
|
|
775
775
|
}
|
|
776
|
+
if (prop === Signals) {
|
|
777
|
+
return signals;
|
|
778
|
+
}
|
|
776
779
|
|
|
777
780
|
// TODO make this a symbol
|
|
778
781
|
if (prop === '___notifications') {
|
|
@@ -801,7 +804,7 @@ class SchemaRecord {
|
|
|
801
804
|
let fn = BoundFns.get('toString');
|
|
802
805
|
if (!fn) {
|
|
803
806
|
fn = function () {
|
|
804
|
-
entangleSignal(signals, receiver, '@identity');
|
|
807
|
+
entangleSignal(signals, receiver, '@identity', null);
|
|
805
808
|
return `Record<${identifier.type}:${identifier.id} (${identifier.lid})>`;
|
|
806
809
|
};
|
|
807
810
|
BoundFns.set(prop, fn);
|
|
@@ -812,7 +815,7 @@ class SchemaRecord {
|
|
|
812
815
|
let fn = BoundFns.get('toHTML');
|
|
813
816
|
if (!fn) {
|
|
814
817
|
fn = function () {
|
|
815
|
-
entangleSignal(signals, receiver, '@identity');
|
|
818
|
+
entangleSignal(signals, receiver, '@identity', null);
|
|
816
819
|
return `<span>Record<${identifier.type}:${identifier.id} (${identifier.lid})></span>`;
|
|
817
820
|
};
|
|
818
821
|
BoundFns.set(prop, fn);
|
|
@@ -872,42 +875,40 @@ class SchemaRecord {
|
|
|
872
875
|
|
|
873
876
|
switch (field.kind) {
|
|
874
877
|
case '@id':
|
|
875
|
-
entangleSignal(signals, receiver, '@identity');
|
|
878
|
+
entangleSignal(signals, receiver, '@identity', null);
|
|
876
879
|
return identifier.id;
|
|
877
880
|
case '@hash':
|
|
878
881
|
// TODO pass actual cache value not {}
|
|
879
882
|
return schema.hashFn(field)({}, field.options ?? null, field.name ?? null);
|
|
880
883
|
case '@local':
|
|
881
884
|
{
|
|
882
|
-
|
|
883
|
-
entangleSignal(signals, receiver, prop);
|
|
884
|
-
return lastValue;
|
|
885
|
+
return computeLocal(receiver, field, prop);
|
|
885
886
|
}
|
|
886
887
|
case 'field':
|
|
887
|
-
entangleSignal(signals, receiver, field.name);
|
|
888
|
+
entangleSignal(signals, receiver, field.name, null);
|
|
888
889
|
return computeField(schema, cache, target, identifier, field, propArray, IS_EDITABLE);
|
|
889
890
|
case 'attribute':
|
|
890
|
-
entangleSignal(signals, receiver, field.name);
|
|
891
|
+
entangleSignal(signals, receiver, field.name, null);
|
|
891
892
|
return computeAttribute(cache, identifier, prop, IS_EDITABLE);
|
|
892
893
|
case 'resource':
|
|
893
|
-
entangleSignal(signals, receiver, field.name);
|
|
894
|
+
entangleSignal(signals, receiver, field.name, null);
|
|
894
895
|
return computeResource(store, cache, target, identifier, field, prop, IS_EDITABLE);
|
|
895
896
|
case 'derived':
|
|
896
897
|
return computeDerivation(schema, receiver, identifier, field, prop);
|
|
897
898
|
case 'schema-array':
|
|
898
899
|
case 'array':
|
|
899
|
-
entangleSignal(signals, receiver, field.name);
|
|
900
|
+
entangleSignal(signals, receiver, field.name, null);
|
|
900
901
|
return computeArray(store, schema, cache, target, identifier, field, propArray, Mode[Editable], Mode[Legacy]);
|
|
901
902
|
case 'object':
|
|
902
|
-
entangleSignal(signals, receiver, field.name);
|
|
903
|
+
entangleSignal(signals, receiver, field.name, null);
|
|
903
904
|
return computeObject(schema, cache, target, identifier, field, propArray, Mode[Editable], Mode[Legacy]);
|
|
904
905
|
case 'schema-object':
|
|
905
|
-
entangleSignal(signals, receiver, field.name);
|
|
906
|
+
entangleSignal(signals, receiver, field.name, null);
|
|
906
907
|
// run transform, then use that value as the object to manage
|
|
907
908
|
return computeSchemaObject(store, cache, target, identifier, field, propArray, Mode[Legacy], Mode[Editable]);
|
|
908
909
|
case 'belongsTo':
|
|
909
910
|
if (field.options.linksMode) {
|
|
910
|
-
entangleSignal(signals, receiver, field.name);
|
|
911
|
+
entangleSignal(signals, receiver, field.name, null);
|
|
911
912
|
const rawValue = IS_EDITABLE ? cache.getRelationship(identifier, field.name) : cache.getRemoteRelationship(identifier, field.name);
|
|
912
913
|
|
|
913
914
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
@@ -930,11 +931,11 @@ class SchemaRecord {
|
|
|
930
931
|
throw new Error(`Can only use belongsTo fields when the resource is in legacy mode`);
|
|
931
932
|
}
|
|
932
933
|
})(Mode[Legacy]) : {};
|
|
933
|
-
entangleSignal(signals, receiver, field.name);
|
|
934
|
+
entangleSignal(signals, receiver, field.name, null);
|
|
934
935
|
return getLegacySupport(receiver).getBelongsTo(field.name);
|
|
935
936
|
case 'hasMany':
|
|
936
937
|
if (field.options.linksMode) {
|
|
937
|
-
entangleSignal(signals, receiver, field.name);
|
|
938
|
+
entangleSignal(signals, receiver, field.name, null);
|
|
938
939
|
return computeHasMany(store, schema, cache, target, identifier, field, propArray, Mode[Editable], Mode[Legacy]);
|
|
939
940
|
}
|
|
940
941
|
if (!HAS_MODEL_PACKAGE) {
|
|
@@ -954,7 +955,7 @@ class SchemaRecord {
|
|
|
954
955
|
throw new Error(`Can only use hasMany fields when the resource is in legacy mode`);
|
|
955
956
|
}
|
|
956
957
|
})(Mode[Legacy]) : {};
|
|
957
|
-
entangleSignal(signals, receiver, field.name);
|
|
958
|
+
entangleSignal(signals, receiver, field.name, null);
|
|
958
959
|
return getLegacySupport(receiver).getHasMany(field.name);
|
|
959
960
|
default:
|
|
960
961
|
throw new Error(`Field '${String(prop)}' on '${identifier.type}' has the unknown kind '${field.kind}'`);
|
|
@@ -1005,10 +1006,10 @@ class SchemaRecord {
|
|
|
1005
1006
|
}
|
|
1006
1007
|
case '@local':
|
|
1007
1008
|
{
|
|
1008
|
-
const signal =
|
|
1009
|
-
if (signal.
|
|
1010
|
-
signal.
|
|
1011
|
-
|
|
1009
|
+
const signal = getOrCreateInternalSignal(signals, receiver, prop, field.options?.defaultValue ?? null);
|
|
1010
|
+
if (signal.value !== value) {
|
|
1011
|
+
signal.value = value;
|
|
1012
|
+
notifyInternalSignal(signal);
|
|
1012
1013
|
}
|
|
1013
1014
|
return true;
|
|
1014
1015
|
}
|
|
@@ -1040,7 +1041,7 @@ class SchemaRecord {
|
|
|
1040
1041
|
}
|
|
1041
1042
|
})(ARRAY_SIGNAL in peeked) : {};
|
|
1042
1043
|
const arrSignal = peeked[ARRAY_SIGNAL];
|
|
1043
|
-
arrSignal.
|
|
1044
|
+
arrSignal.isStale = true;
|
|
1044
1045
|
}
|
|
1045
1046
|
if (!Array.isArray(value)) {
|
|
1046
1047
|
ManagedArrayMap.delete(target);
|
|
@@ -1058,7 +1059,7 @@ class SchemaRecord {
|
|
|
1058
1059
|
}
|
|
1059
1060
|
})(ARRAY_SIGNAL in peeked) : {};
|
|
1060
1061
|
const arrSignal = peeked[ARRAY_SIGNAL];
|
|
1061
|
-
arrSignal.
|
|
1062
|
+
arrSignal.isStale = true;
|
|
1062
1063
|
}
|
|
1063
1064
|
return true;
|
|
1064
1065
|
}
|
|
@@ -1077,7 +1078,7 @@ class SchemaRecord {
|
|
|
1077
1078
|
}
|
|
1078
1079
|
})(ARRAY_SIGNAL in peeked) : {};
|
|
1079
1080
|
const arrSignal = peeked[ARRAY_SIGNAL];
|
|
1080
|
-
arrSignal.
|
|
1081
|
+
arrSignal.isStale = true;
|
|
1081
1082
|
}
|
|
1082
1083
|
if (!Array.isArray(value)) {
|
|
1083
1084
|
ManagedArrayMap.delete(target);
|
|
@@ -1099,7 +1100,7 @@ class SchemaRecord {
|
|
|
1099
1100
|
const peeked = peekManagedObject(self, field);
|
|
1100
1101
|
if (peeked) {
|
|
1101
1102
|
const objSignal = peeked[OBJECT_SIGNAL];
|
|
1102
|
-
objSignal.
|
|
1103
|
+
objSignal.isStale = true;
|
|
1103
1104
|
}
|
|
1104
1105
|
return true;
|
|
1105
1106
|
}
|
|
@@ -1111,7 +1112,7 @@ class SchemaRecord {
|
|
|
1111
1112
|
const peeked = peekManagedObject(self, field);
|
|
1112
1113
|
if (peeked) {
|
|
1113
1114
|
const objSignal = peeked[OBJECT_SIGNAL];
|
|
1114
|
-
objSignal.
|
|
1115
|
+
objSignal.isStale = true;
|
|
1115
1116
|
}
|
|
1116
1117
|
return true;
|
|
1117
1118
|
}
|
|
@@ -1142,7 +1143,7 @@ class SchemaRecord {
|
|
|
1142
1143
|
// const peeked = peekManagedObject(self, field);
|
|
1143
1144
|
// if (peeked) {
|
|
1144
1145
|
// const objSignal = peeked[OBJECT_SIGNAL];
|
|
1145
|
-
// objSignal.
|
|
1146
|
+
// objSignal.isStale = true;
|
|
1146
1147
|
// }
|
|
1147
1148
|
return true;
|
|
1148
1149
|
}
|
|
@@ -1217,7 +1218,7 @@ class SchemaRecord {
|
|
|
1217
1218
|
if (identityField.name && identityField.kind === '@id') {
|
|
1218
1219
|
const signal = signals.get('@identity');
|
|
1219
1220
|
if (signal) {
|
|
1220
|
-
|
|
1221
|
+
notifyInternalSignal(signal);
|
|
1221
1222
|
}
|
|
1222
1223
|
}
|
|
1223
1224
|
break;
|
|
@@ -1247,7 +1248,7 @@ class SchemaRecord {
|
|
|
1247
1248
|
// console.log(`Notification for ${key} on ${identifier.type}`, self);
|
|
1248
1249
|
const signal = signals.get(key);
|
|
1249
1250
|
if (signal) {
|
|
1250
|
-
|
|
1251
|
+
notifyInternalSignal(signal);
|
|
1251
1252
|
}
|
|
1252
1253
|
const field = fields.get(key);
|
|
1253
1254
|
if (field?.kind === 'array' || field?.kind === 'schema-array') {
|
|
@@ -1259,16 +1260,14 @@ class SchemaRecord {
|
|
|
1259
1260
|
}
|
|
1260
1261
|
})(ARRAY_SIGNAL in peeked) : {};
|
|
1261
1262
|
const arrSignal = peeked[ARRAY_SIGNAL];
|
|
1262
|
-
arrSignal
|
|
1263
|
-
addToTransaction(arrSignal);
|
|
1263
|
+
notifyInternalSignal(arrSignal);
|
|
1264
1264
|
}
|
|
1265
1265
|
}
|
|
1266
1266
|
if (field?.kind === 'object') {
|
|
1267
1267
|
const peeked = peekManagedObject(self, field);
|
|
1268
1268
|
if (peeked) {
|
|
1269
1269
|
const objSignal = peeked[OBJECT_SIGNAL];
|
|
1270
|
-
objSignal
|
|
1271
|
-
addToTransaction(objSignal);
|
|
1270
|
+
notifyInternalSignal(objSignal);
|
|
1272
1271
|
}
|
|
1273
1272
|
}
|
|
1274
1273
|
}
|
|
@@ -1290,17 +1289,14 @@ class SchemaRecord {
|
|
|
1290
1289
|
// console.log(`Notification for ${key} on ${identifier.type}`, self);
|
|
1291
1290
|
const signal = signals.get(key);
|
|
1292
1291
|
if (signal) {
|
|
1293
|
-
|
|
1292
|
+
notifyInternalSignal(signal);
|
|
1294
1293
|
}
|
|
1295
1294
|
// FIXME
|
|
1296
1295
|
} else if (field.kind === 'resource') ;else if (field.kind === 'hasMany') {
|
|
1297
1296
|
if (field.options.linksMode) {
|
|
1298
1297
|
const peeked = peekManagedArray(self, field);
|
|
1299
1298
|
if (peeked) {
|
|
1300
|
-
|
|
1301
|
-
// arrSignal.shouldReset = true;
|
|
1302
|
-
// addToTransaction(arrSignal);
|
|
1303
|
-
peeked.notify();
|
|
1299
|
+
notifyInternalSignal(peeked[ARRAY_SIGNAL]);
|
|
1304
1300
|
}
|
|
1305
1301
|
return;
|
|
1306
1302
|
}
|
|
@@ -1323,7 +1319,7 @@ class SchemaRecord {
|
|
|
1323
1319
|
return;
|
|
1324
1320
|
}
|
|
1325
1321
|
if (manyArray) {
|
|
1326
|
-
manyArray
|
|
1322
|
+
notifyInternalSignal(manyArray[ARRAY_SIGNAL]);
|
|
1327
1323
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1328
1324
|
if (!test) {
|
|
1329
1325
|
throw new Error(`Expected options to exist on relationship meta`);
|
|
@@ -1337,7 +1333,7 @@ class SchemaRecord {
|
|
|
1337
1333
|
if (field.options.async) {
|
|
1338
1334
|
const signal = signals.get(key);
|
|
1339
1335
|
if (signal) {
|
|
1340
|
-
|
|
1336
|
+
notifyInternalSignal(signal);
|
|
1341
1337
|
}
|
|
1342
1338
|
}
|
|
1343
1339
|
}
|
|
@@ -1467,15 +1463,23 @@ function _constructor(record) {
|
|
|
1467
1463
|
_constructor[Type] = '@constructor';
|
|
1468
1464
|
|
|
1469
1465
|
/**
|
|
1470
|
-
* Utility for constructing a ResourceSchema with the recommended
|
|
1471
|
-
* for the
|
|
1466
|
+
* Utility for constructing a ResourceSchema with the recommended
|
|
1467
|
+
* fields for the PolarisMode experience.
|
|
1468
|
+
*
|
|
1469
|
+
* Using this requires registering the PolarisMode derivations
|
|
1470
|
+
*
|
|
1471
|
+
* ```ts
|
|
1472
|
+
* import { registerDerivations } from '@warp-drive/schema-record';
|
|
1473
|
+
*
|
|
1474
|
+
* registerDerivations(schema);
|
|
1475
|
+
* ```
|
|
1472
1476
|
*
|
|
1473
1477
|
* @method withDefaults
|
|
1474
1478
|
* @for @warp-drive/schema-record
|
|
1475
1479
|
* @static
|
|
1476
1480
|
* @public
|
|
1477
1481
|
* @param schema
|
|
1478
|
-
* @return {
|
|
1482
|
+
* @return {PolarisResourceSchema}
|
|
1479
1483
|
*/
|
|
1480
1484
|
function withDefaults(schema) {
|
|
1481
1485
|
schema.identity = schema.identity || DefaultIdentityField;
|
|
@@ -1530,7 +1534,12 @@ function fromIdentity(record, options, key) {
|
|
|
1530
1534
|
fromIdentity[Type] = '@identity';
|
|
1531
1535
|
|
|
1532
1536
|
/**
|
|
1533
|
-
* Registers the default derivations for
|
|
1537
|
+
* Registers the default derivations for records that want
|
|
1538
|
+
* to use the PolarisMode defaults provided by
|
|
1539
|
+
*
|
|
1540
|
+
* ```ts
|
|
1541
|
+
* import { withDefaults } from '@warp-drive/schema-record';
|
|
1542
|
+
* ```
|
|
1534
1543
|
*
|
|
1535
1544
|
* @method registerDerivations
|
|
1536
1545
|
* @for @warp-drive/schema-record
|
|
@@ -1550,15 +1559,15 @@ function registerDerivations(schema) {
|
|
|
1550
1559
|
*/
|
|
1551
1560
|
function makeCachedDerivation(derivation) {
|
|
1552
1561
|
const memoizedDerivation = (record, options, prop) => {
|
|
1553
|
-
const signals = record
|
|
1562
|
+
const signals = withSignalStore(record);
|
|
1554
1563
|
let signal = signals.get(prop);
|
|
1555
1564
|
if (!signal) {
|
|
1556
|
-
signal =
|
|
1565
|
+
signal = createMemo(record, prop, () => {
|
|
1557
1566
|
return derivation(record, options, prop);
|
|
1558
1567
|
}); // a total lie, for convenience of reusing the storage
|
|
1559
1568
|
signals.set(prop, signal);
|
|
1560
1569
|
}
|
|
1561
|
-
return
|
|
1570
|
+
return signal();
|
|
1562
1571
|
};
|
|
1563
1572
|
memoizedDerivation[Type] = derivation[Type];
|
|
1564
1573
|
return memoizedDerivation;
|
|
@@ -1577,6 +1586,7 @@ class SchemaService {
|
|
|
1577
1586
|
this._transforms = new Map();
|
|
1578
1587
|
this._hashFns = new Map();
|
|
1579
1588
|
this._derivations = new Map();
|
|
1589
|
+
this._traits = new Set();
|
|
1580
1590
|
}
|
|
1581
1591
|
resourceTypes() {
|
|
1582
1592
|
return Array.from(this._schemas.keys());
|