@warp-drive/schema-record 0.0.1 → 0.0.3

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.
Files changed (54) hide show
  1. package/LICENSE.md +19 -8
  2. package/README.md +231 -129
  3. package/dist/-private.js +1 -0
  4. package/dist/-private.js.map +1 -0
  5. package/dist/{record.js → index.js} +700 -99
  6. package/dist/index.js.map +1 -0
  7. package/dist/symbols-DqoS4ybV.js.map +1 -1
  8. package/logos/NCC-1701-a-gold.svg +4 -0
  9. package/logos/NCC-1701-a-gold_100.svg +1 -0
  10. package/logos/NCC-1701-a-gold_base-64.txt +1 -0
  11. package/logos/README.md +4 -0
  12. package/logos/docs-badge.svg +2 -0
  13. package/logos/ember-data-logo-dark.svg +12 -0
  14. package/logos/ember-data-logo-light.svg +12 -0
  15. package/logos/github-header.svg +444 -0
  16. package/logos/social1.png +0 -0
  17. package/logos/social2.png +0 -0
  18. package/logos/warp-drive-logo-dark.svg +4 -0
  19. package/logos/warp-drive-logo-gold.svg +4 -0
  20. package/package.json +32 -58
  21. package/unstable-preview-types/-private/{compute.d.ts → fields/compute.d.ts} +17 -15
  22. package/unstable-preview-types/-private/fields/compute.d.ts.map +1 -0
  23. package/unstable-preview-types/-private/{managed-array.d.ts → fields/managed-array.d.ts} +4 -4
  24. package/unstable-preview-types/-private/fields/managed-array.d.ts.map +1 -0
  25. package/unstable-preview-types/-private/{managed-object.d.ts → fields/managed-object.d.ts} +4 -4
  26. package/unstable-preview-types/-private/fields/managed-object.d.ts.map +1 -0
  27. package/unstable-preview-types/-private/fields/many-array-manager.d.ts +23 -0
  28. package/unstable-preview-types/-private/fields/many-array-manager.d.ts.map +1 -0
  29. package/unstable-preview-types/{hooks.d.ts → -private/hooks.d.ts} +3 -3
  30. package/unstable-preview-types/-private/hooks.d.ts.map +1 -0
  31. package/unstable-preview-types/{record.d.ts → -private/record.d.ts} +3 -3
  32. package/unstable-preview-types/-private/record.d.ts.map +1 -0
  33. package/unstable-preview-types/{schema.d.ts → -private/schema.d.ts} +61 -11
  34. package/unstable-preview-types/-private/schema.d.ts.map +1 -0
  35. package/unstable-preview-types/{symbols.d.ts → -private/symbols.d.ts} +1 -1
  36. package/unstable-preview-types/-private/symbols.d.ts.map +1 -0
  37. package/unstable-preview-types/-private.d.ts +4 -0
  38. package/unstable-preview-types/-private.d.ts.map +1 -0
  39. package/unstable-preview-types/index.d.ts +353 -7
  40. package/unstable-preview-types/index.d.ts.map +1 -0
  41. package/dist/hooks.js +0 -19
  42. package/dist/hooks.js.map +0 -1
  43. package/dist/record.js.map +0 -1
  44. package/dist/schema.js +0 -278
  45. package/dist/schema.js.map +0 -1
  46. package/unstable-preview-types/-private/compute.d.ts.map +0 -1
  47. package/unstable-preview-types/-private/managed-array.d.ts.map +0 -1
  48. package/unstable-preview-types/-private/managed-object.d.ts.map +0 -1
  49. package/unstable-preview-types/hooks.d.ts.map +0 -1
  50. package/unstable-preview-types/record.d.ts.map +0 -1
  51. package/unstable-preview-types/schema.d.ts.map +0 -1
  52. package/unstable-preview-types/symbols.d.ts.map +0 -1
  53. /package/{NCC-1701-a-blue.svg → logos/NCC-1701-a-blue.svg} +0 -0
  54. /package/{NCC-1701-a.svg → logos/NCC-1701-a.svg} +0 -0
@@ -1,10 +1,14 @@
1
+ import { isResourceSchema } from '@warp-drive/core-types/schema/fields';
1
2
  import { macroCondition, getGlobalConfig, dependencySatisfies, importSync } from '@embroider/macros';
2
- import { setRecordIdentifier, recordIdentifierFor } from '@ember-data/store/-private';
3
- import { createSignal, subscribe, defineSignal, peekSignal, getSignal, Signals, entangleSignal, addToTransaction } from '@ember-data/tracking/-private';
4
- import { STRUCTURED } from '@warp-drive/core-types/request';
5
- import { RecordStore } from '@warp-drive/core-types/symbols';
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';
5
+ import { EnableHydration, STRUCTURED } from '@warp-drive/core-types/request';
6
+ import { RecordStore, Type } from '@warp-drive/core-types/symbols';
6
7
  import { getOrSetGlobal } from '@warp-drive/core-types/-private';
7
8
  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";
9
+ import { deprecate } from '@ember/debug';
10
+ import { recordIdentifierFor as recordIdentifierFor$1 } from '@ember-data/store';
11
+ import { createCache, getValue } from '@ember-data/tracking';
8
12
  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']);
9
13
  // const ARRAY_SETTER_METHODS = new Set<KeyType>(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
10
14
  const SYNC_PROPS = new Set(['[]', 'length']);
@@ -257,6 +261,12 @@ class ManagedArray {
257
261
  _SIGNAL.shouldReset = true;
258
262
  }
259
263
  return reflect;
264
+ },
265
+ has(target, prop) {
266
+ if (prop === 'identifier' || prop === 'owner' || prop === ARRAY_SIGNAL) {
267
+ return true;
268
+ }
269
+ return Reflect.has(target, prop);
260
270
  }
261
271
  });
262
272
  return proxy;
@@ -298,7 +308,7 @@ class ManagedObject {
298
308
  return self[prop];
299
309
  }
300
310
  if (prop === Symbol.toPrimitive) {
301
- return null;
311
+ return () => null;
302
312
  }
