@ember-data/store 5.3.0-alpha.9 → 5.3.0-beta.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/addon/-private.js +1 -1
- package/addon/index.js +1 -1
- package/addon/index.js.map +1 -1
- package/addon/{store-service-845a5162.js → store-service-7ffc4d68.js} +394 -322
- package/addon/store-service-7ffc4d68.js.map +1 -0
- package/package.json +21 -21
- package/addon/store-service-845a5162.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { macroCondition, getOwnConfig } from '@embroider/macros';
|
|
2
2
|
import { getOwner } from '@ember/application';
|
|
3
|
-
import { assert, warn } from '@ember/debug';
|
|
3
|
+
import { assert, deprecate, warn } from '@ember/debug';
|
|
4
4
|
import EmberObject from '@ember/object';
|
|
5
5
|
import { _backburner } from '@ember/runloop';
|
|
6
6
|
import { tracked } from '@glimmer/tracking';
|
|
@@ -354,50 +354,67 @@ function copyDocumentProperties(target, source) {
|
|
|
354
354
|
}
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
-
/**
|
|
358
|
-
@module @ember-data/store
|
|
359
|
-
*/
|
|
360
|
-
|
|
361
357
|
// Used by the store to normalize IDs entering the store. Despite the fact
|
|
362
358
|
// that developers may provide IDs as numbers (e.g., `store.findRecord('person', 1)`),
|
|
363
359
|
// it is important that internally we use strings, since IDs may be serialized
|
|
364
360
|
// and lose type information. For example, Ember's router may put a record's
|
|
365
361
|
// ID into the URL, and if we later try to deserialize that URL and find the
|
|
366
362
|
// corresponding record, we will not know if it is a string or a number.
|
|
367
|
-
|
|
368
363
|
function coerceId(id) {
|
|
369
|
-
if (
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
364
|
+
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_NON_STRICT_ID)) {
|
|
365
|
+
let normalized;
|
|
366
|
+
if (id === null || id === undefined || id === '') {
|
|
367
|
+
normalized = null;
|
|
368
|
+
} else {
|
|
369
|
+
normalized = String(id);
|
|
370
|
+
}
|
|
371
|
+
deprecate(`The resource id '<${typeof id}> ${String(id)} ' is not normalized. Update your application code to use '${JSON.stringify(normalized)}' instead.`, normalized === id, {
|
|
372
|
+
id: 'ember-data:deprecate-non-strict-id',
|
|
373
|
+
until: '6.0',
|
|
374
|
+
for: 'ember-data',
|
|
375
|
+
since: {
|
|
376
|
+
available: '5.3',
|
|
377
|
+
enabled: '5.3'
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
return normalized;
|
|
377
381
|
}
|
|
378
|
-
|
|
382
|
+
assert(`Resource IDs must be a non-empty string or null. Received '${String(id)}'.`, id === null || typeof id === 'string' && id.length > 0);
|
|
383
|
+
return id;
|
|
379
384
|
}
|
|
380
385
|
function ensureStringId(id) {
|
|
381
386
|
let normalized = null;
|
|
382
387
|
if (typeof id === 'string') {
|
|
383
388
|
normalized = id.length > 0 ? id : null;
|
|
384
389
|
} else if (typeof id === 'number' && !isNaN(id)) {
|
|
385
|
-
normalized =
|
|
386
|
-
}
|
|
387
|
-
if (normalized === null) {
|
|
388
|
-
throw new Error(`Expected id to be a string or number, received ${String(id)}`);
|
|
390
|
+
normalized = String(id);
|
|
389
391
|
}
|
|
392
|
+
assert(`Expected id to be a string or number, received ${String(id)}`, normalized !== null);
|
|
390
393
|
return normalized;
|
|
391
394
|
}
|
|
392
395
|
|
|
393
396
|
// provided for additional debuggability
|
|
394
397
|
const DEBUG_CLIENT_ORIGINATED = Symbol('record-originated-on-client');
|
|
395
398
|
const DEBUG_IDENTIFIER_BUCKET = Symbol('identifier-bucket');
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
399
|
+
const DEBUG_STALE_CACHE_OWNER = Symbol('warpDriveStaleCache');
|
|
400
|
+
|
|
401
|
+
// also present in production
|
|
402
|
+
const CACHE_OWNER = Symbol('warpDriveCache');
|
|
403
|
+
function normalizeModelName(type) {
|
|
404
|
+
if (macroCondition(getOwnConfig().deprecations.DEPRECATE_NON_STRICT_TYPES)) {
|
|
405
|
+
const result = dasherize(type);
|
|
406
|
+
deprecate(`The resource type '${type}' is not normalized. Update your application code to use '${result}' instead of '${type}'.`, result === type, {
|
|
407
|
+
id: 'ember-data:deprecate-non-strict-types',
|
|
408
|
+
until: '6.0',
|
|
409
|
+
for: 'ember-data',
|
|
410
|
+
since: {
|
|
411
|
+
available: '5.3',
|
|
412
|
+
enabled: '5.3'
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
return result;
|
|
416
|
+
}
|
|
417
|
+
return type;
|
|
401
418
|
}
|
|
402
419
|
|
|
403
420
|
/**
|
|
@@ -441,6 +458,21 @@ function installPolyfill() {
|
|
|
441
458
|
};
|
|
442
459
|
}
|
|
443
460
|
}
|
|
461
|
+
function isResource(resource) {
|
|
462
|
+
return Boolean(resource && typeof resource === 'object');
|
|
463
|
+
}
|
|
464
|
+
function hasProp(resource, prop) {
|
|
465
|
+
return Boolean(isResource(resource) && prop in resource && typeof resource[prop] === 'string' && resource[prop].length);
|
|
466
|
+
}
|
|
467
|
+
function hasLid(resource) {
|
|
468
|
+
return hasProp(resource, 'lid');
|
|
469
|
+
}
|
|
470
|
+
function hasId(resource) {
|
|
471
|
+
return hasProp(resource, 'id') || Boolean(isResource(resource) && 'id' in resource && typeof resource.id === 'number');
|
|
472
|
+
}
|
|
473
|
+
function hasType(resource) {
|
|
474
|
+
return hasProp(resource, 'type');
|
|
475
|
+
}
|
|
444
476
|
|
|
445
477
|
/**
|
|
446
478
|
@module @ember-data/store
|
|
@@ -448,7 +480,7 @@ function installPolyfill() {
|
|
|
448
480
|
const IDENTIFIERS = new Set();
|
|
449
481
|
const DOCUMENTS = new Set();
|
|
450
482
|
function isStableIdentifier(identifier) {
|
|
451
|
-
return IDENTIFIERS.has(identifier);
|
|
483
|
+
return identifier[CACHE_OWNER] !== undefined || IDENTIFIERS.has(identifier);
|
|
452
484
|
}
|
|
453
485
|
function isDocumentIdentifier(identifier) {
|
|
454
486
|
return DOCUMENTS.has(identifier);
|
|
@@ -459,7 +491,7 @@ if (macroCondition(getOwnConfig().polyfillUUID)) {
|
|
|
459
491
|
installPolyfill();
|
|
460
492
|
}
|
|
461
493
|
function uuidv4() {
|
|
462
|
-
assert('crypto.randomUUID needs to be avaliable. Some browsers incorrectly disallow it in insecure contexts. You maybe want to enable the polyfill: https://github.com/emberjs/data#randomuuid-polyfill', _crypto.randomUUID);
|
|
494
|
+
assert('crypto.randomUUID needs to be avaliable. Some browsers incorrectly disallow it in insecure contexts. You maybe want to enable the polyfill: https://github.com/emberjs/data#randomuuid-polyfill', typeof _crypto.randomUUID === 'function');
|
|
463
495
|
return _crypto.randomUUID();
|
|
464
496
|
}
|
|
465
497
|
function freeze(obj) {
|
|
@@ -468,6 +500,9 @@ function freeze(obj) {
|
|
|
468
500
|
}
|
|
469
501
|
return obj;
|
|
470
502
|
}
|
|
503
|
+
|
|
504
|
+
// type IdentifierTypeLookup = { all: Set<StableRecordIdentifier>; id: Map<string, StableRecordIdentifier> };
|
|
505
|
+
// type IdentifiersByType = Map<string, IdentifierTypeLookup>;
|
|
471
506
|
let configuredForgetMethod;
|
|
472
507
|
let configuredGenerationMethod;
|
|
473
508
|
let configuredResetMethod;
|
|
@@ -484,20 +519,47 @@ function setIdentifierForgetMethod(method) {
|
|
|
484
519
|
function setIdentifierResetMethod(method) {
|
|
485
520
|
configuredResetMethod = method;
|
|
486
521
|
}
|
|
522
|
+
|
|
523
|
+
// Map<type, Map<id, lid>>
|
|
524
|
+
|
|
525
|
+
const NEW_IDENTIFIERS = new Map();
|
|
526
|
+
let IDENTIFIER_CACHE_ID = 0;
|
|
527
|
+
function updateTypeIdMapping(typeMap, identifier, id) {
|
|
528
|
+
let idMap = typeMap.get(identifier.type);
|
|
529
|
+
if (!idMap) {
|
|
530
|
+
idMap = new Map();
|
|
531
|
+
typeMap.set(identifier.type, idMap);
|
|
532
|
+
}
|
|
533
|
+
idMap.set(id, identifier.lid);
|
|
534
|
+
}
|
|
535
|
+
function defaultUpdateMethod(identifier, data, bucket) {
|
|
536
|
+
if (bucket === 'record') {
|
|
537
|
+
assert(`Expected identifier to be a StableRecordIdentifier`, isStableIdentifier(identifier));
|
|
538
|
+
if (!identifier.id && hasId(data)) {
|
|
539
|
+
updateTypeIdMapping(NEW_IDENTIFIERS, identifier, data.id);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
function defaultKeyInfoMethod(resource, known) {
|
|
544
|
+
// TODO RFC something to make this configurable
|
|
545
|
+
const id = hasId(resource) ? coerceId(resource.id) : null;
|
|
546
|
+
const type = hasType(resource) ? normalizeModelName(resource.type) : known ? known.type : null;
|
|
547
|
+
assert(`Expected keyInfoForResource to provide a type for the resource`, type);
|
|
548
|
+
return {
|
|
549
|
+
type,
|
|
550
|
+
id
|
|
551
|
+
};
|
|
552
|
+
}
|
|
487
553
|
function defaultGenerationMethod(data, bucket) {
|
|
488
554
|
if (bucket === 'record') {
|
|
489
|
-
if (
|
|
555
|
+
if (hasLid(data)) {
|
|
490
556
|
return data.lid;
|
|
491
557
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
// TODO: add test for id not a string
|
|
498
|
-
if (isNonEmptyString(coerceId(id))) {
|
|
499
|
-
return `@lid:${normalizeModelName(type)}-${id}`;
|
|
500
|
-
}
|
|
558
|
+
assert(`Cannot generate an identifier for a resource without a type`, hasType(data));
|
|
559
|
+
if (hasId(data)) {
|
|
560
|
+
const type = normalizeModelName(data.type);
|
|
561
|
+
const lid = NEW_IDENTIFIERS.get(type)?.get(data.id);
|
|
562
|
+
return lid || `@lid:${type}-${data.id}`;
|
|
501
563
|
}
|
|
502
564
|
return uuidv4();
|
|
503
565
|
} else if (bucket === 'document') {
|
|
@@ -512,6 +574,9 @@ function defaultGenerationMethod(data, bucket) {
|
|
|
512
574
|
assert(`Unknown bucket ${bucket}`, false);
|
|
513
575
|
}
|
|
514
576
|
function defaultEmptyCallback(...args) {}
|
|
577
|
+
function defaultMergeMethod(a, _b, _c) {
|
|
578
|
+
return a;
|
|
579
|
+
}
|
|
515
580
|
let DEBUG_MAP;
|
|
516
581
|
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
517
582
|
DEBUG_MAP = new WeakMap();
|
|
@@ -532,19 +597,21 @@ if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
|
532
597
|
*/
|
|
533
598
|
class IdentifierCache {
|
|
534
599
|
constructor() {
|
|
535
|
-
this._cache = {
|
|
536
|
-
lids: new Map(),
|
|
537
|
-
types: Object.create(null),
|
|
538
|
-
documents: new Map()
|
|
539
|
-
};
|
|
540
600
|
// we cache the user configuredGenerationMethod at init because it must
|
|
541
601
|
// be configured prior and is not allowed to be changed
|
|
542
602
|
this._generate = configuredGenerationMethod || defaultGenerationMethod;
|
|
543
|
-
this._update = configuredUpdateMethod ||
|
|
603
|
+
this._update = configuredUpdateMethod || defaultUpdateMethod;
|
|
544
604
|
this._forget = configuredForgetMethod || defaultEmptyCallback;
|
|
545
605
|
this._reset = configuredResetMethod || defaultEmptyCallback;
|
|
546
|
-
this._merge =
|
|
606
|
+
this._merge = defaultMergeMethod;
|
|
607
|
+
this._keyInfoForResource = defaultKeyInfoMethod;
|
|
547
608
|
this._isDefaultConfig = !configuredGenerationMethod;
|
|
609
|
+
this._id = IDENTIFIER_CACHE_ID++;
|
|
610
|
+
this._cache = {
|
|
611
|
+
resources: new Map(),
|
|
612
|
+
resourcesByType: Object.create(null),
|
|
613
|
+
documents: new Map()
|
|
614
|
+
};
|
|
548
615
|
}
|
|
549
616
|
|
|
550
617
|
/**
|
|
@@ -557,7 +624,10 @@ class IdentifierCache {
|
|
|
557
624
|
* @private
|
|
558
625
|
*/
|
|
559
626
|
__configureMerge(method) {
|
|
560
|
-
this._merge = method ||
|
|
627
|
+
this._merge = method || defaultMergeMethod;
|
|
628
|
+
}
|
|
629
|
+
upgradeIdentifier(resource) {
|
|
630
|
+
return this._getRecordIdentifier(resource, 2);
|
|
561
631
|
}
|
|
562
632
|
|
|
563
633
|
/**
|
|
@@ -565,130 +635,64 @@ class IdentifierCache {
|
|
|
565
635
|
* @private
|
|
566
636
|
*/
|
|
567
637
|
|
|
568
|
-
_getRecordIdentifier(resource, shouldGenerate
|
|
638
|
+
_getRecordIdentifier(resource, shouldGenerate) {
|
|
639
|
+
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
640
|
+
// eslint-disable-next-line no-console
|
|
641
|
+
console.groupCollapsed(`Identifiers: ${shouldGenerate ? 'Generating' : 'Peeking'} Identifier`, resource);
|
|
642
|
+
}
|
|
569
643
|
// short circuit if we're already the stable version
|
|
570
644
|
if (isStableIdentifier(resource)) {
|
|
571
645
|
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
572
646
|
// TODO should we instead just treat this case as a new generation skipping the short circuit?
|
|
573
|
-
if (!this._cache.
|
|
574
|
-
throw new Error(`The supplied identifier ${resource} does not belong to this store instance`);
|
|
647
|
+
if (!this._cache.resources.has(resource.lid) || this._cache.resources.get(resource.lid) !== resource) {
|
|
648
|
+
throw new Error(`The supplied identifier ${JSON.stringify(resource)} does not belong to this store instance`);
|
|
575
649
|
}
|
|
576
650
|
}
|
|
577
651
|
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
578
652
|
// eslint-disable-next-line no-console
|
|
579
|
-
console.log(`Identifiers:
|
|
580
|
-
}
|
|
581
|
-
return resource;
|
|
582
|
-
}
|
|
583
|
-
let lid = coerceId(resource.lid);
|
|
584
|
-
let identifier = lid !== null ? this._cache.lids.get(lid) : undefined;
|
|
585
|
-
if (identifier !== undefined) {
|
|
586
|
-
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
653
|
+
console.log(`Identifiers: cache HIT - Stable ${resource.lid}`);
|
|
587
654
|
// eslint-disable-next-line no-console
|
|
588
|
-
console.
|
|
655
|
+
console.groupEnd();
|
|
589
656
|
}
|
|
590
|
-
return
|
|
657
|
+
return resource;
|
|
591
658
|
}
|
|
659
|
+
|
|
660
|
+
// the resource is unknown, ask the application to identify this data for us
|
|
661
|
+
const lid = this._generate(resource, 'record');
|
|
592
662
|
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
593
663
|
// eslint-disable-next-line no-console
|
|
594
|
-
console.
|
|
664
|
+
console.log(`Identifiers: ${lid ? 'no ' : ''}lid ${lid ? lid + ' ' : ''}determined for resource`, resource);
|
|
595
665
|
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
666
|
+
let identifier = /*#__NOINLINE__*/getIdentifierFromLid(this._cache, lid, resource);
|
|
667
|
+
if (identifier !== null) {
|
|
668
|
+
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
669
|
+
// eslint-disable-next-line no-console
|
|
670
|
+
console.groupEnd();
|
|
599
671
|
}
|
|
672
|
+
return identifier;
|
|
600
673
|
}
|
|
601
|
-
|
|
602
|
-
// `type` must always be present
|
|
603
|
-
assert('resource.type needs to be a string', 'type' in resource && isNonEmptyString(resource.type));
|
|
604
|
-
let type = resource.type && normalizeModelName(resource.type);
|
|
605
|
-
let id = coerceId(resource.id);
|
|
606
|
-
let keyOptions = getTypeIndex(this._cache.types, type);
|
|
607
|
-
|
|
608
|
-
// go straight for the stable RecordIdentifier key'd to `lid`
|
|
609
|
-
if (lid !== null) {
|
|
610
|
-
identifier = keyOptions.lid.get(lid);
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// we may have not seen this resource before
|
|
614
|
-
// but just in case we check our own secondary lookup (`id`)
|
|
615
|
-
if (identifier === undefined && id !== null) {
|
|
616
|
-
identifier = keyOptions.id.get(id);
|
|
617
|
-
}
|
|
618
|
-
if (identifier === undefined) {
|
|
619
|
-
// we have definitely not seen this resource before
|
|
620
|
-
// so we allow the user configured `GenerationMethod` to tell us
|
|
621
|
-
let newLid = this._generate(resource, 'record');
|
|
674
|
+
if (shouldGenerate === 0) {
|
|
622
675
|
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
623
676
|
// eslint-disable-next-line no-console
|
|
624
|
-
console.
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
// we do this _even_ when `lid` is present because secondary lookups
|
|
628
|
-
// may need to be populated, but we enforce not giving us something
|
|
629
|
-
// different than expected
|
|
630
|
-
if (lid !== null && newLid !== lid) {
|
|
631
|
-
throw new Error(`You should not change the <lid> of a RecordIdentifier`);
|
|
632
|
-
} else if (lid === null && !this._isDefaultConfig) {
|
|
633
|
-
// allow configuration to tell us that we have
|
|
634
|
-
// seen this `lid` before. E.g. a secondary lookup
|
|
635
|
-
// connects this resource to a previously seen
|
|
636
|
-
// resource.
|
|
637
|
-
identifier = keyOptions.lid.get(newLid);
|
|
638
|
-
}
|
|
639
|
-
if (shouldGenerate === true) {
|
|
640
|
-
if (identifier === undefined) {
|
|
641
|
-
// if we still don't have an identifier, time to generate one
|
|
642
|
-
identifier = makeStableRecordIdentifier(id, type, newLid, 'record', false);
|
|
643
|
-
|
|
644
|
-
// populate our unique table
|
|
645
|
-
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
646
|
-
// realistically if you hit this it means you changed `type` :/
|
|
647
|
-
// TODO consider how to handle type change assertions more gracefully
|
|
648
|
-
if (this._cache.lids.has(identifier.lid)) {
|
|
649
|
-
throw new Error(`You should not change the <type> of a RecordIdentifier`);
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
this._cache.lids.set(identifier.lid, identifier);
|
|
653
|
-
|
|
654
|
-
// populate our primary lookup table
|
|
655
|
-
// TODO consider having the `lid` cache be
|
|
656
|
-
// one level up
|
|
657
|
-
keyOptions.lid.set(identifier.lid, identifier);
|
|
658
|
-
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
659
|
-
if (shouldGenerate) {
|
|
660
|
-
// eslint-disable-next-line no-console
|
|
661
|
-
console.log(`Identifiers: generated ${String(identifier)} for`, resource);
|
|
662
|
-
if (resource[DEBUG_IDENTIFIER_BUCKET]) {
|
|
663
|
-
// eslint-disable-next-line no-console
|
|
664
|
-
console.trace(`[WARNING] Identifiers: generated a new identifier from a previously used identifier. This is likely a bug.`);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
// populate our own secondary lookup table
|
|
671
|
-
// even for the "successful" secondary lookup
|
|
672
|
-
// by `_generate()`, since we missed the cache
|
|
673
|
-
// previously
|
|
674
|
-
// we use identifier.id instead of id here
|
|
675
|
-
// because they may not match and we prefer
|
|
676
|
-
// what we've set via resource data
|
|
677
|
-
if (identifier.id !== null) {
|
|
678
|
-
keyOptions.id.set(identifier.id, identifier);
|
|
679
|
-
|
|
680
|
-
// TODO allow filling out of `id` here
|
|
681
|
-
// for the `username` non-client created
|
|
682
|
-
// case.
|
|
683
|
-
}
|
|
677
|
+
console.groupEnd();
|
|
684
678
|
}
|
|
679
|
+
return;
|
|
685
680
|
}
|
|
686
681
|
|
|
682
|
+
// if we still don't have an identifier, time to generate one
|
|
683
|
+
if (shouldGenerate === 2) {
|
|
684
|
+
resource.lid = lid;
|
|
685
|
+
resource[CACHE_OWNER] = this._id;
|
|
686
|
+
identifier = /*#__NOINLINE__*/makeStableRecordIdentifier(resource, 'record', false);
|
|
687
|
+
} else {
|
|
688
|
+
// we lie a bit here as a memory optimization
|
|
689
|
+
const keyInfo = this._keyInfoForResource(resource, null);
|
|
690
|
+
keyInfo.lid = lid;
|
|
691
|
+
keyInfo[CACHE_OWNER] = this._id;
|
|
692
|
+
identifier = /*#__NOINLINE__*/makeStableRecordIdentifier(keyInfo, 'record', false);
|
|
693
|
+
}
|
|
694
|
+
addResourceToCache(this._cache, identifier);
|
|
687
695
|
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
688
|
-
if (!identifier && !shouldGenerate) {
|
|
689
|
-
// eslint-disable-next-line no-console
|
|
690
|
-
console.log(`Identifiers: cache MISS`, resource);
|
|
691
|
-
}
|
|
692
696
|
// eslint-disable-next-line no-console
|
|
693
697
|
console.groupEnd();
|
|
694
698
|
}
|
|
@@ -706,7 +710,7 @@ class IdentifierCache {
|
|
|
706
710
|
* @private
|
|
707
711
|
*/
|
|
708
712
|
peekRecordIdentifier(resource) {
|
|
709
|
-
return this._getRecordIdentifier(resource,
|
|
713
|
+
return this._getRecordIdentifier(resource, 0);
|
|
710
714
|
}
|
|
711
715
|
|
|
712
716
|
/**
|
|
@@ -751,9 +755,8 @@ class IdentifierCache {
|
|
|
751
755
|
@returns {StableRecordIdentifier}
|
|
752
756
|
@public
|
|
753
757
|
*/
|
|
754
|
-
|
|
755
758
|
getOrCreateRecordIdentifier(resource) {
|
|
756
|
-
return this._getRecordIdentifier(resource,
|
|
759
|
+
return this._getRecordIdentifier(resource, 1);
|
|
757
760
|
}
|
|
758
761
|
|
|
759
762
|
/**
|
|
@@ -769,22 +772,22 @@ class IdentifierCache {
|
|
|
769
772
|
*/
|
|
770
773
|
createIdentifierForNewRecord(data) {
|
|
771
774
|
let newLid = this._generate(data, 'record');
|
|
772
|
-
let identifier = makeStableRecordIdentifier(
|
|
773
|
-
|
|
775
|
+
let identifier = /*#__NOINLINE__*/makeStableRecordIdentifier({
|
|
776
|
+
id: data.id || null,
|
|
777
|
+
type: data.type,
|
|
778
|
+
lid: newLid,
|
|
779
|
+
[CACHE_OWNER]: this._id
|
|
780
|
+
}, 'record', true);
|
|
774
781
|
|
|
775
782
|
// populate our unique table
|
|
776
783
|
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
777
|
-
if (this._cache.
|
|
784
|
+
if (this._cache.resources.has(identifier.lid)) {
|
|
778
785
|
throw new Error(`The lid generated for the new record is not unique as it matches an existing identifier`);
|
|
779
786
|
}
|
|
780
787
|
}
|
|
781
|
-
this._cache.lids.set(identifier.lid, identifier);
|
|
782
788
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
if (data.id) {
|
|
786
|
-
keyOptions.id.set(data.id, identifier);
|
|
787
|
-
}
|
|
789
|
+
/*#__NOINLINE__*/
|
|
790
|
+
addResourceToCache(this._cache, identifier);
|
|
788
791
|
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
789
792
|
// eslint-disable-next-line no-console
|
|
790
793
|
console.log(`Identifiers: created identifier ${String(identifier)} for newly generated resource`, data);
|
|
@@ -812,43 +815,49 @@ class IdentifierCache {
|
|
|
812
815
|
*/
|
|
813
816
|
updateRecordIdentifier(identifierObject, data) {
|
|
814
817
|
let identifier = this.getOrCreateRecordIdentifier(identifierObject);
|
|
815
|
-
|
|
816
|
-
let existingIdentifier = detectMerge(this._cache
|
|
818
|
+
const keyInfo = this._keyInfoForResource(data, identifier);
|
|
819
|
+
let existingIdentifier = /*#__NOINLINE__*/detectMerge(this._cache, keyInfo, identifier, data);
|
|
820
|
+
const hadLid = hasLid(data);
|
|
817
821
|
if (!existingIdentifier) {
|
|
818
822
|
// If the incoming type does not match the identifier type, we need to create an identifier for the incoming
|
|
819
823
|
// data so we can merge the incoming data with the existing identifier, see #7325 and #7363
|
|
820
|
-
if (
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
existingIdentifier = this.getOrCreateRecordIdentifier(incomingDataResource);
|
|
824
|
+
if (identifier.type !== keyInfo.type) {
|
|
825
|
+
if (hadLid) {
|
|
826
|
+
// Strip the lid to ensure we force a new identifier creation
|
|
827
|
+
delete data.lid;
|
|
828
|
+
}
|
|
829
|
+
existingIdentifier = this.getOrCreateRecordIdentifier(data);
|
|
827
830
|
}
|
|
828
831
|
}
|
|
829
832
|
if (existingIdentifier) {
|
|
830
|
-
let keyOptions = getTypeIndex(this._cache.types, identifier.type);
|
|
831
833
|
let generatedIdentifier = identifier;
|
|
832
|
-
identifier = this._mergeRecordIdentifiers(
|
|
834
|
+
identifier = this._mergeRecordIdentifiers(keyInfo, generatedIdentifier, existingIdentifier, data);
|
|
835
|
+
|
|
836
|
+
// make sure that the `lid` on the data we are processing matches the lid we kept
|
|
837
|
+
if (hadLid) {
|
|
838
|
+
data.lid = identifier.lid;
|
|
839
|
+
}
|
|
833
840
|
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
834
841
|
// eslint-disable-next-line no-console
|
|
835
842
|
console.log(`Identifiers: merged identifiers ${generatedIdentifier.lid} and ${existingIdentifier.lid} for resource into ${identifier.lid}`, data);
|
|
836
843
|
}
|
|
837
844
|
}
|
|
838
845
|
let id = identifier.id;
|
|
839
|
-
|
|
840
|
-
|
|
846
|
+
/*#__NOINLINE__*/
|
|
847
|
+
performRecordIdentifierUpdate(identifier, keyInfo, data, this._update);
|
|
848
|
+
const newId = identifier.id;
|
|
841
849
|
|
|
842
850
|
// add to our own secondary lookup table
|
|
843
851
|
if (id !== newId && newId !== null) {
|
|
844
852
|
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
845
853
|
// eslint-disable-next-line no-console
|
|
846
|
-
console.log(`Identifiers: updated id for identifier ${identifier.lid} from '${id}' to '${newId}' for resource`, data);
|
|
854
|
+
console.log(`Identifiers: updated id for identifier ${identifier.lid} from '${String(id)}' to '${String(newId)}' for resource`, data);
|
|
847
855
|
}
|
|
848
|
-
|
|
849
|
-
|
|
856
|
+
const typeSet = this._cache.resourcesByType[identifier.type];
|
|
857
|
+
assert(`Expected to find a typeSet for ${identifier.type}`, typeSet);
|
|
858
|
+
typeSet.id.set(newId, identifier);
|
|
850
859
|
if (id !== null) {
|
|
851
|
-
|
|
860
|
+
typeSet.id.delete(id);
|
|
852
861
|
}
|
|
853
862
|
} else if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
854
863
|
// eslint-disable-next-line no-console
|
|
@@ -861,22 +870,22 @@ class IdentifierCache {
|
|
|
861
870
|
* @method _mergeRecordIdentifiers
|
|
862
871
|
* @private
|
|
863
872
|
*/
|
|
864
|
-
_mergeRecordIdentifiers(
|
|
873
|
+
_mergeRecordIdentifiers(keyInfo, identifier, existingIdentifier, data) {
|
|
874
|
+
assert(`Expected keyInfo to contain an id`, hasId(keyInfo));
|
|
865
875
|
// delegate determining which identifier to keep to the configured MergeMethod
|
|
866
|
-
|
|
867
|
-
|
|
876
|
+
const kept = this._merge(identifier, existingIdentifier, data);
|
|
877
|
+
const abandoned = kept === identifier ? existingIdentifier : identifier;
|
|
868
878
|
|
|
869
879
|
// cleanup the identifier we no longer need
|
|
870
880
|
this.forgetRecordIdentifier(abandoned);
|
|
871
881
|
|
|
872
882
|
// ensure a secondary cache entry for this id for the identifier we do keep
|
|
873
|
-
keyOptions.id.set(newId, kept);
|
|
883
|
+
// keyOptions.id.set(newId, kept);
|
|
884
|
+
|
|
874
885
|
// ensure a secondary cache entry for this id for the abandoned identifier's type we do keep
|
|
875
|
-
let baseKeyOptions = getTypeIndex(this._cache.
|
|
876
|
-
baseKeyOptions.id.set(newId, kept);
|
|
886
|
+
// let baseKeyOptions = getTypeIndex(this._cache.resourcesByType, existingIdentifier.type);
|
|
887
|
+
// baseKeyOptions.id.set(newId, kept);
|
|
877
888
|
|
|
878
|
-
// make sure that the `lid` on the data we are processing matches the lid we kept
|
|
879
|
-
data.lid = kept.lid;
|
|
880
889
|
return kept;
|
|
881
890
|
}
|
|
882
891
|
|
|
@@ -891,14 +900,19 @@ class IdentifierCache {
|
|
|
891
900
|
@public
|
|
892
901
|
*/
|
|
893
902
|
forgetRecordIdentifier(identifierObject) {
|
|
894
|
-
|
|
895
|
-
|
|
903
|
+
const identifier = this.getOrCreateRecordIdentifier(identifierObject);
|
|
904
|
+
const typeSet = this._cache.resourcesByType[identifier.type];
|
|
905
|
+
assert(`Expected to find a typeSet for ${identifier.type}`, typeSet);
|
|
896
906
|
if (identifier.id !== null) {
|
|
897
|
-
|
|
907
|
+
typeSet.id.delete(identifier.id);
|
|
908
|
+
}
|
|
909
|
+
this._cache.resources.delete(identifier.lid);
|
|
910
|
+
typeSet.lid.delete(identifier.lid);
|
|
911
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
912
|
+
identifier[DEBUG_STALE_CACHE_OWNER] = identifier[CACHE_OWNER];
|
|
898
913
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
IDENTIFIERS.delete(identifierObject);
|
|
914
|
+
identifier[CACHE_OWNER] = undefined;
|
|
915
|
+
IDENTIFIERS.delete(identifier);
|
|
902
916
|
this._forget(identifier, 'record');
|
|
903
917
|
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
904
918
|
// eslint-disable-next-line no-console
|
|
@@ -906,29 +920,14 @@ class IdentifierCache {
|
|
|
906
920
|
}
|
|
907
921
|
}
|
|
908
922
|
destroy() {
|
|
923
|
+
NEW_IDENTIFIERS.clear();
|
|
909
924
|
this._cache.documents.forEach(identifier => {
|
|
910
925
|
DOCUMENTS.delete(identifier);
|
|
911
926
|
});
|
|
912
927
|
this._reset();
|
|
913
928
|
}
|
|
914
929
|
}
|
|
915
|
-
function
|
|
916
|
-
let typeIndex = typeMap[type];
|
|
917
|
-
if (typeIndex === undefined) {
|
|
918
|
-
typeIndex = {
|
|
919
|
-
lid: new Map(),
|
|
920
|
-
id: new Map()
|
|
921
|
-
};
|
|
922
|
-
typeMap[type] = typeIndex;
|
|
923
|
-
}
|
|
924
|
-
return typeIndex;
|
|
925
|
-
}
|
|
926
|
-
function makeStableRecordIdentifier(id, type, lid, bucket, clientOriginated = false) {
|
|
927
|
-
let recordIdentifier = {
|
|
928
|
-
lid,
|
|
929
|
-
id,
|
|
930
|
-
type
|
|
931
|
-
};
|
|
930
|
+
function makeStableRecordIdentifier(recordIdentifier, bucket, clientOriginated) {
|
|
932
931
|
IDENTIFIERS.add(recordIdentifier);
|
|
933
932
|
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
934
933
|
// we enforce immutability in dev
|
|
@@ -943,16 +942,29 @@ function makeStableRecordIdentifier(id, type, lid, bucket, clientOriginated = fa
|
|
|
943
942
|
get type() {
|
|
944
943
|
return recordIdentifier.type;
|
|
945
944
|
},
|
|
945
|
+
get [CACHE_OWNER]() {
|
|
946
|
+
return recordIdentifier[CACHE_OWNER];
|
|
947
|
+
},
|
|
948
|
+
set [CACHE_OWNER](value) {
|
|
949
|
+
recordIdentifier[CACHE_OWNER] = value;
|
|
950
|
+
},
|
|
951
|
+
get [DEBUG_STALE_CACHE_OWNER]() {
|
|
952
|
+
return recordIdentifier[DEBUG_STALE_CACHE_OWNER];
|
|
953
|
+
},
|
|
954
|
+
set [DEBUG_STALE_CACHE_OWNER](value) {
|
|
955
|
+
recordIdentifier[DEBUG_STALE_CACHE_OWNER] = value;
|
|
956
|
+
},
|
|
957
|
+
// @ts-expect-error debug only
|
|
946
958
|
toString() {
|
|
947
|
-
|
|
959
|
+
const {
|
|
948
960
|
type,
|
|
949
961
|
id,
|
|
950
962
|
lid
|
|
951
963
|
} = recordIdentifier;
|
|
952
|
-
return `${clientOriginated ? '[CLIENT_ORIGINATED] ' : ''}${type}:${id} (${lid})`;
|
|
964
|
+
return `${clientOriginated ? '[CLIENT_ORIGINATED] ' : ''}${String(type)}:${String(id)} (${lid})`;
|
|
953
965
|
},
|
|
954
966
|
toJSON() {
|
|
955
|
-
|
|
967
|
+
const {
|
|
956
968
|
type,
|
|
957
969
|
id,
|
|
958
970
|
lid
|
|
@@ -973,37 +985,33 @@ function makeStableRecordIdentifier(id, type, lid, bucket, clientOriginated = fa
|
|
|
973
985
|
}
|
|
974
986
|
return recordIdentifier;
|
|
975
987
|
}
|
|
976
|
-
function performRecordIdentifierUpdate(identifier, data, updateFn) {
|
|
988
|
+
function performRecordIdentifierUpdate(identifier, keyInfo, data, updateFn) {
|
|
977
989
|
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
let type = 'type' in data && data.type && normalizeModelName(data.type);
|
|
990
|
+
const {
|
|
991
|
+
id,
|
|
992
|
+
type
|
|
993
|
+
} = keyInfo;
|
|
983
994
|
|
|
984
995
|
// get the mutable instance behind our proxy wrapper
|
|
985
996
|
let wrapper = identifier;
|
|
986
997
|
identifier = DEBUG_MAP.get(wrapper);
|
|
987
|
-
if (
|
|
988
|
-
|
|
989
|
-
if (
|
|
990
|
-
throw new Error(`The 'lid' for a RecordIdentifier cannot be updated once it has been created. Attempted to set lid for '${wrapper}' to '${lid}'.`);
|
|
998
|
+
if (hasLid(data)) {
|
|
999
|
+
const lid = data.lid;
|
|
1000
|
+
if (lid !== identifier.lid) {
|
|
1001
|
+
throw new Error(`The 'lid' for a RecordIdentifier cannot be updated once it has been created. Attempted to set lid for '${wrapper.lid}' to '${lid}'.`);
|
|
991
1002
|
}
|
|
992
1003
|
}
|
|
993
|
-
if (id !==
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
id: 'ember-data:multiple-ids-for-identifier'
|
|
1000
|
-
});
|
|
1001
|
-
}
|
|
1004
|
+
if (id && identifier.id !== null && identifier.id !== id) {
|
|
1005
|
+
// here we warn and ignore, as this may be a mistake, but we allow the user
|
|
1006
|
+
// to have multiple cache-keys pointing at a single lid so we cannot error
|
|
1007
|
+
warn(`The 'id' for a RecordIdentifier should not be updated once it has been set. Attempted to set id for '${wrapper.lid}' to '${id}'.`, false, {
|
|
1008
|
+
id: 'ember-data:multiple-ids-for-identifier'
|
|
1009
|
+
});
|
|
1002
1010
|
}
|
|
1003
1011
|
|
|
1004
1012
|
// TODO consider just ignoring here to allow flexible polymorphic support
|
|
1005
1013
|
if (type && type !== identifier.type) {
|
|
1006
|
-
throw new Error(`The 'type' for a RecordIdentifier cannot be updated once it has been set. Attempted to set type for '${wrapper}' to '${type}'.`);
|
|
1014
|
+
throw new Error(`The 'type' for a RecordIdentifier cannot be updated once it has been set. Attempted to set type for '${wrapper.lid}' to '${type}'.`);
|
|
1007
1015
|
}
|
|
1008
1016
|
updateFn(wrapper, data, 'record');
|
|
1009
1017
|
} else {
|
|
@@ -1018,32 +1026,62 @@ function performRecordIdentifierUpdate(identifier, data, updateFn) {
|
|
|
1018
1026
|
identifier.id = coerceId(data.id);
|
|
1019
1027
|
}
|
|
1020
1028
|
}
|
|
1021
|
-
function detectMerge(
|
|
1029
|
+
function detectMerge(cache, keyInfo, identifier, data) {
|
|
1030
|
+
const newId = keyInfo.id;
|
|
1022
1031
|
const {
|
|
1023
1032
|
id,
|
|
1024
1033
|
type,
|
|
1025
1034
|
lid
|
|
1026
1035
|
} = identifier;
|
|
1036
|
+
const typeSet = cache.resourcesByType[identifier.type];
|
|
1037
|
+
|
|
1038
|
+
// if the IDs are present but do not match
|
|
1039
|
+
// then check if we have an existing identifier
|
|
1040
|
+
// for the newer ID.
|
|
1027
1041
|
if (id !== null && id !== newId && newId !== null) {
|
|
1028
|
-
|
|
1029
|
-
let existingIdentifier = keyOptions.id.get(newId);
|
|
1042
|
+
const existingIdentifier = typeSet && typeSet.id.get(newId);
|
|
1030
1043
|
return existingIdentifier !== undefined ? existingIdentifier : false;
|
|
1031
1044
|
} else {
|
|
1032
|
-
|
|
1045
|
+
const newType = keyInfo.type;
|
|
1033
1046
|
|
|
1034
1047
|
// If the ids and type are the same but lid is not the same, we should trigger a merge of the identifiers
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1048
|
+
// we trigger a merge of the identifiers
|
|
1049
|
+
// though probably we should just throw an error here
|
|
1050
|
+
if (id !== null && id === newId && newType === type && hasLid(data) && data.lid !== lid) {
|
|
1051
|
+
return getIdentifierFromLid(cache, data.lid, data) || false;
|
|
1052
|
+
|
|
1038
1053
|
// If the lids are the same, and ids are the same, but types are different we should trigger a merge of the identifiers
|
|
1039
|
-
} else if (id !== null && id === newId && newType && newType !== type && data
|
|
1040
|
-
|
|
1041
|
-
|
|
1054
|
+
} else if (id !== null && id === newId && newType && newType !== type && hasLid(data) && data.lid === lid) {
|
|
1055
|
+
const newTypeSet = cache.resourcesByType[newType];
|
|
1056
|
+
const existingIdentifier = newTypeSet && newTypeSet.id.get(newId);
|
|
1042
1057
|
return existingIdentifier !== undefined ? existingIdentifier : false;
|
|
1043
1058
|
}
|
|
1044
1059
|
}
|
|
1045
1060
|
return false;
|
|
1046
1061
|
}
|
|
1062
|
+
function getIdentifierFromLid(cache, lid, resource) {
|
|
1063
|
+
const identifier = cache.resources.get(lid);
|
|
1064
|
+
if (macroCondition(getOwnConfig().debug.LOG_IDENTIFIERS)) {
|
|
1065
|
+
// eslint-disable-next-line no-console
|
|
1066
|
+
console.log(`Identifiers: cache ${identifier ? 'HIT' : 'MISS'} - Non-Stable ${lid}`, resource);
|
|
1067
|
+
}
|
|
1068
|
+
return identifier || null;
|
|
1069
|
+
}
|
|
1070
|
+
function addResourceToCache(cache, identifier) {
|
|
1071
|
+
cache.resources.set(identifier.lid, identifier);
|
|
1072
|
+
let typeSet = cache.resourcesByType[identifier.type];
|
|
1073
|
+
if (!typeSet) {
|
|
1074
|
+
typeSet = {
|
|
1075
|
+
lid: new Map(),
|
|
1076
|
+
id: new Map()
|
|
1077
|
+
};
|
|
1078
|
+
cache.resourcesByType[identifier.type] = typeSet;
|
|
1079
|
+
}
|
|
1080
|
+
typeSet.lid.set(identifier.lid, identifier);
|
|
1081
|
+
if (identifier.id) {
|
|
1082
|
+
typeSet.id.set(identifier.id, identifier);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1047
1085
|
var _class$1, _descriptor$1;
|
|
1048
1086
|
|
|
1049
1087
|
/**
|
|
@@ -1402,9 +1440,12 @@ class InstanceCache {
|
|
|
1402
1440
|
store.identifierCache.__configureMerge((identifier, matchedIdentifier, resourceData) => {
|
|
1403
1441
|
let keptIdentifier = identifier;
|
|
1404
1442
|
if (identifier.id !== matchedIdentifier.id) {
|
|
1443
|
+
// @ts-expect-error TODO this needs to be fixed
|
|
1405
1444
|
keptIdentifier = 'id' in resourceData && identifier.id === resourceData.id ? identifier : matchedIdentifier;
|
|
1406
1445
|
} else if (identifier.type !== matchedIdentifier.type) {
|
|
1407
|
-
keptIdentifier =
|
|
1446
|
+
keptIdentifier =
|
|
1447
|
+
// @ts-expect-error TODO this needs to be fixed
|
|
1448
|
+
'type' in resourceData && identifier.type === resourceData.type ? identifier : matchedIdentifier;
|
|
1408
1449
|
}
|
|
1409
1450
|
let staleIdentifier = identifier === keptIdentifier ? matchedIdentifier : identifier;
|
|
1410
1451
|
|
|
@@ -1419,6 +1460,7 @@ class InstanceCache {
|
|
|
1419
1460
|
// we can probably just "swap" what data source the abandoned
|
|
1420
1461
|
// record points at so long as
|
|
1421
1462
|
// it itself is not retained by the store in any way.
|
|
1463
|
+
// @ts-expect-error TODO this needs to be fixed
|
|
1422
1464
|
if ('id' in resourceData) {
|
|
1423
1465
|
throw new Error(`Failed to update the 'id' for the RecordIdentifier '${identifier.type}:${String(identifier.id)} (${identifier.lid})' to '${String(resourceData.id)}', because that id is already in use by '${matchedIdentifier.type}:${String(matchedIdentifier.id)} (${matchedIdentifier.lid})'`);
|
|
1424
1466
|
}
|
|
@@ -1557,11 +1599,11 @@ class InstanceCache {
|
|
|
1557
1599
|
if (type === undefined) {
|
|
1558
1600
|
// it would be cool if we could just de-ref cache here
|
|
1559
1601
|
// but probably would require WeakRef models to do so.
|
|
1560
|
-
cache.
|
|
1602
|
+
cache.resources.forEach(identifier => {
|
|
1561
1603
|
this.unloadRecord(identifier);
|
|
1562
1604
|
});
|
|
1563
1605
|
} else {
|
|
1564
|
-
const typeCache = cache.
|
|
1606
|
+
const typeCache = cache.resourcesByType;
|
|
1565
1607
|
let identifiers = typeCache[type]?.lid;
|
|
1566
1608
|
if (identifiers) {
|
|
1567
1609
|
identifiers.forEach(identifier => {
|
|
@@ -1683,7 +1725,7 @@ function _convertPreloadRelationshipToJSON(value, type) {
|
|
|
1683
1725
|
if (typeof value === 'string' || typeof value === 'number') {
|
|
1684
1726
|
return {
|
|
1685
1727
|
type,
|
|
1686
|
-
id: value
|
|
1728
|
+
id: ensureStringId(value)
|
|
1687
1729
|
};
|
|
1688
1730
|
}
|
|
1689
1731
|
// TODO if not a record instance assert it's an identifier
|
|
@@ -1712,7 +1754,7 @@ function getShimClass(store, modelName) {
|
|
|
1712
1754
|
return shim;
|
|
1713
1755
|
}
|
|
1714
1756
|
function mapFromHash(hash) {
|
|
1715
|
-
|
|
1757
|
+
const map = new Map();
|
|
1716
1758
|
for (let i in hash) {
|
|
1717
1759
|
if (Object.prototype.hasOwnProperty.call(hash, i)) {
|
|
1718
1760
|
map.set(i, hash[i]);
|
|
@@ -1721,7 +1763,7 @@ function mapFromHash(hash) {
|
|
|
1721
1763
|
return map;
|
|
1722
1764
|
}
|
|
1723
1765
|
|
|
1724
|
-
// Mimics the static apis of
|
|
1766
|
+
// Mimics the static apis of @ember-data/model
|
|
1725
1767
|
class ShimModelClass {
|
|
1726
1768
|
constructor(store, modelName) {
|
|
1727
1769
|
this.__store = store;
|
|
@@ -2561,13 +2603,13 @@ let IdentifierArray = (_class3 = class IdentifierArray {
|
|
|
2561
2603
|
@type Store
|
|
2562
2604
|
*/
|
|
2563
2605
|
|
|
2564
|
-
destroy() {
|
|
2565
|
-
this.isDestroying =
|
|
2606
|
+
destroy(clear) {
|
|
2607
|
+
this.isDestroying = !clear;
|
|
2566
2608
|
// changing the reference breaks the Proxy
|
|
2567
2609
|
// this[SOURCE] = [];
|
|
2568
2610
|
this[SOURCE].length = 0;
|
|
2569
2611
|
this[NOTIFY]();
|
|
2570
|
-
this.isDestroyed =
|
|
2612
|
+
this.isDestroyed = !clear;
|
|
2571
2613
|
}
|
|
2572
2614
|
|
|
2573
2615
|
// length must be on self for proxied methods to work properly
|
|
@@ -2802,7 +2844,7 @@ let IdentifierArray = (_class3 = class IdentifierArray {
|
|
|
2802
2844
|
}
|
|
2803
2845
|
this.isUpdating = true;
|
|
2804
2846
|
let updatingPromise = this._update();
|
|
2805
|
-
updatingPromise.finally(() => {
|
|
2847
|
+
void updatingPromise.finally(() => {
|
|
2806
2848
|
this._updatingPromise = null;
|
|
2807
2849
|
if (this.isDestroying || this.isDestroyed) {
|
|
2808
2850
|
return;
|
|
@@ -2872,8 +2914,8 @@ class Collection extends IdentifierArray {
|
|
|
2872
2914
|
});
|
|
2873
2915
|
return promise;
|
|
2874
2916
|
}
|
|
2875
|
-
destroy() {
|
|
2876
|
-
super.destroy();
|
|
2917
|
+
destroy(clear) {
|
|
2918
|
+
super.destroy(clear);
|
|
2877
2919
|
this._manager._managed.delete(this);
|
|
2878
2920
|
this._manager._pending.delete(this);
|
|
2879
2921
|
}
|
|
@@ -2971,10 +3013,14 @@ class RecordArrayManager {
|
|
|
2971
3013
|
this._staged = new Map();
|
|
2972
3014
|
this._keyedArrays = new Map();
|
|
2973
3015
|
this._identifiers = new Map();
|
|
3016
|
+
this._set = new Map();
|
|
3017
|
+
this._visibilitySet = new Map();
|
|
2974
3018
|
this._subscription = this.store.notifications.subscribe('resource', (identifier, type) => {
|
|
2975
3019
|
if (type === 'added') {
|
|
3020
|
+
this._visibilitySet.set(identifier, true);
|
|
2976
3021
|
this.identifierAdded(identifier);
|
|
2977
3022
|
} else if (type === 'removed') {
|
|
3023
|
+
this._visibilitySet.set(identifier, false);
|
|
2978
3024
|
this.identifierRemoved(identifier);
|
|
2979
3025
|
} else if (type === 'state') {
|
|
2980
3026
|
this.identifierChanged(identifier);
|
|
@@ -2986,7 +3032,7 @@ class RecordArrayManager {
|
|
|
2986
3032
|
if (!pending || this.isDestroying || this.isDestroyed) {
|
|
2987
3033
|
return;
|
|
2988
3034
|
}
|
|
2989
|
-
sync(array, pending);
|
|
3035
|
+
sync(array, pending, this._set.get(array));
|
|
2990
3036
|
this._pending.delete(array);
|
|
2991
3037
|
}
|
|
2992
3038
|
|
|
@@ -3019,6 +3065,7 @@ class RecordArrayManager {
|
|
|
3019
3065
|
manager: this
|
|
3020
3066
|
});
|
|
3021
3067
|
this._live.set(type, array);
|
|
3068
|
+
this._set.set(array, new Set(identifiers));
|
|
3022
3069
|
}
|
|
3023
3070
|
return array;
|
|
3024
3071
|
}
|
|
@@ -3036,6 +3083,7 @@ class RecordArrayManager {
|
|
|
3036
3083
|
};
|
|
3037
3084
|
let array = new Collection(options);
|
|
3038
3085
|
this._managed.add(array);
|
|
3086
|
+
this._set.set(array, new Set(options.identifiers || []));
|
|
3039
3087
|
if (config.identifiers) {
|
|
3040
3088
|
associate(this._identifiers, array, config.identifiers);
|
|
3041
3089
|
}
|
|
@@ -3107,6 +3155,7 @@ class RecordArrayManager {
|
|
|
3107
3155
|
const old = source.slice();
|
|
3108
3156
|
source.length = 0;
|
|
3109
3157
|
fastPush(source, identifiers);
|
|
3158
|
+
this._set.set(array, new Set(identifiers));
|
|
3110
3159
|
notifyArray(array);
|
|
3111
3160
|
array.meta = payload.meta || null;
|
|
3112
3161
|
array.links = payload.links || null;
|
|
@@ -3144,21 +3193,30 @@ class RecordArrayManager {
|
|
|
3144
3193
|
}
|
|
3145
3194
|
identifierChanged(identifier) {
|
|
3146
3195
|
let newState = this.store._instanceCache.recordIsLoaded(identifier, true);
|
|
3196
|
+
|
|
3197
|
+
// if the change matches the most recent direct added/removed
|
|
3198
|
+
// state, then we can ignore it
|
|
3199
|
+
if (this._visibilitySet.get(identifier) === newState) {
|
|
3200
|
+
return;
|
|
3201
|
+
}
|
|
3147
3202
|
if (newState) {
|
|
3148
3203
|
this.identifierAdded(identifier);
|
|
3149
3204
|
} else {
|
|
3150
3205
|
this.identifierRemoved(identifier);
|
|
3151
3206
|
}
|
|
3152
3207
|
}
|
|
3153
|
-
clear() {
|
|
3154
|
-
this._live.forEach(array => array.destroy());
|
|
3155
|
-
this._managed.forEach(array => array.destroy());
|
|
3208
|
+
clear(isClear = true) {
|
|
3209
|
+
this._live.forEach(array => array.destroy(isClear));
|
|
3210
|
+
this._managed.forEach(array => array.destroy(isClear));
|
|
3156
3211
|
this._managed.clear();
|
|
3157
3212
|
this._identifiers.clear();
|
|
3213
|
+
this._pending.clear();
|
|
3214
|
+
this._set.forEach(set => set.clear());
|
|
3215
|
+
this._visibilitySet.clear();
|
|
3158
3216
|
}
|
|
3159
3217
|
destroy() {
|
|
3160
3218
|
this.isDestroying = true;
|
|
3161
|
-
this.clear();
|
|
3219
|
+
this.clear(false);
|
|
3162
3220
|
this._live.clear();
|
|
3163
3221
|
this.isDestroyed = true;
|
|
3164
3222
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
@@ -3187,19 +3245,20 @@ function disassociateIdentifier(ArraysCache, array, identifier) {
|
|
|
3187
3245
|
cache.delete(array);
|
|
3188
3246
|
}
|
|
3189
3247
|
}
|
|
3190
|
-
function sync(array, changes) {
|
|
3248
|
+
function sync(array, changes, arraySet) {
|
|
3191
3249
|
let state = array[SOURCE];
|
|
3192
3250
|
const adds = [];
|
|
3193
3251
|
const removes = [];
|
|
3194
3252
|
changes.forEach((value, key) => {
|
|
3195
3253
|
if (value === 'add') {
|
|
3196
3254
|
// likely we want to keep a Set along-side
|
|
3197
|
-
if (
|
|
3255
|
+
if (arraySet.has(key)) {
|
|
3198
3256
|
return;
|
|
3199
3257
|
}
|
|
3200
3258
|
adds.push(key);
|
|
3259
|
+
arraySet.add(key);
|
|
3201
3260
|
} else {
|
|
3202
|
-
if (
|
|
3261
|
+
if (arraySet.has(key)) {
|
|
3203
3262
|
removes.push(key);
|
|
3204
3263
|
}
|
|
3205
3264
|
}
|
|
@@ -3207,6 +3266,7 @@ function sync(array, changes) {
|
|
|
3207
3266
|
if (removes.length) {
|
|
3208
3267
|
if (removes.length === state.length) {
|
|
3209
3268
|
state.length = 0;
|
|
3269
|
+
arraySet.clear();
|
|
3210
3270
|
// changing the reference breaks the Proxy
|
|
3211
3271
|
// state = array[SOURCE] = [];
|
|
3212
3272
|
} else {
|
|
@@ -3214,6 +3274,7 @@ function sync(array, changes) {
|
|
|
3214
3274
|
const index = state.indexOf(i);
|
|
3215
3275
|
if (index !== -1) {
|
|
3216
3276
|
state.splice(index, 1);
|
|
3277
|
+
arraySet.delete(i);
|
|
3217
3278
|
}
|
|
3218
3279
|
});
|
|
3219
3280
|
}
|
|
@@ -3232,11 +3293,9 @@ function sync(array, changes) {
|
|
|
3232
3293
|
}
|
|
3233
3294
|
}
|
|
3234
3295
|
|
|
3235
|
-
/**
|
|
3236
|
-
* @module @ember-data/store
|
|
3237
|
-
*/
|
|
3238
3296
|
const Touching = Symbol('touching');
|
|
3239
3297
|
const RequestPromise = Symbol('promise');
|
|
3298
|
+
const EMPTY_ARR = macroCondition(getOwnConfig().env.DEBUG) ? Object.freeze([]) : [];
|
|
3240
3299
|
function hasRecordIdentifier(op) {
|
|
3241
3300
|
return 'recordIdentifier' in op;
|
|
3242
3301
|
}
|
|
@@ -3250,9 +3309,9 @@ function hasRecordIdentifier(op) {
|
|
|
3250
3309
|
*/
|
|
3251
3310
|
class RequestStateService {
|
|
3252
3311
|
constructor(store) {
|
|
3253
|
-
this._pending =
|
|
3312
|
+
this._pending = new Map();
|
|
3254
3313
|
this._done = new Map();
|
|
3255
|
-
this._subscriptions =
|
|
3314
|
+
this._subscriptions = new Map();
|
|
3256
3315
|
this._toFlush = [];
|
|
3257
3316
|
this._store = void 0;
|
|
3258
3317
|
this._store = store;
|
|
@@ -3263,10 +3322,10 @@ class RequestStateService {
|
|
|
3263
3322
|
_enqueue(promise, queryRequest) {
|
|
3264
3323
|
let query = queryRequest.data[0];
|
|
3265
3324
|
if (hasRecordIdentifier(query)) {
|
|
3266
|
-
|
|
3325
|
+
const identifier = query.recordIdentifier;
|
|
3267
3326
|
let type = query.op === 'saveRecord' ? 'mutation' : 'query';
|
|
3268
|
-
if (!this._pending
|
|
3269
|
-
this._pending
|
|
3327
|
+
if (!this._pending.has(identifier)) {
|
|
3328
|
+
this._pending.set(identifier, []);
|
|
3270
3329
|
}
|
|
3271
3330
|
let request = {
|
|
3272
3331
|
state: 'pending',
|
|
@@ -3275,10 +3334,10 @@ class RequestStateService {
|
|
|
3275
3334
|
};
|
|
3276
3335
|
request[Touching] = [query.recordIdentifier];
|
|
3277
3336
|
request[RequestPromise] = promise;
|
|
3278
|
-
this._pending
|
|
3337
|
+
this._pending.get(identifier).push(request);
|
|
3279
3338
|
this._triggerSubscriptions(request);
|
|
3280
3339
|
return promise.then(result => {
|
|
3281
|
-
this._dequeue(
|
|
3340
|
+
this._dequeue(identifier, request);
|
|
3282
3341
|
let finalizedRequest = {
|
|
3283
3342
|
state: 'fulfilled',
|
|
3284
3343
|
request: queryRequest,
|
|
@@ -3292,7 +3351,7 @@ class RequestStateService {
|
|
|
3292
3351
|
this._triggerSubscriptions(finalizedRequest);
|
|
3293
3352
|
return result;
|
|
3294
3353
|
}, error => {
|
|
3295
|
-
this._dequeue(
|
|
3354
|
+
this._dequeue(identifier, request);
|
|
3296
3355
|
let finalizedRequest = {
|
|
3297
3356
|
state: 'rejected',
|
|
3298
3357
|
request: queryRequest,
|
|
@@ -3329,13 +3388,15 @@ class RequestStateService {
|
|
|
3329
3388
|
}
|
|
3330
3389
|
_flushRequest(req) {
|
|
3331
3390
|
req[Touching].forEach(identifier => {
|
|
3332
|
-
|
|
3333
|
-
|
|
3391
|
+
const subscriptions = this._subscriptions.get(identifier);
|
|
3392
|
+
if (subscriptions) {
|
|
3393
|
+
subscriptions.forEach(callback => callback(req));
|
|
3334
3394
|
}
|
|
3335
3395
|
});
|
|
3336
3396
|
}
|
|
3337
|
-
_dequeue(
|
|
3338
|
-
|
|
3397
|
+
_dequeue(identifier, request) {
|
|
3398
|
+
const pending = this._pending.get(identifier);
|
|
3399
|
+
this._pending.set(identifier, pending.filter(req => req !== request));
|
|
3339
3400
|
}
|
|
3340
3401
|
_addDone(request) {
|
|
3341
3402
|
request[Touching].forEach(identifier => {
|
|
@@ -3346,7 +3407,7 @@ class RequestStateService {
|
|
|
3346
3407
|
requests = requests.filter(req => {
|
|
3347
3408
|
// TODO add support for multiple
|
|
3348
3409
|
let data;
|
|
3349
|
-
if (req.request.data
|
|
3410
|
+
if (Array.isArray(req.request.data)) {
|
|
3350
3411
|
data = req.request.data[0];
|
|
3351
3412
|
} else {
|
|
3352
3413
|
data = req.request.data;
|
|
@@ -3390,10 +3451,12 @@ class RequestStateService {
|
|
|
3390
3451
|
* @param {(state: RequestState) => void} callback
|
|
3391
3452
|
*/
|
|
3392
3453
|
subscribeForRecord(identifier, callback) {
|
|
3393
|
-
|
|
3394
|
-
|
|
3454
|
+
let subscriptions = this._subscriptions.get(identifier);
|
|
3455
|
+
if (!subscriptions) {
|
|
3456
|
+
subscriptions = [];
|
|
3457
|
+
this._subscriptions.set(identifier, subscriptions);
|
|
3395
3458
|
}
|
|
3396
|
-
|
|
3459
|
+
subscriptions.push(callback);
|
|
3397
3460
|
}
|
|
3398
3461
|
|
|
3399
3462
|
/**
|
|
@@ -3405,10 +3468,7 @@ class RequestStateService {
|
|
|
3405
3468
|
* @returns {RequestState[]} an array of request states for any pending requests for the given identifier
|
|
3406
3469
|
*/
|
|
3407
3470
|
getPendingRequestsForRecord(identifier) {
|
|
3408
|
-
|
|
3409
|
-
return this._pending[identifier.lid];
|
|
3410
|
-
}
|
|
3411
|
-
return [];
|
|
3471
|
+
return this._pending.get(identifier) || EMPTY_ARR;
|
|
3412
3472
|
}
|
|
3413
3473
|
|
|
3414
3474
|
/**
|
|
@@ -3427,6 +3487,9 @@ class RequestStateService {
|
|
|
3427
3487
|
return null;
|
|
3428
3488
|
}
|
|
3429
3489
|
}
|
|
3490
|
+
function isNonEmptyString(str) {
|
|
3491
|
+
return Boolean(str && typeof str === 'string');
|
|
3492
|
+
}
|
|
3430
3493
|
function constructResource(type, id, lid) {
|
|
3431
3494
|
if (typeof type === 'object' && type !== null) {
|
|
3432
3495
|
let resource = type;
|
|
@@ -3623,17 +3686,34 @@ class Store extends EmberObject {
|
|
|
3623
3686
|
_run(cb) {
|
|
3624
3687
|
assert(`EmberData should never encounter a nested run`, !this._cbs);
|
|
3625
3688
|
const _cbs = this._cbs = {};
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3689
|
+
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
3690
|
+
try {
|
|
3691
|
+
cb();
|
|
3692
|
+
if (_cbs.coalesce) {
|
|
3693
|
+
_cbs.coalesce();
|
|
3694
|
+
}
|
|
3695
|
+
if (_cbs.sync) {
|
|
3696
|
+
_cbs.sync();
|
|
3697
|
+
}
|
|
3698
|
+
if (_cbs.notify) {
|
|
3699
|
+
_cbs.notify();
|
|
3700
|
+
}
|
|
3701
|
+
} finally {
|
|
3702
|
+
this._cbs = null;
|
|
3703
|
+
}
|
|
3704
|
+
} else {
|
|
3705
|
+
cb();
|
|
3706
|
+
if (_cbs.coalesce) {
|
|
3707
|
+
_cbs.coalesce();
|
|
3708
|
+
}
|
|
3709
|
+
if (_cbs.sync) {
|
|
3710
|
+
_cbs.sync();
|
|
3711
|
+
}
|
|
3712
|
+
if (_cbs.notify) {
|
|
3713
|
+
_cbs.notify();
|
|
3714
|
+
}
|
|
3715
|
+
this._cbs = null;
|
|
3635
3716
|
}
|
|
3636
|
-
this._cbs = null;
|
|
3637
3717
|
}
|
|
3638
3718
|
_join(cb) {
|
|
3639
3719
|
if (this._cbs) {
|
|
@@ -3666,9 +3746,8 @@ class Store extends EmberObject {
|
|
|
3666
3746
|
if (macroCondition(getOwnConfig().env.TESTING)) {
|
|
3667
3747
|
const all = [];
|
|
3668
3748
|
const pending = this._requestCache._pending;
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
all.push(...pending[lid].map(v => v[RequestPromise]));
|
|
3749
|
+
pending.forEach(requests => {
|
|
3750
|
+
all.push(...requests.map(v => v[RequestPromise]));
|
|
3672
3751
|
});
|
|
3673
3752
|
this.requestManager._pending.forEach(v => all.push(v));
|
|
3674
3753
|
const promise = Promise.allSettled(all);
|
|
@@ -3994,7 +4073,7 @@ class Store extends EmberObject {
|
|
|
3994
4073
|
};
|
|
3995
4074
|
if (resource.id) {
|
|
3996
4075
|
const identifier = this.identifierCache.peekRecordIdentifier(resource);
|
|
3997
|
-
assert(`The id ${properties.id} has already been used with another '${normalizedModelName}' record.`, !identifier);
|
|
4076
|
+
assert(`The id ${String(properties.id)} has already been used with another '${normalizedModelName}' record.`, !identifier);
|
|
3998
4077
|
}
|
|
3999
4078
|
const identifier = this.identifierCache.createIdentifierForNewRecord(resource);
|
|
4000
4079
|
const cache = this.cache;
|
|
@@ -4476,7 +4555,7 @@ class Store extends EmberObject {
|
|
|
4476
4555
|
assertDestroyingStore(this, 'peekRecord');
|
|
4477
4556
|
}
|
|
4478
4557
|
assert(`You need to pass a model name to the store's peekRecord method`, identifier);
|
|
4479
|
-
assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${identifier}`, typeof identifier === 'string');
|
|
4558
|
+
assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${String(identifier)}`, typeof identifier === 'string');
|
|
4480
4559
|
const type = normalizeModelName(identifier);
|
|
4481
4560
|
const normalizedId = ensureStringId(id);
|
|
4482
4561
|
const resource = {
|
|
@@ -4864,7 +4943,7 @@ class Store extends EmberObject {
|
|
|
4864
4943
|
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
4865
4944
|
assertDestroyedStoreOnly(this, 'unloadAll');
|
|
4866
4945
|
}
|
|
4867
|
-
assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, !modelName || typeof modelName === 'string');
|
|
4946
|
+
assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${String(modelName)}`, !modelName || typeof modelName === 'string');
|
|
4868
4947
|
this._join(() => {
|
|
4869
4948
|
if (modelName === undefined) {
|
|
4870
4949
|
// destroy the graph before unloadAll
|
|
@@ -5032,7 +5111,7 @@ class Store extends EmberObject {
|
|
|
5032
5111
|
@method _push
|
|
5033
5112
|
@private
|
|
5034
5113
|
@param {Object} jsonApiDoc
|
|
5035
|
-
@return {StableRecordIdentifier|Array<StableRecordIdentifier
|
|
5114
|
+
@return {StableRecordIdentifier|Array<StableRecordIdentifier>|null} identifiers for the primary records that had data loaded
|
|
5036
5115
|
*/
|
|
5037
5116
|
_push(jsonApiDoc, asyncFlush) {
|
|
5038
5117
|
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
@@ -5058,7 +5137,7 @@ class Store extends EmberObject {
|
|
|
5058
5137
|
});
|
|
5059
5138
|
});
|
|
5060
5139
|
this._enableAsyncFlush = null;
|
|
5061
|
-
return ret.data;
|
|
5140
|
+
return 'data' in ret ? ret.data : null;
|
|
5062
5141
|
}
|
|
5063
5142
|
|
|
5064
5143
|
/**
|
|
@@ -5109,19 +5188,10 @@ class Store extends EmberObject {
|
|
|
5109
5188
|
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5110
5189
|
assertDestroyingStore(this, 'pushPayload');
|
|
5111
5190
|
}
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
serializer = this.serializerFor('application');
|
|
5117
|
-
assert(`You cannot use 'store#pushPayload' without a modelName unless your default serializer defines 'pushPayload'`, typeof serializer.pushPayload === 'function');
|
|
5118
|
-
} else {
|
|
5119
|
-
payload = inputPayload;
|
|
5120
|
-
assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string');
|
|
5121
|
-
let normalizedModelName = normalizeModelName(modelName);
|
|
5122
|
-
serializer = this.serializerFor(normalizedModelName);
|
|
5123
|
-
}
|
|
5124
|
-
assert(`You must define a pushPayload method in your serializer in order to call store.pushPayload`, serializer.pushPayload);
|
|
5191
|
+
const payload = inputPayload || modelName;
|
|
5192
|
+
const normalizedModelName = inputPayload ? normalizeModelName(modelName) : 'application';
|
|
5193
|
+
const serializer = this.serializerFor(normalizedModelName);
|
|
5194
|
+
assert(`You cannot use 'store.pushPayload(<type>, <payload>)' unless the serializer for '${normalizedModelName}' defines 'pushPayload'`, serializer && typeof serializer.pushPayload === 'function');
|
|
5125
5195
|
serializer.pushPayload(this, payload);
|
|
5126
5196
|
}
|
|
5127
5197
|
|
|
@@ -5147,7 +5217,7 @@ class Store extends EmberObject {
|
|
|
5147
5217
|
return Promise.reject(`Record Is Disconnected`);
|
|
5148
5218
|
}
|
|
5149
5219
|
// TODO we used to check if the record was destroyed here
|
|
5150
|
-
assert(`Cannot initiate a save request for an unloaded record: ${identifier}`, this._instanceCache.recordIsLoaded(identifier));
|
|
5220
|
+
assert(`Cannot initiate a save request for an unloaded record: ${identifier.lid}`, this._instanceCache.recordIsLoaded(identifier));
|
|
5151
5221
|
if (resourceIsFullyDeleted(this._instanceCache, identifier)) {
|
|
5152
5222
|
return Promise.resolve(record);
|
|
5153
5223
|
}
|
|
@@ -5235,11 +5305,11 @@ class Store extends EmberObject {
|
|
|
5235
5305
|
}
|
|
5236
5306
|
assert(`You need to pass a model name to the store's normalize method`, modelName);
|
|
5237
5307
|
assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${typeof modelName}`, typeof modelName === 'string');
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
assert(`You must define a normalize method in your serializer in order to call store.normalize`, serializer?.normalize);
|
|
5242
|
-
return serializer.normalize(
|
|
5308
|
+
const normalizedModelName = normalizeModelName(modelName);
|
|
5309
|
+
const serializer = this.serializerFor(normalizedModelName);
|
|
5310
|
+
const schema = this.modelFor(normalizedModelName);
|
|
5311
|
+
assert(`You must define a normalize method in your serializer in order to call store.normalize`, typeof serializer?.normalize === 'function');
|
|
5312
|
+
return serializer.normalize(schema, payload);
|
|
5243
5313
|
}
|
|
5244
5314
|
|
|
5245
5315
|
/**
|
|
@@ -5268,7 +5338,7 @@ class Store extends EmberObject {
|
|
|
5268
5338
|
if (adapter) {
|
|
5269
5339
|
return adapter;
|
|
5270
5340
|
}
|
|
5271
|
-
|
|
5341
|
+
const owner = getOwner(this);
|
|
5272
5342
|
|
|
5273
5343
|
// name specific adapter
|
|
5274
5344
|
adapter = owner.lookup(`adapter:${normalizedModelName}`);
|
|
@@ -5315,9 +5385,9 @@ class Store extends EmberObject {
|
|
|
5315
5385
|
if (serializer) {
|
|
5316
5386
|
return serializer;
|
|
5317
5387
|
}
|
|
5318
|
-
let owner = getOwner(this);
|
|
5319
5388
|
|
|
5320
5389
|
// by name
|
|
5390
|
+
const owner = getOwner(this);
|
|
5321
5391
|
serializer = owner.lookup(`serializer:${normalizedModelName}`);
|
|
5322
5392
|
if (serializer !== undefined) {
|
|
5323
5393
|
_serializerCache[normalizedModelName] = serializer;
|
|
@@ -5369,9 +5439,11 @@ class Store extends EmberObject {
|
|
|
5369
5439
|
let assertDestroyingStore;
|
|
5370
5440
|
let assertDestroyedStoreOnly;
|
|
5371
5441
|
if (macroCondition(getOwnConfig().env.DEBUG)) {
|
|
5372
|
-
|
|
5442
|
+
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
5443
|
+
assertDestroyingStore = function assertDestroyingStore(store, method) {
|
|
5373
5444
|
assert(`Attempted to call store.${method}(), but the store instance has already been destroyed.`, !(store.isDestroying || store.isDestroyed));
|
|
5374
5445
|
};
|
|
5446
|
+
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
5375
5447
|
assertDestroyedStoreOnly = function assertDestroyedStoreOnly(store, method) {
|
|
5376
5448
|
assert(`Attempted to call store.${method}(), but the store instance has already been destroyed.`, !store.isDestroyed);
|
|
5377
5449
|
};
|