@warp-drive-mirror/schema-record 0.0.0-beta.9 → 0.0.1
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/dist/hooks.js +1 -1
- package/dist/hooks.js.map +1 -1
- package/dist/record.js +248 -148
- package/dist/record.js.map +1 -1
- package/dist/schema.js +20 -20
- package/dist/schema.js.map +1 -1
- package/package.json +36 -25
- package/unstable-preview-types/-private/compute.d.ts +7 -5
- package/unstable-preview-types/-private/compute.d.ts.map +1 -1
- package/unstable-preview-types/-private/managed-array.d.ts +5 -3
- package/unstable-preview-types/-private/managed-array.d.ts.map +1 -1
- package/unstable-preview-types/-private/managed-object.d.ts +6 -6
- package/unstable-preview-types/-private/managed-object.d.ts.map +1 -1
- package/unstable-preview-types/index.d.ts +4 -4
- package/unstable-preview-types/record.d.ts +1 -1
- package/unstable-preview-types/record.d.ts.map +1 -1
package/dist/record.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { macroCondition, getGlobalConfig, dependencySatisfies, importSync } from '@embroider/macros';
|
|
2
|
+
import { setRecordIdentifier, recordIdentifierFor } from '@ember-data-mirror/store/-private';
|
|
2
3
|
import { createSignal, subscribe, defineSignal, peekSignal, getSignal, Signals, entangleSignal, addToTransaction } from '@ember-data-mirror/tracking/-private';
|
|
3
4
|
import { STRUCTURED } from '@warp-drive-mirror/core-types/request';
|
|
4
5
|
import { RecordStore } from '@warp-drive-mirror/core-types/symbols';
|
|
5
6
|
import { getOrSetGlobal } from '@warp-drive-mirror/core-types/-private';
|
|
6
|
-
import { S as SOURCE, A as ARRAY_SIGNAL,
|
|
7
|
+
import { S as SOURCE, A as ARRAY_SIGNAL, E as Editable, L as Legacy, I as Identifier, P as Parent, O as OBJECT_SIGNAL, a as EmbeddedPath, D as Destroy, C as Checkout, b as EmbeddedType } from "./symbols-DqoS4ybV.js";
|
|
7
8
|
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']);
|
|
8
9
|
// const ARRAY_SETTER_METHODS = new Set<KeyType>(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
|
|
9
10
|
const SYNC_PROPS = new Set(['[]', 'length']);
|
|
10
11
|
function isArrayGetter(prop) {
|
|
11
12
|
return ARRAY_GETTER_METHODS.has(prop);
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const ARRAY_SETTER_METHODS = new Set(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
|
|
15
|
+
function isArraySetter(prop) {
|
|
16
|
+
return ARRAY_SETTER_METHODS.has(prop);
|
|
17
|
+
}
|
|
18
|
+
|
|
16
19
|
// function isSelfProp<T extends object>(self: T, prop: KeyType): prop is keyof T {
|
|
17
20
|
// return prop in self;
|
|
18
21
|
// }
|
|
@@ -29,7 +32,7 @@ function safeForEach(instance, arr, store, callback, target) {
|
|
|
29
32
|
}
|
|
30
33
|
// clone to prevent mutation
|
|
31
34
|
arr = arr.slice();
|
|
32
|
-
macroCondition(getGlobalConfig().
|
|
35
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
33
36
|
if (!test) {
|
|
34
37
|
throw new Error('`forEach` expects a function as first argument.');
|
|
35
38
|
}
|
|
@@ -48,14 +51,16 @@ function safeForEach(instance, arr, store, callback, target) {
|
|
|
48
51
|
}
|
|
49
52
|
class ManagedArray {
|
|
50
53
|
[SOURCE];
|
|
51
|
-
constructor(store, schema, cache, field, data,
|
|
54
|
+
constructor(store, schema, cache, field, data, identifier, path, owner, isSchemaArray, editable, legacy) {
|
|
52
55
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
53
56
|
const self = this;
|
|
54
57
|
this[SOURCE] = data?.slice();
|
|
55
58
|
this[ARRAY_SIGNAL] = createSignal(this, 'length');
|
|
59
|
+
const IS_EDITABLE = this[Editable] = editable ?? false;
|
|
60
|
+
this[Legacy] = legacy;
|
|
56
61
|
const _SIGNAL = this[ARRAY_SIGNAL];
|
|
57
62
|
const boundFns = new Map();
|
|
58
|
-
this.
|
|
63
|
+
this.identifier = identifier;
|
|
59
64
|
this.path = path;
|
|
60
65
|
this.owner = owner;
|
|
61
66
|
let transaction = false;
|
|
@@ -74,8 +79,8 @@ class ManagedArray {
|
|
|
74
79
|
if (prop === ARRAY_SIGNAL) {
|
|
75
80
|
return _SIGNAL;
|
|
76
81
|
}
|
|
77
|
-
if (prop === '
|
|
78
|
-
return self.
|
|
82
|
+
if (prop === 'identifier') {
|
|
83
|
+
return self.identifier;
|
|
79
84
|
}
|
|
80
85
|
if (prop === 'owner') {
|
|
81
86
|
return self.owner;
|
|
@@ -84,7 +89,7 @@ class ManagedArray {
|
|
|
84
89
|
if (_SIGNAL.shouldReset && (index !== null || SYNC_PROPS.has(prop) || isArrayGetter(prop))) {
|
|
85
90
|
_SIGNAL.t = false;
|
|
86
91
|
_SIGNAL.shouldReset = false;
|
|
87
|
-
const newData = cache.getAttr(
|
|
92
|
+
const newData = cache.getAttr(identifier, path);
|
|
88
93
|
if (newData && newData !== self[SOURCE]) {
|
|
89
94
|
self[SOURCE].length = 0;
|
|
90
95
|
self[SOURCE].push(...newData);
|
|
@@ -107,7 +112,7 @@ class ManagedArray {
|
|
|
107
112
|
// the given field does not exist OR
|
|
108
113
|
// the field is anything other than a GenericField or LegacyAttributeField.
|
|
109
114
|
if (mode !== '@identity' && mode !== '@index') {
|
|
110
|
-
macroCondition(getGlobalConfig().
|
|
115
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
111
116
|
if (!test) {
|
|
112
117
|
throw new Error('mode must be a string');
|
|
113
118
|
}
|
|
@@ -115,12 +120,12 @@ class ManagedArray {
|
|
|
115
120
|
const modeField = schema.resource({
|
|
116
121
|
type: field.type
|
|
117
122
|
}).fields.find(f => f.name === mode);
|
|
118
|
-
macroCondition(getGlobalConfig().
|
|
123
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
119
124
|
if (!test) {
|
|
120
125
|
throw new Error('field must exist in schema');
|
|
121
126
|
}
|
|
122
127
|
})(modeField) : {};
|
|
123
|
-
macroCondition(getGlobalConfig().
|
|
128
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
124
129
|
if (!test) {
|
|
125
130
|
throw new Error('field must be a GenericField or LegacyAttributeField');
|
|
126
131
|
}
|
|
@@ -144,7 +149,8 @@ class ManagedArray {
|
|
|
144
149
|
// same object reference from cache should result in same SchemaRecord
|
|
145
150
|
// embedded object.
|
|
146
151
|
recordPath.push(index);
|
|
147
|
-
|
|
152
|
+
const recordIdentifier = self.owner[Identifier] || self.owner[Parent];
|
|
153
|
+
record = new SchemaRecord(store, recordIdentifier, {
|
|
148
154
|
[Editable]: self.owner[Editable],
|
|
149
155
|
[Legacy]: self.owner[Legacy]
|
|
150
156
|
}, true, field.type, recordPath);
|
|
@@ -195,12 +201,36 @@ class ManagedArray {
|
|
|
195
201
|
}
|
|
196
202
|
return fn;
|
|
197
203
|
}
|
|
204
|
+
if (isArraySetter(prop)) {
|
|
205
|
+
let fn = boundFns.get(prop);
|
|
206
|
+
if (fn === undefined) {
|
|
207
|
+
fn = function () {
|
|
208
|
+
if (!IS_EDITABLE) {
|
|
209
|
+
throw new Error(`Mutating this array via ${String(prop)} is not allowed because the record is not editable`);
|
|
210
|
+
}
|
|
211
|
+
subscribe(_SIGNAL);
|
|
212
|
+
transaction = true;
|
|
213
|
+
const result = Reflect.apply(target[prop], receiver, arguments);
|
|
214
|
+
transaction = false;
|
|
215
|
+
return result;
|
|
216
|
+
};
|
|
217
|
+
boundFns.set(prop, fn);
|
|
218
|
+
}
|
|
219
|
+
return fn;
|
|
220
|
+
}
|
|
198
221
|
return Reflect.get(target, prop, receiver);
|
|
199
222
|
},
|
|
200
223
|
set(target, prop, value, receiver) {
|
|
201
|
-
if (
|
|
224
|
+
if (!IS_EDITABLE) {
|
|
225
|
+
let errorPath = identifier.type;
|
|
226
|
+
if (path) {
|
|
227
|
+
errorPath = path[path.length - 1];
|
|
228
|
+
}
|
|
229
|
+
throw new Error(`Cannot set ${String(prop)} on ${errorPath} because the record is not editable`);
|
|
230
|
+
}
|
|
231
|
+
if (prop === 'identifier') {
|
|
202
232
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
203
|
-
self.
|
|
233
|
+
self.identifier = value;
|
|
204
234
|
return true;
|
|
205
235
|
}
|
|
206
236
|
if (prop === 'owner') {
|
|
@@ -211,7 +241,7 @@ class ManagedArray {
|
|
|
211
241
|
const reflect = Reflect.set(target, prop, value, receiver);
|
|
212
242
|
if (reflect) {
|
|
213
243
|
if (!field.type) {
|
|
214
|
-
cache.setAttr(
|
|
244
|
+
cache.setAttr(identifier, path, self[SOURCE]);
|
|
215
245
|
_SIGNAL.shouldReset = true;
|
|
216
246
|
return true;
|
|
217
247
|
}
|
|
@@ -219,11 +249,11 @@ class ManagedArray {
|
|
|
219
249
|
if (!isSchemaArray) {
|
|
220
250
|
const transform = schema.transformation(field);
|
|
221
251
|
if (!transform) {
|
|
222
|
-
throw new Error(`No '${field.type}' transform defined for use by ${
|
|
252
|
+
throw new Error(`No '${field.type}' transform defined for use by ${identifier.type}.${String(prop)}`);
|
|
223
253
|
}
|
|
224
254
|
rawValue = self[SOURCE].map(item => transform.serialize(item, field.options ?? null, self.owner));
|
|
225
255
|
}
|
|
226
|
-
cache.setAttr(
|
|
256
|
+
cache.setAttr(identifier, path, rawValue);
|
|
227
257
|
_SIGNAL.shouldReset = true;
|
|
228
258
|
}
|
|
229
259
|
return reflect;
|
|
@@ -232,41 +262,53 @@ class ManagedArray {
|
|
|
232
262
|
return proxy;
|
|
233
263
|
}
|
|
234
264
|
}
|
|
235
|
-
const
|
|
265
|
+
const ObjectSymbols = new Set([OBJECT_SIGNAL, Parent, SOURCE, Editable, EmbeddedPath]);
|
|
266
|
+
|
|
267
|
+
// const ignoredGlobalFields = new Set<string>(['setInterval', 'nodeType', 'nodeName', 'length', 'document', STRUCTURED]);
|
|
268
|
+
|
|
236
269
|
class ManagedObject {
|
|
237
|
-
|
|
238
|
-
constructor(store, schema, cache, field, data, address, key, owner, isSchemaObject) {
|
|
270
|
+
constructor(schema, cache, field, data, identifier, path, owner, editable, legacy) {
|
|
239
271
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
240
272
|
const self = this;
|
|
241
273
|
this[SOURCE] = {
|
|
242
274
|
...data
|
|
243
275
|
};
|
|
244
276
|
this[OBJECT_SIGNAL] = createSignal(this, 'length');
|
|
277
|
+
this[Editable] = editable;
|
|
278
|
+
this[Legacy] = legacy;
|
|
279
|
+
this[Parent] = identifier;
|
|
280
|
+
this[EmbeddedPath] = path;
|
|
245
281
|
const _SIGNAL = this[OBJECT_SIGNAL];
|
|
246
|
-
// const boundFns = new Map<KeyType, ProxiedMethod>();
|
|
247
|
-
this.address = address;
|
|
248
|
-
this.key = key;
|
|
249
|
-
this.owner = owner;
|
|
250
282
|
const proxy = new Proxy(this[SOURCE], {
|
|
283
|
+
ownKeys() {
|
|
284
|
+
return Object.keys(self[SOURCE]);
|
|
285
|
+
},
|
|
286
|
+
has(target, prop) {
|
|
287
|
+
return prop in self[SOURCE];
|
|
288
|
+
},
|
|
289
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
290
|
+
return {
|
|
291
|
+
writable: editable,
|
|
292
|
+
enumerable: true,
|
|
293
|
+
configurable: true
|
|
294
|
+
};
|
|
295
|
+
},
|
|
251
296
|
get(target, prop, receiver) {
|
|
252
|
-
if (prop
|
|
253
|
-
return
|
|
297
|
+
if (ObjectSymbols.has(prop)) {
|
|
298
|
+
return self[prop];
|
|
254
299
|
}
|
|
255
|
-
if (prop ===
|
|
256
|
-
return
|
|
257
|
-
}
|
|
258
|
-
if (prop === 'key') {
|
|
259
|
-
return self.key;
|
|
260
|
-
}
|
|
261
|
-
if (prop === 'owner') {
|
|
262
|
-
return self.owner;
|
|
300
|
+
if (prop === Symbol.toPrimitive) {
|
|
301
|
+
return null;
|
|
263
302
|
}
|
|
264
303
|
if (prop === Symbol.toStringTag) {
|
|
265
|
-
return `ManagedObject<${
|
|
304
|
+
return `ManagedObject<${identifier.type}:${identifier.id} (${identifier.lid})>`;
|
|
305
|
+
}
|
|
306
|
+
if (prop === 'constructor') {
|
|
307
|
+
return Object;
|
|
266
308
|
}
|
|
267
309
|
if (prop === 'toString') {
|
|
268
310
|
return function () {
|
|
269
|
-
return `ManagedObject<${
|
|
311
|
+
return `ManagedObject<${identifier.type}:${identifier.id} (${identifier.lid})>`;
|
|
270
312
|
};
|
|
271
313
|
}
|
|
272
314
|
if (prop === 'toHTML') {
|
|
@@ -277,71 +319,42 @@ class ManagedObject {
|
|
|
277
319
|
if (_SIGNAL.shouldReset) {
|
|
278
320
|
_SIGNAL.t = false;
|
|
279
321
|
_SIGNAL.shouldReset = false;
|
|
280
|
-
let newData = cache.getAttr(
|
|
322
|
+
let newData = cache.getAttr(identifier, path);
|
|
281
323
|
if (newData && newData !== self[SOURCE]) {
|
|
282
|
-
if (
|
|
324
|
+
if (field.type) {
|
|
283
325
|
const transform = schema.transformation(field);
|
|
284
|
-
newData = transform.hydrate(newData, field.options ?? null,
|
|
326
|
+
newData = transform.hydrate(newData, field.options ?? null, owner);
|
|
285
327
|
}
|
|
286
328
|
self[SOURCE] = {
|
|
287
329
|
...newData
|
|
288
330
|
}; // Add type assertion for newData
|
|
289
331
|
}
|
|
290
332
|
}
|
|
291
|
-
if (isSchemaObject) {
|
|
292
|
-
const fields = schema.fields({
|
|
293
|
-
type: field.type
|
|
294
|
-
});
|
|
295
|
-
// TODO: is there a better way to do this?
|
|
296
|
-
if (typeof prop === 'string' && !ignoredGlobalFields.has(prop) && !fields.has(prop)) {
|
|
297
|
-
throw new Error(`Field ${prop} does not exist on schema object ${field.type}`);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
333
|
if (prop in self[SOURCE]) {
|
|
301
|
-
|
|
302
|
-
subscribe(_SIGNAL);
|
|
303
|
-
}
|
|
334
|
+
subscribe(_SIGNAL);
|
|
304
335
|
return self[SOURCE][prop];
|
|
305
336
|
}
|
|
306
337
|
return Reflect.get(target, prop, receiver);
|
|
307
338
|
},
|
|
308
339
|
set(target, prop, value, receiver) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
return true;
|
|
313
|
-
}
|
|
314
|
-
if (prop === 'key') {
|
|
315
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
316
|
-
self.key = value;
|
|
317
|
-
return true;
|
|
318
|
-
}
|
|
319
|
-
if (prop === 'owner') {
|
|
320
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
321
|
-
self.owner = value;
|
|
322
|
-
return true;
|
|
323
|
-
}
|
|
324
|
-
if (isSchemaObject) {
|
|
325
|
-
const fields = schema.fields({
|
|
326
|
-
type: field.type
|
|
327
|
-
});
|
|
328
|
-
if (typeof prop === 'string' && !ignoredGlobalFields.has(prop) && !fields.has(prop)) {
|
|
329
|
-
throw new Error(`Field ${prop} does not exist on schema object ${field.type}`);
|
|
340
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
341
|
+
if (!test) {
|
|
342
|
+
throw new Error(`Cannot set read-only property '${String(prop)}' on ManagedObject`);
|
|
330
343
|
}
|
|
331
|
-
}
|
|
344
|
+
})(editable) : {};
|
|
332
345
|
const reflect = Reflect.set(target, prop, value, receiver);
|
|
333
|
-
if (reflect) {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
346
|
+
if (!reflect) {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
if (!field.type) {
|
|
350
|
+
cache.setAttr(identifier, path, self[SOURCE]);
|
|
351
|
+
} else {
|
|
339
352
|
const transform = schema.transformation(field);
|
|
340
|
-
const val = transform.serialize(self[SOURCE], field.options ?? null,
|
|
341
|
-
cache.setAttr(
|
|
342
|
-
_SIGNAL.shouldReset = true;
|
|
353
|
+
const val = transform.serialize(self[SOURCE], field.options ?? null, owner);
|
|
354
|
+
cache.setAttr(identifier, path, val);
|
|
343
355
|
}
|
|
344
|
-
|
|
356
|
+
_SIGNAL.shouldReset = true;
|
|
357
|
+
return true;
|
|
345
358
|
}
|
|
346
359
|
});
|
|
347
360
|
return proxy;
|
|
@@ -377,7 +390,7 @@ function computeField(schema, cache, record, identifier, field, prop) {
|
|
|
377
390
|
const transform = schema.transformation(field);
|
|
378
391
|
return transform.hydrate(rawValue, field.options ?? null, record);
|
|
379
392
|
}
|
|
380
|
-
function computeArray(store, schema, cache, record, identifier, field, path, isSchemaArray
|
|
393
|
+
function computeArray(store, schema, cache, record, identifier, field, path, isSchemaArray, editable, legacy) {
|
|
381
394
|
// the thing we hand out needs to know its owner and path in a private manner
|
|
382
395
|
// its "address" is the parent identifier (identifier) + field name (field.name)
|
|
383
396
|
// in the nested object case field name here is the full dot path from root resource to this value
|
|
@@ -396,7 +409,7 @@ function computeArray(store, schema, cache, record, identifier, field, path, isS
|
|
|
396
409
|
if (!rawValue) {
|
|
397
410
|
return null;
|
|
398
411
|
}
|
|
399
|
-
managedArray = new ManagedArray(store, schema, cache, field, rawValue, identifier, path, record, isSchemaArray);
|
|
412
|
+
managedArray = new ManagedArray(store, schema, cache, field, rawValue, identifier, path, record, isSchemaArray, editable, legacy);
|
|
400
413
|
if (!managedArrayMapForRecord) {
|
|
401
414
|
ManagedArrayMap.set(record, new Map([[field, managedArray]]));
|
|
402
415
|
} else {
|
|
@@ -405,7 +418,7 @@ function computeArray(store, schema, cache, record, identifier, field, path, isS
|
|
|
405
418
|
}
|
|
406
419
|
return managedArray;
|
|
407
420
|
}
|
|
408
|
-
function computeObject(
|
|
421
|
+
function computeObject(schema, cache, record, identifier, field, path, editable, legacy) {
|
|
409
422
|
const managedObjectMapForRecord = ManagedObjectMap.get(record);
|
|
410
423
|
let managedObject;
|
|
411
424
|
if (managedObjectMapForRecord) {
|
|
@@ -414,17 +427,15 @@ function computeObject(store, schema, cache, record, identifier, field, prop, is
|
|
|
414
427
|
if (managedObject) {
|
|
415
428
|
return managedObject;
|
|
416
429
|
} else {
|
|
417
|
-
let rawValue = cache.getAttr(identifier,
|
|
430
|
+
let rawValue = cache.getAttr(identifier, path);
|
|
418
431
|
if (!rawValue) {
|
|
419
432
|
return null;
|
|
420
433
|
}
|
|
421
|
-
if (field.
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
rawValue = transform.hydrate(rawValue, field.options ?? null, record);
|
|
425
|
-
}
|
|
434
|
+
if (field.type) {
|
|
435
|
+
const transform = schema.transformation(field);
|
|
436
|
+
rawValue = transform.hydrate(rawValue, field.options ?? null, record);
|
|
426
437
|
}
|
|
427
|
-
managedObject = new ManagedObject(
|
|
438
|
+
managedObject = new ManagedObject(schema, cache, field, rawValue, identifier, path, record, editable, legacy);
|
|
428
439
|
if (!managedObjectMapForRecord) {
|
|
429
440
|
ManagedObjectMap.set(record, new Map([[field, managedObject]]));
|
|
430
441
|
} else {
|
|
@@ -433,6 +444,32 @@ function computeObject(store, schema, cache, record, identifier, field, prop, is
|
|
|
433
444
|
}
|
|
434
445
|
return managedObject;
|
|
435
446
|
}
|
|
447
|
+
function computeSchemaObject(store, cache, record, identifier, field, path, legacy, editable) {
|
|
448
|
+
const schemaObjectMapForRecord = ManagedObjectMap.get(record);
|
|
449
|
+
let schemaObject;
|
|
450
|
+
if (schemaObjectMapForRecord) {
|
|
451
|
+
schemaObject = schemaObjectMapForRecord.get(field);
|
|
452
|
+
}
|
|
453
|
+
if (schemaObject) {
|
|
454
|
+
return schemaObject;
|
|
455
|
+
} else {
|
|
456
|
+
const rawValue = cache.getAttr(identifier, path);
|
|
457
|
+
if (!rawValue) {
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
const embeddedPath = path.slice();
|
|
461
|
+
schemaObject = new SchemaRecord(store, identifier, {
|
|
462
|
+
[Editable]: editable,
|
|
463
|
+
[Legacy]: legacy
|
|
464
|
+
}, true, field.type, embeddedPath);
|
|
465
|
+
}
|
|
466
|
+
if (!schemaObjectMapForRecord) {
|
|
467
|
+
ManagedObjectMap.set(record, new Map([[field, schemaObject]]));
|
|
468
|
+
} else {
|
|
469
|
+
schemaObjectMapForRecord.set(field, schemaObject);
|
|
470
|
+
}
|
|
471
|
+
return schemaObject;
|
|
472
|
+
}
|
|
436
473
|
function computeAttribute(cache, identifier, prop) {
|
|
437
474
|
return cache.getAttr(identifier, prop);
|
|
438
475
|
}
|
|
@@ -452,7 +489,7 @@ class ResourceRelationship {
|
|
|
452
489
|
this.lid = rawValue.lid ?? rawValue.links?.self ?? `relationship:${identifier.lid}.${name}`;
|
|
453
490
|
this.data = rawValue.data ? store.peekRecord(rawValue.data) : null;
|
|
454
491
|
this.name = name;
|
|
455
|
-
if (macroCondition(getGlobalConfig().
|
|
492
|
+
if (macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG)) {
|
|
456
493
|
this.links = Object.freeze(Object.assign({}, rawValue.links));
|
|
457
494
|
this.meta = Object.freeze(Object.assign({}, rawValue.meta));
|
|
458
495
|
} else {
|
|
@@ -494,12 +531,13 @@ function computeResource(store, cache, parent, identifier, field, prop) {
|
|
|
494
531
|
}
|
|
495
532
|
const HAS_MODEL_PACKAGE = dependencySatisfies('@ember-data-mirror/model', '*');
|
|
496
533
|
const getLegacySupport = macroCondition(dependencySatisfies('@ember-data-mirror/model', '*')) ? importSync('@ember-data-mirror/model/-private').lookupLegacySupport : null;
|
|
497
|
-
const IgnoredGlobalFields = new Set(['length', 'nodeType', 'then', 'setInterval', STRUCTURED]);
|
|
534
|
+
const IgnoredGlobalFields = new Set(['length', 'nodeType', 'then', 'setInterval', 'document', STRUCTURED]);
|
|
498
535
|
const symbolList = [Destroy, RecordStore, Identifier, Editable, Parent, Checkout, Legacy, Signals, EmbeddedPath, EmbeddedType];
|
|
499
536
|
const RecordSymbols = new Set(symbolList);
|
|
500
537
|
function isPathMatch(a, b) {
|
|
501
538
|
return a.length === b.length && a.every((v, i) => v === b[i]);
|
|
502
539
|
}
|
|
540
|
+
const Editables = new WeakMap();
|
|
503
541
|
class SchemaRecord {
|
|
504
542
|
constructor(store, identifier, Mode, isEmbedded = false, embeddedType = null, embeddedPath = null) {
|
|
505
543
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
@@ -550,6 +588,7 @@ class SchemaRecord {
|
|
|
550
588
|
case 'field':
|
|
551
589
|
case 'attribute':
|
|
552
590
|
case 'resource':
|
|
591
|
+
case 'alias':
|
|
553
592
|
case 'belongsTo':
|
|
554
593
|
case 'hasMany':
|
|
555
594
|
case 'collection':
|
|
@@ -576,6 +615,11 @@ class SchemaRecord {
|
|
|
576
615
|
return `SchemaRecord<${identifier.type}:${identifier.id} (${identifier.lid})>`;
|
|
577
616
|
};
|
|
578
617
|
}
|
|
618
|
+
if (prop === 'toHTML') {
|
|
619
|
+
return function () {
|
|
620
|
+
return `<div>SchemaRecord<${identifier.type}:${identifier.id} (${identifier.lid})></div>`;
|
|
621
|
+
};
|
|
622
|
+
}
|
|
579
623
|
if (prop === Symbol.toPrimitive) {
|
|
580
624
|
return null;
|
|
581
625
|
}
|
|
@@ -589,10 +633,8 @@ class SchemaRecord {
|
|
|
589
633
|
// for its own usage.
|
|
590
634
|
// _, @, $, *
|
|
591
635
|
|
|
592
|
-
const
|
|
593
|
-
|
|
594
|
-
const field = prop === identityField?.name ? identityField : fields.get(prop);
|
|
595
|
-
if (!field) {
|
|
636
|
+
const maybeField = prop === identityField?.name ? identityField : fields.get(prop);
|
|
637
|
+
if (!maybeField) {
|
|
596
638
|
if (IgnoredGlobalFields.has(prop)) {
|
|
597
639
|
return undefined;
|
|
598
640
|
}
|
|
@@ -603,8 +645,24 @@ class SchemaRecord {
|
|
|
603
645
|
if (typeof prop === 'symbol') {
|
|
604
646
|
return undefined;
|
|
605
647
|
}
|
|
606
|
-
|
|
648
|
+
let type = identifier.type;
|
|
649
|
+
if (isEmbedded) {
|
|
650
|
+
type = embeddedType;
|
|
651
|
+
}
|
|
652
|
+
throw new Error(`No field named ${String(prop)} on ${type}`);
|
|
607
653
|
}
|
|
654
|
+
const field = maybeField.kind === 'alias' ? maybeField.options : maybeField;
|
|
655
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
656
|
+
if (!test) {
|
|
657
|
+
throw new Error(`Alias fields cannot alias '@id' '@local' '@hash' or 'derived' fields`);
|
|
658
|
+
}
|
|
659
|
+
})(maybeField.kind !== 'alias' || !['@id', '@local', '@hash', 'derived'].includes(maybeField.options.kind)) : {};
|
|
660
|
+
const propArray = isEmbedded ? embeddedPath.slice() : [];
|
|
661
|
+
// we use the field.name instead of prop here because we want to use the cache-path not
|
|
662
|
+
// the record path.
|
|
663
|
+
propArray.push(field.name);
|
|
664
|
+
// propArray.push(prop as string);
|
|
665
|
+
|
|
608
666
|
switch (field.kind) {
|
|
609
667
|
case '@id':
|
|
610
668
|
entangleSignal(signals, receiver, '@identity');
|
|
@@ -619,7 +677,7 @@ class SchemaRecord {
|
|
|
619
677
|
return lastValue;
|
|
620
678
|
}
|
|
621
679
|
case 'field':
|
|
622
|
-
macroCondition(getGlobalConfig().
|
|
680
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
623
681
|
if (!test) {
|
|
624
682
|
throw new Error(`SchemaRecord.${field.name} is not available in legacy mode because it has type '${field.kind}'`);
|
|
625
683
|
}
|
|
@@ -630,7 +688,7 @@ class SchemaRecord {
|
|
|
630
688
|
entangleSignal(signals, receiver, field.name);
|
|
631
689
|
return computeAttribute(cache, identifier, prop);
|
|
632
690
|
case 'resource':
|
|
633
|
-
macroCondition(getGlobalConfig().
|
|
691
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
634
692
|
if (!test) {
|
|
635
693
|
throw new Error(`SchemaRecord.${field.name} is not available in legacy mode because it has type '${field.kind}'`);
|
|
636
694
|
}
|
|
@@ -641,43 +699,53 @@ class SchemaRecord {
|
|
|
641
699
|
return computeDerivation(schema, receiver, identifier, field, prop);
|
|
642
700
|
case 'schema-array':
|
|
643
701
|
entangleSignal(signals, receiver, field.name);
|
|
644
|
-
return computeArray(store, schema, cache, target, identifier, field, propArray, true);
|
|
702
|
+
return computeArray(store, schema, cache, target, identifier, field, propArray, true, Mode[Editable], Mode[Legacy]);
|
|
645
703
|
case 'array':
|
|
646
|
-
macroCondition(getGlobalConfig().
|
|
704
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
647
705
|
if (!test) {
|
|
648
706
|
throw new Error(`SchemaRecord.${field.name} is not available in legacy mode because it has type '${field.kind}'`);
|
|
649
707
|
}
|
|
650
708
|
})(!target[Legacy]) : {};
|
|
651
709
|
entangleSignal(signals, receiver, field.name);
|
|
652
|
-
return computeArray(store, schema, cache, target, identifier, field, propArray);
|
|
653
|
-
case 'schema-object':
|
|
654
|
-
// validate any access off of schema, no transform to run
|
|
655
|
-
// use raw cache value as the object to manage
|
|
656
|
-
entangleSignal(signals, receiver, field.name);
|
|
657
|
-
return computeObject(store, schema, cache, target, identifier, field, prop, true);
|
|
710
|
+
return computeArray(store, schema, cache, target, identifier, field, propArray, false, Mode[Editable], Mode[Legacy]);
|
|
658
711
|
case 'object':
|
|
659
|
-
macroCondition(getGlobalConfig().
|
|
712
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
713
|
+
if (!test) {
|
|
714
|
+
throw new Error(`SchemaRecord.${field.name} is not available in legacy mode because it has type '${field.kind}'`);
|
|
715
|
+
}
|
|
716
|
+
})(!target[Legacy]) : {};
|
|
717
|
+
entangleSignal(signals, receiver, field.name);
|
|
718
|
+
return computeObject(schema, cache, target, identifier, field, propArray, Mode[Editable], Mode[Legacy]);
|
|
719
|
+
case 'schema-object':
|
|
720
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
660
721
|
if (!test) {
|
|
661
722
|
throw new Error(`SchemaRecord.${field.name} is not available in legacy mode because it has type '${field.kind}'`);
|
|
662
723
|
}
|
|
663
724
|
})(!target[Legacy]) : {};
|
|
664
725
|
entangleSignal(signals, receiver, field.name);
|
|
665
726
|
// run transform, then use that value as the object to manage
|
|
666
|
-
return
|
|
727
|
+
return computeSchemaObject(store, cache, target, identifier, field, propArray, Mode[Legacy], Mode[Editable]);
|
|
667
728
|
case 'belongsTo':
|
|
729
|
+
if (field.options.linksMode) {
|
|
730
|
+
entangleSignal(signals, receiver, field.name);
|
|
731
|
+
const rawValue = cache.getRelationship(identifier, field.name);
|
|
732
|
+
|
|
733
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
734
|
+
return rawValue.data ? store.peekRecord(rawValue.data) : null;
|
|
735
|
+
}
|
|
668
736
|
if (!HAS_MODEL_PACKAGE) {
|
|
669
|
-
macroCondition(getGlobalConfig().
|
|
737
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
670
738
|
{
|
|
671
739
|
throw new Error(`Cannot use belongsTo fields in your schema unless @ember-data-mirror/model is installed to provide legacy model support. ${field.name} should likely be migrated to be a resource field.`);
|
|
672
740
|
}
|
|
673
741
|
})() : {};
|
|
674
742
|
}
|
|
675
|
-
macroCondition(getGlobalConfig().
|
|
743
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
676
744
|
if (!test) {
|
|
677
745
|
throw new Error(`Expected to have a getLegacySupport function`);
|
|
678
746
|
}
|
|
679
747
|
})(getLegacySupport) : {};
|
|
680
|
-
macroCondition(getGlobalConfig().
|
|
748
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
681
749
|
if (!test) {
|
|
682
750
|
throw new Error(`Can only use belongsTo fields when the resource is in legacy mode`);
|
|
683
751
|
}
|
|
@@ -686,18 +754,18 @@ class SchemaRecord {
|
|
|
686
754
|
return getLegacySupport(receiver).getBelongsTo(field.name);
|
|
687
755
|
case 'hasMany':
|
|
688
756
|
if (!HAS_MODEL_PACKAGE) {
|
|
689
|
-
macroCondition(getGlobalConfig().
|
|
757
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
690
758
|
{
|
|
691
759
|
throw new Error(`Cannot use hasMany fields in your schema unless @ember-data-mirror/model is installed to provide legacy model support. ${field.name} should likely be migrated to be a collection field.`);
|
|
692
760
|
}
|
|
693
761
|
})() : {};
|
|
694
762
|
}
|
|
695
|
-
macroCondition(getGlobalConfig().
|
|
763
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
696
764
|
if (!test) {
|
|
697
765
|
throw new Error(`Expected to have a getLegacySupport function`);
|
|
698
766
|
}
|
|
699
767
|
})(getLegacySupport) : {};
|
|
700
|
-
macroCondition(getGlobalConfig().
|
|
768
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
701
769
|
if (!test) {
|
|
702
770
|
throw new Error(`Can only use hasMany fields when the resource is in legacy mode`);
|
|
703
771
|
}
|
|
@@ -710,25 +778,37 @@ class SchemaRecord {
|
|
|
710
778
|
},
|
|
711
779
|
set(target, prop, value, receiver) {
|
|
712
780
|
if (!IS_EDITABLE) {
|
|
713
|
-
|
|
781
|
+
const type = isEmbedded ? embeddedType : identifier.type;
|
|
782
|
+
throw new Error(`Cannot set ${String(prop)} on ${type} because the record is not editable`);
|
|
714
783
|
}
|
|
715
|
-
const
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
throw new Error(`There is no field named ${String(prop)} on ${identifier.type}`);
|
|
784
|
+
const maybeField = prop === identityField?.name ? identityField : fields.get(prop);
|
|
785
|
+
if (!maybeField) {
|
|
786
|
+
const type = isEmbedded ? embeddedType : identifier.type;
|
|
787
|
+
throw new Error(`There is no field named ${String(prop)} on ${type}`);
|
|
720
788
|
}
|
|
789
|
+
const field = maybeField.kind === 'alias' ? maybeField.options : maybeField;
|
|
790
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
791
|
+
if (!test) {
|
|
792
|
+
throw new Error(`Alias fields cannot alias '@id' '@local' '@hash' or 'derived' fields`);
|
|
793
|
+
}
|
|
794
|
+
})(maybeField.kind !== 'alias' || !['@id', '@local', '@hash', 'derived'].includes(maybeField.options.kind)) : {};
|
|
795
|
+
const propArray = isEmbedded ? embeddedPath.slice() : [];
|
|
796
|
+
// we use the field.name instead of prop here because we want to use the cache-path not
|
|
797
|
+
// the record path.
|
|
798
|
+
propArray.push(field.name);
|
|
799
|
+
// propArray.push(prop as string);
|
|
800
|
+
|
|
721
801
|
switch (field.kind) {
|
|
722
802
|
case '@id':
|
|
723
803
|
{
|
|
724
|
-
macroCondition(getGlobalConfig().
|
|
804
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
725
805
|
if (!test) {
|
|
726
806
|
throw new Error(`Expected to receive a string id`);
|
|
727
807
|
}
|
|
728
808
|
})(typeof value === 'string' && value.length) : {};
|
|
729
809
|
const normalizedId = String(value);
|
|
730
810
|
const didChange = normalizedId !== identifier.id;
|
|
731
|
-
macroCondition(getGlobalConfig().
|
|
811
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
732
812
|
if (!test) {
|
|
733
813
|
throw new Error(`Cannot set ${identifier.type} record's id to ${normalizedId}, because id is already ${identifier.id}`);
|
|
734
814
|
}
|
|
@@ -840,6 +920,11 @@ class SchemaRecord {
|
|
|
840
920
|
{
|
|
841
921
|
let newValue = value;
|
|
842
922
|
if (value !== null) {
|
|
923
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
924
|
+
if (!test) {
|
|
925
|
+
throw new Error(`Expected value to be an object`);
|
|
926
|
+
}
|
|
927
|
+
})(typeof value === 'object') : {};
|
|
843
928
|
newValue = {
|
|
844
929
|
...value
|
|
845
930
|
};
|
|
@@ -855,11 +940,11 @@ class SchemaRecord {
|
|
|
855
940
|
ManagedObjectMap.delete(target);
|
|
856
941
|
}
|
|
857
942
|
cache.setAttr(identifier, propArray, newValue);
|
|
858
|
-
const peeked = peekManagedObject(self, field);
|
|
859
|
-
if (peeked) {
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
}
|
|
943
|
+
// const peeked = peekManagedObject(self, field);
|
|
944
|
+
// if (peeked) {
|
|
945
|
+
// const objSignal = peeked[OBJECT_SIGNAL];
|
|
946
|
+
// objSignal.shouldReset = true;
|
|
947
|
+
// }
|
|
863
948
|
return true;
|
|
864
949
|
}
|
|
865
950
|
case 'derived':
|
|
@@ -868,18 +953,18 @@ class SchemaRecord {
|
|
|
868
953
|
}
|
|
869
954
|
case 'belongsTo':
|
|
870
955
|
if (!HAS_MODEL_PACKAGE) {
|
|
871
|
-
macroCondition(getGlobalConfig().
|
|
956
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
872
957
|
{
|
|
873
958
|
throw new Error(`Cannot use belongsTo fields in your schema unless @ember-data-mirror/model is installed to provide legacy model support. ${field.name} should likely be migrated to be a resource field.`);
|
|
874
959
|
}
|
|
875
960
|
})() : {};
|
|
876
961
|
}
|
|
877
|
-
macroCondition(getGlobalConfig().
|
|
962
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
878
963
|
if (!test) {
|
|
879
964
|
throw new Error(`Expected to have a getLegacySupport function`);
|
|
880
965
|
}
|
|
881
966
|
})(getLegacySupport) : {};
|
|
882
|
-
macroCondition(getGlobalConfig().
|
|
967
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
883
968
|
if (!test) {
|
|
884
969
|
throw new Error(`Can only use belongsTo fields when the resource is in legacy mode`);
|
|
885
970
|
}
|
|
@@ -890,23 +975,23 @@ class SchemaRecord {
|
|
|
890
975
|
return true;
|
|
891
976
|
case 'hasMany':
|
|
892
977
|
if (!HAS_MODEL_PACKAGE) {
|
|
893
|
-
macroCondition(getGlobalConfig().
|
|
978
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
894
979
|
{
|
|
895
980
|
throw new Error(`Cannot use hasMany fields in your schema unless @ember-data-mirror/model is installed to provide legacy model support. ${field.name} should likely be migrated to be a collection field.`);
|
|
896
981
|
}
|
|
897
982
|
})() : {};
|
|
898
983
|
}
|
|
899
|
-
macroCondition(getGlobalConfig().
|
|
984
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
900
985
|
if (!test) {
|
|
901
986
|
throw new Error(`Expected to have a getLegacySupport function`);
|
|
902
987
|
}
|
|
903
988
|
})(getLegacySupport) : {};
|
|
904
|
-
macroCondition(getGlobalConfig().
|
|
989
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
905
990
|
if (!test) {
|
|
906
991
|
throw new Error(`Can only use hasMany fields when the resource is in legacy mode`);
|
|
907
992
|
}
|
|
908
993
|
})(Mode[Legacy]) : {};
|
|
909
|
-
macroCondition(getGlobalConfig().
|
|
994
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
910
995
|
if (!test) {
|
|
911
996
|
throw new Error(`You must pass an array of records to set a hasMany relationship`);
|
|
912
997
|
}
|
|
@@ -974,7 +1059,7 @@ class SchemaRecord {
|
|
|
974
1059
|
addToTransaction(arrSignal);
|
|
975
1060
|
}
|
|
976
1061
|
}
|
|
977
|
-
if (field?.kind === 'object'
|
|
1062
|
+
if (field?.kind === 'object') {
|
|
978
1063
|
const peeked = peekManagedObject(self, field);
|
|
979
1064
|
if (peeked) {
|
|
980
1065
|
const objSignal = peeked[OBJECT_SIGNAL];
|
|
@@ -991,7 +1076,7 @@ class SchemaRecord {
|
|
|
991
1076
|
if (isEmbedded) return; // base paths never apply to embedded records
|
|
992
1077
|
|
|
993
1078
|
const field = fields.get(key);
|
|
994
|
-
macroCondition(getGlobalConfig().
|
|
1079
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
995
1080
|
if (!test) {
|
|
996
1081
|
throw new Error(`Expected relationshp ${key} to be the name of a field`);
|
|
997
1082
|
}
|
|
@@ -1005,12 +1090,12 @@ class SchemaRecord {
|
|
|
1005
1090
|
}
|
|
1006
1091
|
// FIXME
|
|
1007
1092
|
} else if (field.kind === 'resource') ;else if (field.kind === 'hasMany') {
|
|
1008
|
-
macroCondition(getGlobalConfig().
|
|
1093
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
1009
1094
|
if (!test) {
|
|
1010
1095
|
throw new Error(`Expected to have a getLegacySupport function`);
|
|
1011
1096
|
}
|
|
1012
1097
|
})(getLegacySupport) : {};
|
|
1013
|
-
macroCondition(getGlobalConfig().
|
|
1098
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
1014
1099
|
if (!test) {
|
|
1015
1100
|
throw new Error(`Can only use hasMany fields when the resource is in legacy mode`);
|
|
1016
1101
|
}
|
|
@@ -1025,12 +1110,12 @@ class SchemaRecord {
|
|
|
1025
1110
|
}
|
|
1026
1111
|
if (manyArray) {
|
|
1027
1112
|
manyArray.notify();
|
|
1028
|
-
macroCondition(getGlobalConfig().
|
|
1113
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
1029
1114
|
if (!test) {
|
|
1030
1115
|
throw new Error(`Expected options to exist on relationship meta`);
|
|
1031
1116
|
}
|
|
1032
1117
|
})(field.options) : {};
|
|
1033
|
-
macroCondition(getGlobalConfig().
|
|
1118
|
+
macroCondition(getGlobalConfig().WarpDriveMirror.env.DEBUG) ? (test => {
|
|
1034
1119
|
if (!test) {
|
|
1035
1120
|
throw new Error(`Expected async to exist on relationship meta options`);
|
|
1036
1121
|
}
|
|
@@ -1060,7 +1145,22 @@ class SchemaRecord {
|
|
|
1060
1145
|
this[RecordStore].notifications.unsubscribe(this.___notifications);
|
|
1061
1146
|
}
|
|
1062
1147
|
[Checkout]() {
|
|
1063
|
-
|
|
1148
|
+
const editable = Editables.get(this);
|
|
1149
|
+
if (editable) {
|
|
1150
|
+
return Promise.resolve(editable);
|
|
1151
|
+
}
|
|
1152
|
+
const embeddedType = this[EmbeddedType];
|
|
1153
|
+
const embeddedPath = this[EmbeddedPath];
|
|
1154
|
+
const isEmbedded = embeddedType !== null && embeddedPath !== null;
|
|
1155
|
+
if (isEmbedded) {
|
|
1156
|
+
throw new Error(`Cannot checkout an embedded record (yet)`);
|
|
1157
|
+
}
|
|
1158
|
+
const editableRecord = new SchemaRecord(this[RecordStore], this[Identifier], {
|
|
1159
|
+
[Editable]: true,
|
|
1160
|
+
[Legacy]: this[Legacy]
|
|
1161
|
+
}, isEmbedded, embeddedType, embeddedPath);
|
|
1162
|
+
setRecordIdentifier(editableRecord, recordIdentifierFor(this));
|
|
1163
|
+
return Promise.resolve(editableRecord);
|
|
1064
1164
|
}
|
|
1065
1165
|
}
|
|
1066
|
-
export { Editable, Legacy, SchemaRecord };
|
|
1166
|
+
export { Checkout, Editable, Legacy, SchemaRecord };
|