303
313
  if (prop === Symbol.toStringTag) {
304
314
  return `ManagedObject<${identifier.type}:${identifier.id} (${identifier.lid})>`;
@@ -313,7 +323,12 @@ class ManagedObject {
313
323
  }
314
324
  if (prop === 'toHTML') {
315
325
  return function () {
316
- return '<div>ManagedObject</div>';
326
+ return '<span>ManagedObject</span>';
327
+ };
328
+ }
329
+ if (prop === 'toJSON') {
330
+ return function () {
331
+ return structuredClone(self[SOURCE]);
317
332
  };
318
333
  }
319
334
  if (_SIGNAL.shouldReset) {
@@ -360,6 +375,81 @@ class ManagedObject {
360
375
  return proxy;
361
376
  }
362
377
  }
378
+ class ManyArrayManager {
379
+ constructor(record) {
380
+ this.record = record;
381
+ this.store = record[RecordStore];
382
+ this.identifier = record[Identifier];
383
+ }
384
+ _syncArray(array) {
385
+ const rawValue = this.store.cache.getRelationship(this.identifier, array.key);
386
+ if (rawValue.meta) {
387
+ array.meta = rawValue.meta;
388
+ }
389
+ if (rawValue.links) {
390
+ array.links = rawValue.links;
391
+ }
392
+ const currentState = array[SOURCE$1];
393
+
394
+ // unlike in the normal RecordArray case, we don't need to divorce the reference
395
+ // because we don't need to worry about associate/disassociate since the graph
396
+ // takes care of that for us
397
+ if (currentState !== rawValue.data) {
398
+ currentState.length = 0;
399
+ fastPush(currentState, rawValue.data);
400
+ }
401
+ }
402
+ reloadHasMany(key, options) {
403
+ const field = this.store.schema.fields(this.identifier).get(key);
404
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
405
+ if (!test) {
406
+ throw new Error(`Expected a hasMany field for ${key}`);
407
+ }
408
+ })(field?.kind === 'hasMany') : {};
409
+ const cacheOptions = options ? extractCacheOptions(options) : {
410
+ reload: true
411
+ };
412
+ cacheOptions.types = [field.type];
413
+ const rawValue = this.store.cache.getRelationship(this.identifier, key);
414
+ const req = {
415
+ url: getRelatedLink(rawValue),
416
+ op: 'findHasMany',
417
+ method: 'GET',
418
+ records: rawValue.data,
419
+ cacheOptions,
420
+ options: {
421
+ field,
422
+ identifier: this.identifier,
423
+ links: rawValue.links,
424
+ meta: rawValue.meta
425
+ },
426
+ [EnableHydration]: false
427
+ };
428
+ return this.store.request(req);
429
+ }
430
+ mutate(mutation) {
431
+ this.cache.mutate(mutation);
432
+ }
433
+ }
434
+ function getRelatedLink(resource) {
435
+ const related = resource.links?.related;
436
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
437
+ if (!test) {
438
+ throw new Error(`Expected a related link`);
439
+ }
440
+ })(related) : {};
441
+ return typeof related === 'object' ? related.href : related;
442
+ }
443
+ function extractCacheOptions(options) {
444
+ const cacheOptions = {};
445
+ if ('reload' in options) {
446
+ cacheOptions.reload = options.reload;
447
+ }
448
+ if ('backgroundReload' in options) {
449
+ cacheOptions.backgroundReload = options.backgroundReload;
450
+ }
451
+ return cacheOptions;
452
+ }
363
453
  const ManagedArrayMap = getOrSetGlobal('ManagedArrayMap', new Map());
364
454
  const ManagedObjectMap = getOrSetGlobal('ManagedObjectMap', new Map());
365
455
  function computeLocal(record, field, prop) {
@@ -373,24 +463,25 @@ function computeLocal(record, field, prop) {
373
463
  function peekManagedArray(record, field) {
374
464
  const managedArrayMapForRecord = ManagedArrayMap.get(record);
375
465
  if (managedArrayMapForRecord) {
376
- return managedArrayMapForRecord.get(field);
466
+ return managedArrayMapForRecord.get(field.name);
377
467
  }
378
468
  }
379
469
  function peekManagedObject(record, field) {
380
470
  const managedObjectMapForRecord = ManagedObjectMap.get(record);
381
471
  if (managedObjectMapForRecord) {
382
- return managedObjectMapForRecord.get(field);
472
+ return managedObjectMapForRecord.get(field.name);
383
473
  }
384
474
  }
385
- function computeField(schema, cache, record, identifier, field, prop) {
386
- const rawValue = cache.getAttr(identifier, prop);
475
+ function computeField(schema, cache, record, identifier, field, prop, editable) {
476
+ const rawValue = editable ? cache.getAttr(identifier, prop) : cache.getRemoteAttr(identifier, prop);
387
477
  if (!field.type) {
388
478
  return rawValue;
389
479
  }
390
480
  const transform = schema.transformation(field);
391
481
  return transform.hydrate(rawValue, field.options ?? null, record);
392
482
  }
393
- function computeArray(store, schema, cache, record, identifier, field, path, isSchemaArray, editable, legacy) {
483
+ function computeArray(store, schema, cache, record, identifier, field, path, editable, legacy) {
484
+ const isSchemaArray = field.kind === 'schema-array';
394
485
  // the thing we hand out needs to know its owner and path in a private manner
395
486
  // its "address" is the parent identifier (identifier) + field name (field.name)
396
487
  // in the nested object case field name here is the full dot path from root resource to this value
@@ -400,20 +491,20 @@ function computeArray(store, schema, cache, record, identifier, field, path, isS
400
491
  const managedArrayMapForRecord = ManagedArrayMap.get(record);
401
492
  let managedArray;
402
493
  if (managedArrayMapForRecord) {
403
- managedArray = managedArrayMapForRecord.get(field);
494
+ managedArray = managedArrayMapForRecord.get(field.name);
404
495
  }
405
496
  if (managedArray) {
406
497
  return managedArray;
407
498
  } else {
408
- const rawValue = cache.getAttr(identifier, path);
499
+ const rawValue = editable ? cache.getAttr(identifier, path) : cache.getRemoteAttr(identifier, path);
409
500
  if (!rawValue) {
410
501
  return null;
411
502
  }
412
503
  managedArray = new ManagedArray(store, schema, cache, field, rawValue, identifier, path, record, isSchemaArray, editable, legacy);
413
504
  if (!managedArrayMapForRecord) {
414
- ManagedArrayMap.set(record, new Map([[field, managedArray]]));
505
+ ManagedArrayMap.set(record, new Map([[field.name, managedArray]]));
415
506
  } else {
416
- managedArrayMapForRecord.set(field, managedArray);
507
+ managedArrayMapForRecord.set(field.name, managedArray);
417
508
  }
418
509
  }
419
510
  return managedArray;
@@ -422,12 +513,12 @@ function computeObject(schema, cache, record, identifier, field, path, editable,
422
513
  const managedObjectMapForRecord = ManagedObjectMap.get(record);
423
514
  let managedObject;
424
515
  if (managedObjectMapForRecord) {
425
- managedObject = managedObjectMapForRecord.get(field);
516
+ managedObject = managedObjectMapForRecord.get(field.name);
426
517
  }
427
518
  if (managedObject) {
428
519
  return managedObject;
429
520
  } else {
430
- let rawValue = cache.getAttr(identifier, path);
521
+ let rawValue = editable ? cache.getAttr(identifier, path) : cache.getRemoteAttr(identifier, path);
431
522
  if (!rawValue) {
432
523
  return null;
433
524
  }
@@ -437,9 +528,9 @@ function computeObject(schema, cache, record, identifier, field, path, editable,
437
528
  }
438
529
  managedObject = new ManagedObject(schema, cache, field, rawValue, identifier, path, record, editable, legacy);
439
530
  if (!managedObjectMapForRecord) {
440
- ManagedObjectMap.set(record, new Map([[field, managedObject]]));
531
+ ManagedObjectMap.set(record, new Map([[field.name, managedObject]]));
441
532
  } else {
442
- managedObjectMapForRecord.set(field, managedObject);
533
+ managedObjectMapForRecord.set(field.name, managedObject);
443
534
  }
444
535
  }
445
536
  return managedObject;
@@ -448,12 +539,12 @@ function computeSchemaObject(store, cache, record, identifier, field, path, lega
448
539
  const schemaObjectMapForRecord = ManagedObjectMap.get(record);
449
540
  let schemaObject;
450
541
  if (schemaObjectMapForRecord) {
451
- schemaObject = schemaObjectMapForRecord.get(field);
542
+ schemaObject = schemaObjectMapForRecord.get(field.name);
452
543
  }
453
544
  if (schemaObject) {
454
545
  return schemaObject;
455
546
  } else {
456
- const rawValue = cache.getAttr(identifier, path);
547
+ const rawValue = editable ? cache.getAttr(identifier, path) : cache.getRemoteAttr(identifier, path);
457
548
  if (!rawValue) {
458
549
  return null;
459
550
  }
@@ -464,14 +555,14 @@ function computeSchemaObject(store, cache, record, identifier, field, path, lega
464
555
  }, true, field.type, embeddedPath);
465
556
  }
466
557
  if (!schemaObjectMapForRecord) {
467
- ManagedObjectMap.set(record, new Map([[field, schemaObject]]));
558
+ ManagedObjectMap.set(record, new Map([[field.name, schemaObject]]));
468
559
  } else {
469
- schemaObjectMapForRecord.set(field, schemaObject);
560
+ schemaObjectMapForRecord.set(field.name, schemaObject);
470
561
  }
471
562
  return schemaObject;
472
563
  }
473
- function computeAttribute(cache, identifier, prop) {
474
- return cache.getAttr(identifier, prop);
564
+ function computeAttribute(cache, identifier, prop, editable) {
565
+ return editable ? cache.getAttr(identifier, prop) : cache.getRemoteAttr(identifier, prop);
475
566
  }
476
567
  function computeDerivation(schema, record, identifier, field, prop) {
477
568
  return schema.derivation(field)(record, field.options ?? null, prop);
@@ -480,8 +571,8 @@ function computeDerivation(schema, record, identifier, field, prop) {
480
571
  // TODO probably this should just be a Document
481
572
  // but its separate until we work out the lid situation
482
573
  class ResourceRelationship {
483
- constructor(store, cache, parent, identifier, field, name) {
484
- const rawValue = cache.getRelationship(identifier, name);
574
+ constructor(store, cache, parent, identifier, field, name, editable) {
575
+ const rawValue = editable ? cache.getRelationship(identifier, name) : cache.getRemoteRelationship(identifier, name);
485
576
 
486
577
  // TODO setup true lids for relationship documents
487
578
  // @ts-expect-error we need to give relationship documents a lid
@@ -523,11 +614,56 @@ function getHref(link) {
523
614
  }
524
615
  return link.href;
525
616
  }
526
- function computeResource(store, cache, parent, identifier, field, prop) {
617
+ function computeResource(store, cache, parent, identifier, field, prop, editable) {
527
618
  if (field.kind !== 'resource') {
528
619
  throw new Error(`The schema for ${identifier.type}.${String(prop)} is not a resource relationship`);
529
620
  }
530
- return new ResourceRelationship(store, cache, parent, identifier, field, prop);
621
+ return new ResourceRelationship(store, cache, parent, identifier, field, prop, editable);
622
+ }
623
+ function computeHasMany(store, schema, cache, record, identifier, field, path, editable, legacy) {
624
+ // the thing we hand out needs to know its owner and path in a private manner
625
+ // its "address" is the parent identifier (identifier) + field name (field.name)
626
+ // in the nested object case field name here is the full dot path from root resource to this value
627
+ // its "key" is the field on the parent record
628
+ // its "owner" is the parent record
629
+
630
+ const managedArrayMapForRecord = ManagedArrayMap.get(record);
631
+ let managedArray;
632
+ if (managedArrayMapForRecord) {
633
+ managedArray = managedArrayMapForRecord.get(field.name);
634
+ }
635
+ if (managedArray) {
636
+ return managedArray;
637
+ } else {
638
+ const rawValue = cache.getRelationship(identifier, field.name);
639
+ if (!rawValue) {
640
+ return null;
641
+ }
642
+ managedArray = new RelatedCollection({
643
+ store,
644
+ type: field.type,
645
+ identifier,
646
+ cache,
647
+ identifiers: rawValue.data,
648
+ key: field.name,
649
+ meta: rawValue.meta || null,
650
+ links: rawValue.links || null,
651
+ isPolymorphic: field.options.polymorphic ?? false,
652
+ isAsync: field.options.async ?? false,
653
+ // TODO: Grab the proper value
654
+ _inverseIsAsync: false,
655
+ // @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
+ isLoaded: true,
658
+ allowMutation: editable
659
+ });
660
+ if (!managedArrayMapForRecord) {
661
+ ManagedArrayMap.set(record, new Map([[field.name, managedArray]]));
662
+ } else {
663
+ managedArrayMapForRecord.set(field.name, managedArray);
664
+ }
665
+ }
666
+ return managedArray;
531
667
  }
532
668
  const HAS_MODEL_PACKAGE = dependencySatisfies('@ember-data/model', '*');
533
669
  const getLegacySupport = macroCondition(dependencySatisfies('@ember-data/model', '*')) ? importSync('@ember-data/model/-private').lookupLegacySupport : null;
@@ -537,6 +673,9 @@ const RecordSymbols = new Set(symbolList);
537
673
  function isPathMatch(a, b) {
538
674
  return a.length === b.length && a.every((v, i) => v === b[i]);
539
675
  }
676
+ function isNonEnumerableProp(prop) {
677
+ return prop === 'constructor' || prop === 'prototype' || prop === '__proto__' || prop === 'toString' || prop === 'toJSON' || prop === 'toHTML' || typeof prop === 'symbol';
678
+ }
540
679
  const Editables = new WeakMap();
541
680
  class SchemaRecord {
542
681
  constructor(store, identifier, Mode, isEmbedded = false, embeddedType = null, embeddedPath = null) {
@@ -552,31 +691,46 @@ class SchemaRecord {
552
691
  this[Legacy] = Mode[Legacy] ?? false;
553
692
  const schema = store.schema;
554
693
  const cache = store.cache;
555
- const identityField = schema.resource(identifier).identity;
694
+ const identityField = schema.resource(isEmbedded ? {
695
+ type: embeddedType
696
+ } : identifier).identity;
697
+ const BoundFns = new Map();
556
698
  this[EmbeddedType] = embeddedType;
557
699
  this[EmbeddedPath] = embeddedPath;
558
- let fields;
559
- if (isEmbedded) {
560
- fields = schema.fields({
561
- type: embeddedType
562
- });
563
- } else {
564
- fields = schema.fields(identifier);
565
- }
700
+ const fields = isEmbedded ? schema.fields({
701
+ type: embeddedType
702
+ }) : schema.fields(identifier);
566
703
  const signals = new Map();
567
704
  this[Signals] = signals;
568
705
  const proxy = new Proxy(this, {
569
706
  ownKeys() {
570
- return Array.from(fields.keys());
707
+ const identityKey = identityField?.name;
708
+ const keys = Array.from(fields.keys());
709
+ if (identityKey) {
710
+ keys.unshift(identityKey);
711
+ }
712
+ return keys;
571
713
  },
572
714
  has(target, prop) {
715
+ if (prop === Destroy || prop === Checkout) {
716
+ return true;
717
+ }
573
718
  return fields.has(prop);
574
719
  },
575
720
  getOwnPropertyDescriptor(target, prop) {
576
- if (!fields.has(prop)) {
577
- throw new Error(`No field named ${String(prop)} on ${identifier.type}`);
721
+ const schemaForField = prop === identityField?.name ? identityField : fields.get(prop);
722
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
723
+ if (!test) {
724
+ throw new Error(`No field named ${String(prop)} on ${identifier.type}`);
725
+ }
726
+ })(schemaForField) : {};
727
+ if (isNonEnumerableProp(prop)) {
728
+ return {
729
+ writable: false,
730
+ enumerable: false,
731
+ configurable: true
732
+ };
578
733
  }
579
- const schemaForField = fields.get(prop);
580
734
  switch (schemaForField.kind) {
581
735
  case 'derived':
582
736
  return {
@@ -584,6 +738,12 @@ class SchemaRecord {
584
738
  enumerable: true,
585
739
  configurable: true
586
740
  };
741
+ case '@id':
742
+ return {
743
+ writable: identifier.id === null,
744
+ enumerable: true,
745
+ configurable: true
746
+ };
587
747
  case '@local':
588
748
  case 'field':
589
749
  case 'attribute':
@@ -601,28 +761,18 @@ class SchemaRecord {
601
761
  enumerable: true,
602
762
  configurable: true
603
763
  };
764
+ default:
765
+ return {
766
+ writable: false,
767
+ enumerable: false,
768
+ configurable: false
769
+ };
604
770
  }
605
771
  },
606
772
  get(target, prop, receiver) {
607
773
  if (RecordSymbols.has(prop)) {
608
774
  return target[prop];
609
775
  }
610
- if (prop === Symbol.toStringTag) {
611
- return `SchemaRecord<${identifier.type}:${identifier.id} (${identifier.lid})>`;
612
- }
613
- if (prop === 'toString') {
614
- return function () {
615
- return `SchemaRecord<${identifier.type}:${identifier.id} (${identifier.lid})>`;
616
- };
617
- }
618
- if (prop === 'toHTML') {
619
- return function () {
620
- return `<div>SchemaRecord<${identifier.type}:${identifier.id} (${identifier.lid})></div>`;
621
- };
622
- }
623
- if (prop === Symbol.toPrimitive) {
624
- return null;
625
- }
626
776
 
627
777
  // TODO make this a symbol
628
778
  if (prop === '___notifications') {
@@ -638,18 +788,75 @@ class SchemaRecord {
638
788
  if (IgnoredGlobalFields.has(prop)) {
639
789
  return undefined;
640
790
  }
791
+
792
+ /////////////////////////////////////////////////////////////
793
+ //// Note these bound function behaviors are essentially ////
794
+ //// built-in but overrideable derivations. ////
795
+ //// ////
796
+ //// The bar for this has to be "basic expectations of ////
797
+ /// an object" – very, very high ////
798
+ /////////////////////////////////////////////////////////////
799
+
800
+ if (prop === Symbol.toStringTag || prop === 'toString') {
801
+ let fn = BoundFns.get('toString');
802
+ if (!fn) {
803
+ fn = function () {
804
+ entangleSignal(signals, receiver, '@identity');
805
+ return `Record<${identifier.type}:${identifier.id} (${identifier.lid})>`;
806
+ };
807
+ BoundFns.set(prop, fn);
808
+ }
809
+ return fn;
810
+ }
811
+ if (prop === 'toHTML') {
812
+ let fn = BoundFns.get('toHTML');
813
+ if (!fn) {
814
+ fn = function () {
815
+ entangleSignal(signals, receiver, '@identity');
816
+ return `<span>Record<${identifier.type}:${identifier.id} (${identifier.lid})></span>`;
817
+ };
818
+ BoundFns.set(prop, fn);
819
+ }
820
+ return fn;
821
+ }
822
+ if (prop === 'toJSON') {
823
+ let fn = BoundFns.get('toJSON');
824
+ if (!fn) {
825
+ fn = function () {
826
+ const json = {};
827
+ for (const key in receiver) {
828
+ json[key] = receiver[key];
829
+ }
830
+ return json;
831
+ };
832
+ BoundFns.set(prop, fn);
833
+ }
834
+ return fn;
835
+ }
836
+ if (prop === Symbol.toPrimitive) return () => null;
837
+ if (prop === Symbol.iterator) {
838
+ let fn = BoundFns.get(Symbol.iterator);
839
+ if (!fn) {
840
+ fn = function* () {
841
+ for (const key in receiver) {
842
+ yield [key, receiver[key]];
843
+ }
844
+ };
845
+ BoundFns.set(Symbol.iterator, fn);
846
+ }
847
+ return fn;
848
+ }
641
849
  if (prop === 'constructor') {
642
850
  return SchemaRecord;
643
851
  }
644
852
  // too many things check for random symbols
645
- if (typeof prop === 'symbol') {
646
- return undefined;
647
- }
648
- let type = identifier.type;
649
- if (isEmbedded) {
650
- type = embeddedType;
651
- }
652
- throw new Error(`No field named ${String(prop)} on ${type}`);
853
+ if (typeof prop === 'symbol') return undefined;
854
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
855
+ {
856
+ throw new Error(`No field named ${String(prop)} on ${isEmbedded ? embeddedType : identifier.type}`);
857
+ }
858
+ })() : {};
859
+ return undefined;
653
860
  }
654
861
  const field = maybeField.kind === 'alias' ? maybeField.options : maybeField;
655
862
  macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
@@ -677,58 +884,31 @@ class SchemaRecord {
677
884
  return lastValue;
678
885
  }
679
886
  case 'field':
680
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
681
- if (!test) {
682
- throw new Error(`SchemaRecord.${field.name} is not available in legacy mode because it has type '${field.kind}'`);
683
- }
684
- })(!target[Legacy]) : {};
685
887
  entangleSignal(signals, receiver, field.name);
686
- return computeField(schema, cache, target, identifier, field, propArray);
888
+ return computeField(schema, cache, target, identifier, field, propArray, IS_EDITABLE);
687
889
  case 'attribute':
688
890
  entangleSignal(signals, receiver, field.name);
689
- return computeAttribute(cache, identifier, prop);
891
+ return computeAttribute(cache, identifier, prop, IS_EDITABLE);
690
892
  case 'resource':
691
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
692
- if (!test) {
693
- throw new Error(`SchemaRecord.${field.name} is not available in legacy mode because it has type '${field.kind}'`);
694
- }
695
- })(!target[Legacy]) : {};
696
893
  entangleSignal(signals, receiver, field.name);
697
- return computeResource(store, cache, target, identifier, field, prop);
894
+ return computeResource(store, cache, target, identifier, field, prop, IS_EDITABLE);
698
895
  case 'derived':
699
896
  return computeDerivation(schema, receiver, identifier, field, prop);
700
897
  case 'schema-array':
701
- entangleSignal(signals, receiver, field.name);
702
- return computeArray(store, schema, cache, target, identifier, field, propArray, true, Mode[Editable], Mode[Legacy]);
703
898
  case 'array':
704
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
705
- if (!test) {
706
- throw new Error(`SchemaRecord.${field.name} is not available in legacy mode because it has type '${field.kind}'`);
707
- }
708
- })(!target[Legacy]) : {};
709
899
  entangleSignal(signals, receiver, field.name);
710
- return computeArray(store, schema, cache, target, identifier, field, propArray, false, Mode[Editable], Mode[Legacy]);
900
+ return computeArray(store, schema, cache, target, identifier, field, propArray, Mode[Editable], Mode[Legacy]);
711
901
  case 'object':
712
- macroCondition(getGlobalConfig().WarpDrive.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
902
  entangleSignal(signals, receiver, field.name);
718
903
  return computeObject(schema, cache, target, identifier, field, propArray, Mode[Editable], Mode[Legacy]);
719
904
  case 'schema-object':
720
- macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
721
- if (!test) {
722
- throw new Error(`SchemaRecord.${field.name} is not available in legacy mode because it has type '${field.kind}'`);
723
- }
724
- })(!target[Legacy]) : {};
725
905
  entangleSignal(signals, receiver, field.name);
726
906
  // run transform, then use that value as the object to manage
727
907
  return computeSchemaObject(store, cache, target, identifier, field, propArray, Mode[Legacy], Mode[Editable]);
728
908
  case 'belongsTo':
729
909
  if (field.options.linksMode) {
730
910
  entangleSignal(signals, receiver, field.name);
731
- const rawValue = cache.getRelationship(identifier, field.name);
911
+ const rawValue = IS_EDITABLE ? cache.getRelationship(identifier, field.name) : cache.getRemoteRelationship(identifier, field.name);
732
912
 
733
913
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
734
914
  return rawValue.data ? store.peekRecord(rawValue.data) : null;
@@ -753,6 +933,10 @@ class SchemaRecord {
753
933
  entangleSignal(signals, receiver, field.name);
754
934
  return getLegacySupport(receiver).getBelongsTo(field.name);
755
935
  case 'hasMany':
936
+ if (field.options.linksMode) {
937
+ entangleSignal(signals, receiver, field.name);
938
+ return computeHasMany(store, schema, cache, target, identifier, field, propArray, Mode[Editable], Mode[Legacy]);
939
+ }
756
940
  if (!HAS_MODEL_PACKAGE) {
757
941
  macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
758
942
  {
@@ -850,6 +1034,11 @@ class SchemaRecord {
850
1034
  cache.setAttr(identifier, propArray, value?.slice());
851
1035
  const peeked = peekManagedArray(self, field);
852
1036
  if (peeked) {
1037
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1038
+ if (!test) {
1039
+ throw new Error(`Expected the peekManagedArray for ${field.kind} to return a ManagedArray`);
1040
+ }
1041
+ })(ARRAY_SIGNAL in peeked) : {};
853
1042
  const arrSignal = peeked[ARRAY_SIGNAL];
854
1043
  arrSignal.shouldReset = true;
855
1044
  }
@@ -863,6 +1052,11 @@ class SchemaRecord {
863
1052
  cache.setAttr(identifier, propArray, rawValue);
864
1053
  const peeked = peekManagedArray(self, field);
865
1054
  if (peeked) {
1055
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1056
+ if (!test) {
1057
+ throw new Error(`Expected the peekManagedArray for ${field.kind} to return a ManagedArray`);
1058
+ }
1059
+ })(ARRAY_SIGNAL in peeked) : {};
866
1060
  const arrSignal = peeked[ARRAY_SIGNAL];
867
1061
  arrSignal.shouldReset = true;
868
1062
  }
@@ -877,6 +1071,11 @@ class SchemaRecord {
877
1071
  cache.setAttr(identifier, propArray, arrayValue);
878
1072
  const peeked = peekManagedArray(self, field);
879
1073
  if (peeked) {
1074
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1075
+ if (!test) {
1076
+ throw new Error(`Expected the peekManagedArray for ${field.kind} to return a ManagedArray`);
1077
+ }
1078
+ })(ARRAY_SIGNAL in peeked) : {};
880
1079
  const arrSignal = peeked[ARRAY_SIGNAL];
881
1080
  arrSignal.shouldReset = true;
882
1081
  }
@@ -1054,6 +1253,11 @@ class SchemaRecord {
1054
1253
  if (field?.kind === 'array' || field?.kind === 'schema-array') {
1055
1254
  const peeked = peekManagedArray(self, field);
1056
1255
  if (peeked) {
1256
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1257
+ if (!test) {
1258
+ throw new Error(`Expected the peekManagedArray for ${field.kind} to return a ManagedArray`);
1259
+ }
1260
+ })(ARRAY_SIGNAL in peeked) : {};
1057
1261
  const arrSignal = peeked[ARRAY_SIGNAL];
1058
1262
  arrSignal.shouldReset = true;
1059
1263
  addToTransaction(arrSignal);
@@ -1090,6 +1294,16 @@ class SchemaRecord {
1090
1294
  }
1091
1295
  // FIXME
1092
1296
  } else if (field.kind === 'resource') ;else if (field.kind === 'hasMany') {
1297
+ if (field.options.linksMode) {
1298
+ const peeked = peekManagedArray(self, field);
1299
+ if (peeked) {
1300
+ // const arrSignal = peeked[ARRAY_SIGNAL];
1301
+ // arrSignal.shouldReset = true;
1302
+ // addToTransaction(arrSignal);
1303
+ peeked.notify();
1304
+ }
1305
+ return;
1306
+ }
1093
1307
  macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1094
1308
  if (!test) {
1095
1309
  throw new Error(`Expected to have a getLegacySupport function`);
@@ -1133,6 +1347,19 @@ class SchemaRecord {
1133
1347
  break;
1134
1348
  }
1135
1349
  });
1350
+ if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
1351
+ Object.defineProperty(this, '__SHOW_ME_THE_DATA_(debug mode only)__', {
1352
+ enumerable: false,
1353
+ configurable: true,
1354
+ get() {
1355
+ const data = {};
1356
+ for (const key of fields.keys()) {
1357
+ data[key] = proxy[key];
1358
+ }
1359
+ return data;
1360
+ }
1361
+ });
1362
+ }
1136
1363
  return proxy;
1137
1364
  }
1138
1365
  [Destroy]() {
@@ -1145,6 +1372,10 @@ class SchemaRecord {
1145
1372
  this[RecordStore].notifications.unsubscribe(this.___notifications);
1146
1373
  }
1147
1374
  [Checkout]() {
1375
+ // IF we are already the editable record, throw an error
1376
+ if (this[Editable]) {
1377
+ throw new Error(`Cannot checkout an already editable record`);
1378
+ }
1148
1379
  const editable = Editables.get(this);
1149
1380
  if (editable) {
1150
1381
  return Promise.resolve(editable);
@@ -1163,4 +1394,374 @@ class SchemaRecord {
1163
1394
  return Promise.resolve(editableRecord);
1164
1395
  }
1165
1396
  }
1166
- export { Checkout, Editable, Legacy, SchemaRecord };
1397
+ function instantiateRecord(store, identifier, createArgs) {
1398
+ const schema = store.schema;
1399
+ const resourceSchema = schema.resource(identifier);
1400
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1401
+ if (!test) {
1402
+ throw new Error(`Expected a resource schema`);
1403
+ }
1404
+ })(isResourceSchema(resourceSchema)) : {};
1405
+ const isLegacy = resourceSchema?.legacy ?? false;
1406
+ const isEditable = isLegacy || store.cache.isNew(identifier);
1407
+ const record = new SchemaRecord(store, identifier, {
1408
+ [Editable]: isEditable,
1409
+ [Legacy]: isLegacy
1410
+ });
1411
+ if (createArgs) {
1412
+ Object.assign(record, createArgs);
1413
+ }
1414
+ return record;
1415
+ }
1416
+ function assertSchemaRecord(record) {
1417
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1418
+ if (!test) {
1419
+ throw new Error('Expected a SchemaRecord');
1420
+ }
1421
+ })(record && typeof record === 'object' && Destroy in record) : {};
1422
+ }
1423
+ function teardownRecord(record) {
1424
+ assertSchemaRecord(record);
1425
+ record[Destroy]();
1426
+ }
1427
+
1428
+ /**
1429
+ * @module @warp-drive/schema-record
1430
+ */
1431
+ const Support = getOrSetGlobal('Support', new WeakMap());
1432
+ const ConstructorField = {
1433
+ type: '@constructor',
1434
+ name: 'constructor',
1435
+ kind: 'derived'
1436
+ };
1437
+ const TypeField = {
1438
+ type: '@identity',
1439
+ name: '$type',
1440
+ kind: 'derived',
1441
+ options: {
1442
+ key: 'type'
1443
+ }
1444
+ };
1445
+ const DefaultIdentityField = {
1446
+ name: 'id',
1447
+ kind: '@id'
1448
+ };
1449
+ function _constructor(record) {
1450
+ let state = Support.get(record);
1451
+ if (!state) {
1452
+ state = {};
1453
+ Support.set(record, state);
1454
+ }
1455
+ return state._constructor = state._constructor || {
1456
+ name: `SchemaRecord<${recordIdentifierFor$1(record).type}>`,
1457
+ get modelName() {
1458
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1459
+ {
1460
+ throw new Error(`record.constructor.modelName is not available outside of legacy mode`);
1461
+ }
1462
+ })() : {};
1463
+ return undefined;
1464
+ }
1465
+ };
1466
+ }
1467
+ _constructor[Type] = '@constructor';
1468
+
1469
+ /**
1470
+ * Utility for constructing a ResourceSchema with the recommended fields
1471
+ * for the Polaris experience.
1472
+ *
1473
+ * @method withDefaults
1474
+ * @for @warp-drive/schema-record
1475
+ * @static
1476
+ * @public
1477
+ * @param schema
1478
+ * @return {ResourceSchema}
1479
+ */
1480
+ function withDefaults(schema) {
1481
+ schema.identity = schema.identity || DefaultIdentityField;
1482
+
1483
+ // because fields gets iterated in definition order,
1484
+ // we add TypeField to the beginning so that it will
1485
+ // appear right next to the identity field
1486
+ schema.fields.unshift(TypeField);
1487
+ schema.fields.push(ConstructorField);
1488
+ return schema;
1489
+ }
1490
+
1491
+ /**
1492
+ * A derivation that computes its value from the
1493
+ * record's identity.
1494
+ *
1495
+ * It can be used via a derived field definition like:
1496
+ *
1497
+ * ```ts
1498
+ * {
1499
+ * kind: 'derived',
1500
+ * name: 'id',
1501
+ * type: '@identity',
1502
+ * options: { key: 'id' }
1503
+ * }
1504
+ * ```
1505
+ *
1506
+ * Valid keys are `'id'`, `'lid'`, `'type'`, and `'^'`.
1507
+ *
1508
+ * `^` returns the entire identifier object.
1509
+ *
1510
+ * @method fromIdentity
1511
+ * @for @warp-drive/schema-record
1512
+ * @static
1513
+ * @public
1514
+ */
1515
+
1516
+ function fromIdentity(record, options, key) {
1517
+ const identifier = record[Identifier];
1518
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1519
+ if (!test) {
1520
+ throw new Error(`Cannot compute @identity for a record without an identifier`);
1521
+ }
1522
+ })(identifier) : {};
1523
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1524
+ if (!test) {
1525
+ throw new Error(`Expected to receive a key to compute @identity, but got ${String(options)}`);
1526
+ }
1527
+ })(options?.key && ['lid', 'id', 'type', '^'].includes(options.key)) : {};
1528
+ return options.key === '^' ? identifier : identifier[options.key];
1529
+ }
1530
+ fromIdentity[Type] = '@identity';
1531
+
1532
+ /**
1533
+ * Registers the default derivations for the SchemaRecord
1534
+ *
1535
+ * @method registerDerivations
1536
+ * @for @warp-drive/schema-record
1537
+ * @static
1538
+ * @public
1539
+ * @param {SchemaService} schema
1540
+ */
1541
+ function registerDerivations(schema) {
1542
+ schema.registerDerivation(fromIdentity);
1543
+ schema.registerDerivation(_constructor);
1544
+ }
1545
+ /**
1546
+ * Wraps a derivation in a new function with Derivation signature but that looks
1547
+ * up the value in the cache before recomputing.
1548
+ *
1549
+ * @internal
1550
+ */
1551
+ function makeCachedDerivation(derivation) {
1552
+ const memoizedDerivation = (record, options, prop) => {
1553
+ const signals = record[Signals];
1554
+ let signal = signals.get(prop);
1555
+ if (!signal) {
1556
+ signal = createCache(() => {
1557
+ return derivation(record, options, prop);
1558
+ }); // a total lie, for convenience of reusing the storage
1559
+ signals.set(prop, signal);
1560
+ }
1561
+ return getValue(signal);
1562
+ };
1563
+ memoizedDerivation[Type] = derivation[Type];
1564
+ return memoizedDerivation;
1565
+ }
1566
+ /**
1567
+ * A SchemaService designed to work with dynamically registered schemas.
1568
+ *
1569
+ * @class SchemaService
1570
+ * @public
1571
+ */
1572
+ class SchemaService {
1573
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1574
+
1575
+ constructor() {
1576
+ this._schemas = new Map();
1577
+ this._transforms = new Map();
1578
+ this._hashFns = new Map();
1579
+ this._derivations = new Map();
1580
+ }
1581
+ resourceTypes() {
1582
+ return Array.from(this._schemas.keys());
1583
+ }
1584
+ hasTrait(type) {
1585
+ return this._traits.has(type);
1586
+ }
1587
+ resourceHasTrait(resource, trait) {
1588
+ return this._schemas.get(resource.type).traits.has(trait);
1589
+ }
1590
+ transformation(field) {
1591
+ const kind = 'kind' in field ? field.kind : '<unknown kind>';
1592
+ const name = 'name' in field ? field.name : '<unknown name>';
1593
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1594
+ if (!test) {
1595
+ throw new Error(`'${kind}' fields cannot be transformed. Only fields of kind 'field' 'object' or 'array' can specify a transformation. Attempted to find '${field.type ?? '<unknown type>'}' on field '${name}'.`);
1596
+ }
1597
+ })(!('kind' in field) || ['field', 'object', 'array'].includes(kind)) : {};
1598
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1599
+ if (!test) {
1600
+ throw new Error(`Expected the '${kind}' field '${name}' to specify a transformation via 'field.type', but none was present`);
1601
+ }
1602
+ })(field.type) : {};
1603
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1604
+ if (!test) {
1605
+ throw new Error(`No transformation registered with name '${field.type}' for '${kind}' field '${name}'`);
1606
+ }
1607
+ })(this._transforms.has(field.type)) : {};
1608
+ return this._transforms.get(field.type);
1609
+ }
1610
+ derivation(field) {
1611
+ const kind = 'kind' in field ? field.kind : '<unknown kind>';
1612
+ const name = 'name' in field ? field.name : '<unknown name>';
1613
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1614
+ if (!test) {
1615
+ throw new Error(`The '${kind}' field '${name}' is not derived and so cannot be used to lookup a derivation`);
1616
+ }
1617
+ })(!('kind' in field) || kind === 'derived') : {};
1618
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1619
+ if (!test) {
1620
+ throw new Error(`Expected the '${kind}' field '${name}' to specify a derivation via 'field.type', but no value was present`);
1621
+ }
1622
+ })(field.type) : {};
1623
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1624
+ if (!test) {
1625
+ throw new Error(`No '${field.type}' derivation registered for use by the '${kind}' field '${name}'`);
1626
+ }
1627
+ })(this._derivations.has(field.type)) : {};
1628
+ return this._derivations.get(field.type);
1629
+ }
1630
+ hashFn(field) {
1631
+ const kind = 'kind' in field ? field.kind : '<unknown kind>';
1632
+ const name = 'name' in field ? field.name : '<unknown name>';
1633
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1634
+ if (!test) {
1635
+ throw new Error(`The '${kind}' field '${name}' is not a HashField and so cannot be used to lookup a hash function`);
1636
+ }
1637
+ })(!('kind' in field) || kind === '@hash') : {};
1638
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1639
+ if (!test) {
1640
+ throw new Error(`Expected the '${kind}' field '${name}' to specify a hash function via 'field.type', but no value was present`);
1641
+ }
1642
+ })(field.type) : {};
1643
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1644
+ if (!test) {
1645
+ throw new Error(`No '${field.type}' hash function is registered for use by the '${kind}' field '${name}'`);
1646
+ }
1647
+ })(this._hashFns.has(field.type)) : {};
1648
+ return this._hashFns.get(field.type);
1649
+ }
1650
+ resource(resource) {
1651
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1652
+ if (!test) {
1653
+ throw new Error(`No resource registered with name '${resource.type}'`);
1654
+ }
1655
+ })(this._schemas.has(resource.type)) : {};
1656
+ return this._schemas.get(resource.type).original;
1657
+ }
1658
+ registerResources(schemas) {
1659
+ schemas.forEach(schema => {
1660
+ this.registerResource(schema);
1661
+ });
1662
+ }
1663
+ registerResource(schema) {
1664
+ const fields = new Map();
1665
+ const relationships = {};
1666
+ const attributes = {};
1667
+ schema.fields.forEach(field => {
1668
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1669
+ if (!test) {
1670
+ throw new Error(`${field.kind} is not valid inside a ResourceSchema's fields.`);
1671
+ }
1672
+ })(
1673
+ // @ts-expect-error we are checking for mistakes at runtime
1674
+ field.kind !== '@id' && field.kind !== '@hash') : {};
1675
+ fields.set(field.name, field);
1676
+ if (field.kind === 'attribute') {
1677
+ attributes[field.name] = field;
1678
+ } else if (field.kind === 'belongsTo' || field.kind === 'hasMany') {
1679
+ relationships[field.name] = field;
1680
+ }
1681
+ });
1682
+ const traits = new Set(isResourceSchema(schema) ? schema.traits : []);
1683
+ traits.forEach(trait => {
1684
+ this._traits.add(trait);
1685
+ });
1686
+ const internalSchema = {
1687
+ original: schema,
1688
+ fields,
1689
+ relationships,
1690
+ attributes,
1691
+ traits
1692
+ };
1693
+ this._schemas.set(schema.type, internalSchema);
1694
+ }
1695
+ registerTransformation(transformation) {
1696
+ this._transforms.set(transformation[Type], transformation);
1697
+ }
1698
+ registerDerivation(derivation) {
1699
+ this._derivations.set(derivation[Type], makeCachedDerivation(derivation));
1700
+ }
1701
+ registerHashFn(hashFn) {
1702
+ this._hashFns.set(hashFn[Type], hashFn);
1703
+ }
1704
+ fields({
1705
+ type
1706
+ }) {
1707
+ const schema = this._schemas.get(type);
1708
+ if (!schema) {
1709
+ throw new Error(`No schema defined for ${type}`);
1710
+ }
1711
+ return schema.fields;
1712
+ }
1713
+ hasResource(resource) {
1714
+ return this._schemas.has(resource.type);
1715
+ }
1716
+ }
1717
+ if (macroCondition(getGlobalConfig().WarpDrive.deprecations.ENABLE_LEGACY_SCHEMA_SERVICE)) {
1718
+ SchemaService.prototype.attributesDefinitionFor = function ({
1719
+ type
1720
+ }) {
1721
+ deprecate(`Use \`schema.fields({ type })\` instead of \`schema.attributesDefinitionFor({ type })\``, false, {
1722
+ id: 'ember-data:schema-service-updates',
1723
+ until: '6.0',
1724
+ for: 'ember-data',
1725
+ since: {
1726
+ available: '4.13',
1727
+ enabled: '5.4'
1728
+ }
1729
+ });
1730
+ const schema = this._schemas.get(type);
1731
+ if (!schema) {
1732
+ throw new Error(`No schema defined for ${type}`);
1733
+ }
1734
+ return schema.attributes;
1735
+ };
1736
+ SchemaService.prototype.relationshipsDefinitionFor = function ({
1737
+ type
1738
+ }) {
1739
+ deprecate(`Use \`schema.fields({ type })\` instead of \`schema.relationshipsDefinitionFor({ type })\``, false, {
1740
+ id: 'ember-data:schema-service-updates',
1741
+ until: '6.0',
1742
+ for: 'ember-data',
1743
+ since: {
1744
+ available: '4.13',
1745
+ enabled: '5.4'
1746
+ }
1747
+ });
1748
+ const schema = this._schemas.get(type);
1749
+ if (!schema) {
1750
+ throw new Error(`No schema defined for ${type}`);
1751
+ }
1752
+ return schema.relationships;
1753
+ };
1754
+ SchemaService.prototype.doesTypeExist = function (type) {
1755
+ deprecate(`Use \`schema.hasResource({ type })\` instead of \`schema.doesTypeExist(type)\``, false, {
1756
+ id: 'ember-data:schema-service-updates',
1757
+ until: '6.0',
1758
+ for: 'ember-data',
1759
+ since: {
1760
+ available: '4.13',
1761
+ enabled: '5.4'
1762
+ }
1763
+ });
1764
+ return this._schemas.has(type);
1765
+ };
1766
+ }
1767
+ export { Checkout, SchemaService, fromIdentity, instantiateRecord, registerDerivations, teardownRecord, withDefaults };