@ember-data/store 4.1.0-alpha.7 → 4.1.0

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.
@@ -2,7 +2,6 @@
2
2
  @module @ember-data/store
3
3
  */
4
4
  import { assert, warn } from '@ember/debug';
5
- import { assign } from '@ember/polyfills';
6
5
  import { DEBUG } from '@glimmer/env';
7
6
 
8
7
  import coerceId from '../system/coerce-id';
@@ -23,7 +22,6 @@ import type {
23
22
  import { DEBUG_CLIENT_ORIGINATED, DEBUG_IDENTIFIER_BUCKET } from '../ts-interfaces/identifier';
24
23
  import type { ConfidentDict } from '../ts-interfaces/utils';
25
24
  import isNonEmptyString from '../utils/is-non-empty-string';
26
- import { addSymbol } from '../utils/symbol';
27
25
  import isStableIdentifier, { markStableIdentifier, unmarkStableIdentifier } from './is-stable-identifier';
28
26
  import uuidv4 from './utils/uuid-v4';
29
27
 
@@ -372,7 +370,7 @@ export class IdentifierCache {
372
370
  // If the incoming type does not match the identifier type, we need to create an identifier for the incoming
373
371
  // data so we can merge the incoming data with the existing identifier, see #7325 and #7363
374
372
  if ('type' in data && data.type && identifier.type !== normalizeModelName(data.type)) {
375
- let incomingDataResource = assign({}, data);
373
+ let incomingDataResource = { ...data };
376
374
  // Need to strip the lid from the incomingData in order force a new identifier creation
377
375
  delete incomingDataResource.lid;
378
376
  existingIdentifier = this.getOrCreateRecordIdentifier(incomingDataResource);
@@ -511,8 +509,8 @@ function makeStableRecordIdentifier(
511
509
  return `${clientOriginated ? '[CLIENT_ORIGINATED] ' : ''}${type}:${id} (${lid})`;
512
510
  },
513
511
  };
514
- addSymbol(wrapper, DEBUG_CLIENT_ORIGINATED, clientOriginated);
515
- addSymbol(wrapper, DEBUG_IDENTIFIER_BUCKET, bucket);
512
+ wrapper[DEBUG_CLIENT_ORIGINATED] = clientOriginated;
513
+ wrapper[DEBUG_IDENTIFIER_BUCKET] = bucket;
516
514
  wrapper = freeze(wrapper);
517
515
  markStableIdentifier(wrapper);
518
516
  DEBUG_MAP.set(wrapper, recordIdentifier);
@@ -2,13 +2,6 @@
2
2
  @module @ember-data/store
3
3
  */
4
4
 
5
- // support IE11
6
- declare global {
7
- interface Window {
8
- msCrypto: Crypto;
9
- }
10
- }
11
-
12
5
  const CRYPTO = (() => {
13
6
  const hasWindow = typeof window !== 'undefined';
14
7
  const isFastBoot = typeof FastBoot !== 'undefined';
@@ -27,12 +20,6 @@ const CRYPTO = (() => {
27
20
  };
28
21
  } else if (hasWindow && typeof window.crypto !== 'undefined') {
29
22
  return window.crypto;
30
- } else if (
31
- hasWindow &&
32
- typeof window.msCrypto !== 'undefined' &&
33
- typeof window.msCrypto.getRandomValues === 'function'
34
- ) {
35
- return window.msCrypto;
36
23
  } else {
37
24
  throw new Error('ember-data: Cannot find a valid way to generate local identifiers');
38
25
  }
@@ -25,7 +25,6 @@ export { default as RootState } from './system/model/states';
25
25
  export { default as InternalModel } from './system/model/internal-model';
26
26
 
27
27
  export { PromiseArray, PromiseObject } from './system/promise-proxies';
28
- export { addSymbol, symbol } from './utils/symbol';
29
28
 
30
29
  export { RecordArray, AdapterPopulatedRecordArray } from './system/record-arrays';
31
30
 
@@ -5,7 +5,6 @@ import { getOwner } from '@ember/application';
5
5
  import { A } from '@ember/array';
6
6
  import { assert, deprecate, inspect, warn } from '@ember/debug';
7
7
  import { computed, defineProperty, get, set } from '@ember/object';
8
- import { assign } from '@ember/polyfills';
9
8
  import { _backburner as emberBackburner } from '@ember/runloop';
10
9
  import type { Backburner } from '@ember/runloop/-private/backburner';
11
10
  import Service from '@ember/service';
@@ -68,7 +67,6 @@ import type { FindOptions } from '../ts-interfaces/store';
68
67
  import type { Dict } from '../ts-interfaces/utils';
69
68
  import constructResource from '../utils/construct-resource';
70
69
  import promiseRecord from '../utils/promise-record';
71
- import { addSymbol } from '../utils/symbol';
72
70
  import edBackburner from './backburner';
73
71
  import coerceId, { ensureStringId } from './coerce-id';
74
72
  import { errorsArrayToHash } from './errors-utils';
@@ -646,7 +644,7 @@ abstract class CoreStore extends Service {
646
644
  return emberBackburner.join(() => {
647
645
  return this._backburner.join(() => {
648
646
  let normalizedModelName = normalizeModelName(modelName);
649
- let properties = assign({}, inputProperties);
647
+ let properties = { ...inputProperties };
650
648
 
651
649
  // If the passed properties do not include a primary key,
652
650
  // give the adapter an opportunity to generate one. Typically,
@@ -1280,7 +1278,7 @@ abstract class CoreStore extends Service {
1280
1278
  return Promise.resolve(internalModel);
1281
1279
  }
1282
1280
 
1283
- _findByInternalModel(internalModel, options: { preload?: any } = {}) {
1281
+ _findByInternalModel(internalModel: InternalModel, options: FindOptions = {}) {
1284
1282
  if (options.preload) {
1285
1283
  this._backburner.join(() => {
1286
1284
  internalModel.preloadData(options.preload);
@@ -1295,7 +1293,7 @@ abstract class CoreStore extends Service {
1295
1293
  );
1296
1294
  }
1297
1295
 
1298
- _findEmptyInternalModel(internalModel, options) {
1296
+ _findEmptyInternalModel(internalModel: InternalModel, options: FindOptions) {
1299
1297
  if (internalModel.currentState.isEmpty) {
1300
1298
  return this._scheduleFetch(internalModel, options);
1301
1299
  }
@@ -1307,9 +1305,9 @@ abstract class CoreStore extends Service {
1307
1305
  }
1308
1306
  } else {
1309
1307
  if (internalModel.currentState.isLoading) {
1310
- let pending = this._fetchManager.getPendingFetch(internalModel.identifier);
1311
- if (pending) {
1312
- return pending.then(() => Promise.resolve(internalModel));
1308
+ let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier, options);
1309
+ if (pendingRequest) {
1310
+ return pendingRequest.then(() => Promise.resolve(internalModel));
1313
1311
  }
1314
1312
  return this._scheduleFetch(internalModel, options);
1315
1313
  }
@@ -1601,18 +1599,14 @@ abstract class CoreStore extends Service {
1601
1599
  groups = [snapshots];
1602
1600
  }
1603
1601
 
1604
- // we use var here because babel transpiles let
1605
- // in a manner that causes a mega-bad perf scenario here
1606
- // when targets no longer include IE11 we can drop this.
1607
- /* eslint-disable no-var */
1608
- for (var i = 0, l = groups.length; i < l; i++) {
1609
- var group = groups[i];
1610
- var totalInGroup = groups[i].length;
1611
- var ids = new Array(totalInGroup);
1612
- var groupedInternalModels = new Array(totalInGroup);
1602
+ for (let i = 0, l = groups.length; i < l; i++) {
1603
+ let group = groups[i];
1604
+ let totalInGroup = groups[i].length;
1605
+ let ids = new Array(totalInGroup);
1606
+ let groupedInternalModels = new Array(totalInGroup);
1613
1607
 
1614
- for (var j = 0; j < totalInGroup; j++) {
1615
- var internalModel = group[j]._internalModel;
1608
+ for (let j = 0; j < totalInGroup; j++) {
1609
+ let internalModel = group[j]._internalModel;
1616
1610
 
1617
1611
  groupedInternalModels[j] = internalModel;
1618
1612
  ids[j] = internalModel.id;
@@ -1629,7 +1623,7 @@ abstract class CoreStore extends Service {
1629
1623
  });
1630
1624
  })(groupedInternalModels);
1631
1625
  } else if (ids.length === 1) {
1632
- var pair = seeking[groupedInternalModels[0].id];
1626
+ let pair = seeking[groupedInternalModels[0].id];
1633
1627
  _fetchRecord(pair);
1634
1628
  } else {
1635
1629
  assert("You cannot return an empty array from adapter's method groupRecordsForFindMany");
@@ -1765,7 +1759,7 @@ abstract class CoreStore extends Service {
1765
1759
  if (arguments.length === 1 && isMaybeIdentifier(identifier)) {
1766
1760
  let stableIdentifier = identifierCacheFor(this).peekRecordIdentifier(identifier);
1767
1761
  if (stableIdentifier) {
1768
- return internalModelFactoryFor(this).peek(stableIdentifier)?.getRecord();
1762
+ return internalModelFactoryFor(this).peek(stableIdentifier)?.getRecord() || null;
1769
1763
  }
1770
1764
  return null;
1771
1765
  }
@@ -2055,7 +2049,7 @@ abstract class CoreStore extends Service {
2055
2049
  if (internalModel) {
2056
2050
  // short circuit if we are already loading
2057
2051
  if (REQUEST_SERVICE) {
2058
- let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier);
2052
+ let pendingRequest = this._fetchManager.getPendingFetch(internalModel.identifier, options);
2059
2053
  if (pendingRequest) {
2060
2054
  return pendingRequest.then(() => internalModel.getRecord());
2061
2055
  }
@@ -2087,6 +2081,10 @@ abstract class CoreStore extends Service {
2087
2081
  return resolve(null);
2088
2082
  }
2089
2083
 
2084
+ if (!internalModel) {
2085
+ assert(`No InternalModel found for ${resource.lid}`, internalModel);
2086
+ }
2087
+
2090
2088
  return this._findByInternalModel(internalModel, options);
2091
2089
  }
2092
2090
 
@@ -2714,7 +2712,7 @@ abstract class CoreStore extends Service {
2714
2712
  operation = 'deleteRecord';
2715
2713
  }
2716
2714
 
2717
- addSymbol(options, SaveOp, operation);
2715
+ options[SaveOp] = operation;
2718
2716
 
2719
2717
  let fetchManagerPromise = this._fetchManager.scheduleSave(internalModel.identifier, options);
2720
2718
  let promise = fetchManagerPromise.then(
@@ -2,7 +2,6 @@ import { getOwner, setOwner } from '@ember/application';
2
2
  import { assert, deprecate } from '@ember/debug';
3
3
  import EmberError from '@ember/error';
4
4
  import { get } from '@ember/object';
5
- import { assign } from '@ember/polyfills';
6
5
  import { isPresent } from '@ember/utils';
7
6
  import { DEBUG } from '@glimmer/env';
8
7
 
@@ -38,9 +37,10 @@ class Store extends CoreStore {
38
37
  let createOptions: any = {
39
38
  store: this,
40
39
  _internalModel: internalModel,
40
+ // TODO deprecate allowing unknown args setting
41
+ _createProps: createRecordArgs,
41
42
  container: null,
42
43
  };
43
- assign(createOptions, createRecordArgs);
44
44
 
45
45
  // ensure that `getOwner(this)` works inside a model instance
46
46
  setOwner(createOptions, getOwner(this));
@@ -12,7 +12,6 @@ import type { CollectionResourceDocument, SingleResourceDocument } from '../ts-i
12
12
  import type { FindRecordQuery, Request, SaveRecordMutation } from '../ts-interfaces/fetch-manager';
13
13
  import type { ExistingRecordIdentifier, RecordIdentifier, StableRecordIdentifier } from '../ts-interfaces/identifier';
14
14
  import type { Dict } from '../ts-interfaces/utils';
15
- import { symbol } from '../utils/symbol';
16
15
  import coerceId from './coerce-id';
17
16
  import type CoreStore from './core-store';
18
17
  import { errorsArrayToHash } from './errors-utils';
@@ -30,7 +29,7 @@ function payloadIsNotBlank(adapterPayload): boolean {
30
29
  }
31
30
  }
32
31
 
33
- export const SaveOp: unique symbol = symbol('SaveOp');
32
+ export const SaveOp: unique symbol = Symbol('SaveOp');
34
33
 
35
34
  interface PendingFetchItem {
36
35
  identifier: ExistingRecordIdentifier;
@@ -502,10 +501,10 @@ export default class FetchManager {
502
501
  }
503
502
  }
504
503
 
505
- getPendingFetch(identifier: StableRecordIdentifier) {
506
- let pendingRequests = this.requestCache
507
- .getPendingRequestsForRecord(identifier)
508
- .filter((req) => req.type === 'query');
504
+ getPendingFetch(identifier: StableRecordIdentifier, options) {
505
+ let pendingRequests = this.requestCache.getPendingRequestsForRecord(identifier).filter((req) => {
506
+ return req.type === 'query' && isSameRequest(options, req.request.data[0].options);
507
+ });
509
508
 
510
509
  if (pendingRequests.length > 0) {
511
510
  return pendingRequests[0][RequestPromise];
@@ -533,3 +532,8 @@ function assertIsString(id: string | null): asserts id is string {
533
532
  }
534
533
  }
535
534
  }
535
+
536
+ // this function helps resolve whether we have a pending request that we should use instead
537
+ function isSameRequest(options: Dict<unknown> = {}, reqOptions: Dict<unknown> = {}) {
538
+ return options.include === reqOptions.include;
539
+ }
@@ -3,7 +3,6 @@ import { A, default as EmberArray } from '@ember/array';
3
3
  import { assert, inspect } from '@ember/debug';
4
4
  import EmberError from '@ember/error';
5
5
  import { get, set } from '@ember/object';
6
- import { assign } from '@ember/polyfills';
7
6
  import { _backburner as emberBackburner, cancel, run } from '@ember/runloop';
8
7
  import { DEBUG } from '@glimmer/env';
9
8
 
@@ -25,6 +24,7 @@ import type {
25
24
  import type { UpgradedMeta } from '@ember-data/record-data/-private/graph/-edge-definition';
26
25
 
27
26
  import { identifierCacheFor } from '../../identifiers/cache';
27
+ import { DSModel } from '../../ts-interfaces/ds-model';
28
28
  import type { StableRecordIdentifier } from '../../ts-interfaces/identifier';
29
29
  import type { RecordData } from '../../ts-interfaces/record-data';
30
30
  import type { JsonApiResource, JsonApiValidationError } from '../../ts-interfaces/record-data-json-api';
@@ -128,7 +128,7 @@ export default class InternalModel {
128
128
  declare _deferredTriggers: any;
129
129
  declare __recordArrays: any;
130
130
  declare references: any;
131
- declare _recordReference: any;
131
+ declare _recordReference: RecordReference;
132
132
  declare _manyArrayCache: ConfidentDict<ManyArray>;
133
133
 
134
134
  declare _relationshipPromisesCache: ConfidentDict<RSVP.Promise<any>>;
@@ -200,7 +200,7 @@ export default class InternalModel {
200
200
  }
201
201
  }
202
202
 
203
- get recordReference() {
203
+ get recordReference(): RecordReference {
204
204
  if (this._recordReference === null) {
205
205
  this._recordReference = new RecordReference(this.store, this.identifier);
206
206
  }
@@ -292,7 +292,7 @@ export default class InternalModel {
292
292
  }
293
293
  }
294
294
 
295
- getRecord(properties?) {
295
+ getRecord(properties?): Object {
296
296
  if (!this._record && !this._isDematerializing) {
297
297
  let { store } = this;
298
298
 
@@ -354,7 +354,7 @@ export default class InternalModel {
354
354
  }
355
355
 
356
356
  let additionalCreateOptions = this._recordData._initRecordCreateOptions(properties);
357
- assign(createOptions, additionalCreateOptions);
357
+ Object.assign(createOptions, additionalCreateOptions);
358
358
 
359
359
  // ensure that `getOwner(this)` works inside a model instance
360
360
  setOwner(createOptions, getOwner(store));
@@ -614,7 +614,7 @@ export default class InternalModel {
614
614
  "' with id " +
615
615
  parentInternalModel.id +
616
616
  ' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`belongsTo({ async: true })`)',
617
- toReturn === null || !toReturn.get('isEmpty')
617
+ toReturn === null || !(toReturn as DSModel).isEmpty
618
618
  );
619
619
  return toReturn;
620
620
  }
@@ -673,7 +673,7 @@ export default class InternalModel {
673
673
  assert(`hasMany only works with the @ember-data/record-data package`);
674
674
  }
675
675
 
676
- getHasMany(key: string, options) {
676
+ getHasMany(key: string, options?) {
677
677
  if (HAS_RECORD_DATA_PACKAGE) {
678
678
  const graphFor = require('@ember-data/record-data/-private').graphFor;
679
679
  const relationship = graphFor(this.store).get(this.identifier, key);
@@ -791,11 +791,22 @@ export default class InternalModel {
791
791
  !this._record || this._record.get('isDestroyed') || this._record.get('isDestroying')
792
792
  );
793
793
  this.isDestroying = true;
794
+ if (this._recordReference) {
795
+ this._recordReference.destroy();
796
+ }
797
+ this._recordReference = null;
794
798
  let cache = this._manyArrayCache;
795
799
  Object.keys(cache).forEach((key) => {
796
800
  cache[key].destroy();
797
801
  delete cache[key];
798
802
  });
803
+ if (this.references) {
804
+ cache = this.references;
805
+ Object.keys(cache).forEach((key) => {
806
+ cache[key].destroy();
807
+ delete cache[key];
808
+ });
809
+ }
799
810
 
800
811
  internalModelFactoryFor(this.store).remove(this);
801
812
  this._isDestroyed = true;
@@ -804,6 +815,7 @@ export default class InternalModel {
804
815
  setupData(data) {
805
816
  let changedKeys = this._recordData.pushData(data, this.hasRecord);
806
817
  if (this.hasRecord) {
818
+ // TODO @runspired should this be going through the notification manager?
807
819
  this._record._notifyProperties(changedKeys);
808
820
  }
809
821
  this.send('pushedData');
@@ -903,11 +915,18 @@ export default class InternalModel {
903
915
 
904
916
  notifyHasManyChange(key: string) {
905
917
  if (this.hasRecord) {
918
+ let manyArray = this._manyArrayCache[key];
919
+ let hasPromise = !!this._relationshipPromisesCache[key];
920
+
921
+ if (manyArray && hasPromise) {
922
+ // do nothing, we will notify the ManyArray directly
923
+ // once the fetch has completed.
924
+ return;
925
+ }
926
+
906
927
  if (CUSTOM_MODEL_CLASS) {
907
928
  this.store._notificationManager.notify(this.identifier, 'relationships', key);
908
929
  } else {
909
- let manyArray = this._manyArrayCache[key];
910
-
911
930
  if (manyArray) {
912
931
  manyArray.notify();
913
932
 
@@ -957,10 +976,10 @@ export default class InternalModel {
957
976
  this.store._notificationManager.notify(this.identifier, 'state');
958
977
  } else {
959
978
  if (!key || key === 'isNew') {
960
- this.getRecord().notifyPropertyChange('isNew');
979
+ (this.getRecord() as DSModel).notifyPropertyChange('isNew');
961
980
  }
962
981
  if (!key || key === 'isDeleted') {
963
- this.getRecord().notifyPropertyChange('isDeleted');
982
+ (this.getRecord() as DSModel).notifyPropertyChange('isDeleted');
964
983
  }
965
984
  }
966
985
  }
@@ -1264,12 +1283,12 @@ export default class InternalModel {
1264
1283
  if (this._recordData.getErrors) {
1265
1284
  return this._recordData.getErrors(this.identifier).length > 0;
1266
1285
  } else {
1267
- let errors = get(this.getRecord(), 'errors');
1268
- return errors.get('length') > 0;
1286
+ let errors = (this.getRecord() as DSModel).errors;
1287
+ return errors.length > 0;
1269
1288
  }
1270
1289
  } else {
1271
- let errors = get(this.getRecord(), 'errors');
1272
- return errors.get('length') > 0;
1290
+ let errors = (this.getRecord() as DSModel).errors;
1291
+ return errors.length > 0;
1273
1292
  }
1274
1293
  }
1275
1294
 
@@ -1284,7 +1303,7 @@ export default class InternalModel {
1284
1303
  if (!this._recordData.getErrors) {
1285
1304
  for (attribute in parsedErrors) {
1286
1305
  if (hasOwnProperty.call(parsedErrors, attribute)) {
1287
- this.getRecord().errors._add(attribute, parsedErrors[attribute]);
1306
+ (this.getRecord() as DSModel).errors._add(attribute, parsedErrors[attribute]);
1288
1307
  }
1289
1308
  }
1290
1309
  }
@@ -1304,7 +1323,7 @@ export default class InternalModel {
1304
1323
 
1305
1324
  for (attribute in parsedErrors) {
1306
1325
  if (hasOwnProperty.call(parsedErrors, attribute)) {
1307
- this.getRecord().errors._add(attribute, parsedErrors[attribute]);
1326
+ (this.getRecord() as DSModel).errors._add(attribute, parsedErrors[attribute]);
1308
1327
  }
1309
1328
  }
1310
1329
 
@@ -1456,15 +1475,11 @@ export function extractRecordDataFromRecord(recordOrPromiseRecord) {
1456
1475
  }
1457
1476
 
1458
1477
  function anyUnloaded(store: CoreStore, relationship: ManyRelationship) {
1459
- // Can't use `find` because of IE11 and these arrays are potentially massive
1460
1478
  let state = relationship.currentState;
1461
- let unloaded = false;
1462
- for (let i = 0; i < state.length; i++) {
1463
- let im = store._internalModelForResource(state[i]);
1464
- if (im._isDematerializing || !im.currentState.isLoaded) {
1465
- unloaded = true;
1466
- break;
1467
- }
1468
- }
1469
- return unloaded;
1479
+ const unloaded = state.find((s) => {
1480
+ let im = store._internalModelForResource(s);
1481
+ return im._isDematerializing || !im.currentState.isLoaded;
1482
+ });
1483
+
1484
+ return unloaded || false;
1470
1485
  }
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { assert } from '@ember/debug';
5
5
 
6
- import { REQUEST_SERVICE } from '@ember-data/canary-features';
6
+ import { CUSTOM_MODEL_CLASS, REQUEST_SERVICE } from '@ember-data/canary-features';
7
7
  /*
8
8
  This file encapsulates the various states that a record can transition
9
9
  through during its lifecycle.
@@ -431,6 +431,12 @@ createdState.uncommitted.rollback = function (internalModel) {
431
431
  };
432
432
 
433
433
  createdState.uncommitted.pushedData = function (internalModel) {
434
+ // TODO @runspired consider where to do this once we kill off state machine
435
+ if (CUSTOM_MODEL_CLASS) {
436
+ internalModel.store._notificationManager.notify(internalModel.identifier, 'identity');
437
+ } else {
438
+ internalModel.notifyPropertyChange('id');
439
+ }
434
440
  internalModel.transitionTo('loaded.updated.uncommitted');
435
441
  internalModel.triggerLater('didLoad');
436
442
  };
@@ -5,7 +5,6 @@
5
5
  import { A } from '@ember/array';
6
6
  import { assert } from '@ember/debug';
7
7
  import { get, set } from '@ember/object';
8
- import { assign } from '@ember/polyfills';
9
8
  import { _backburner as emberBackburner } from '@ember/runloop';
10
9
 
11
10
  import { REMOVE_RECORD_ARRAY_MANAGER_LEGACY_COMPAT } from '@ember-data/canary-features';
@@ -281,8 +280,8 @@ class RecordArrayManager {
281
280
  manager: this,
282
281
  isLoaded: true,
283
282
  isUpdating: false,
284
- meta: assign({}, payload.meta),
285
- links: assign({}, payload.links),
283
+ meta: { ...payload.meta },
284
+ links: { ...payload.links },
286
285
  });
287
286
 
288
287
  this._associateWithRecordArray(identifiers, array);
@@ -1,6 +1,5 @@
1
1
  import { A } from '@ember/array';
2
2
  import { get } from '@ember/object';
3
- import { assign } from '@ember/polyfills';
4
3
  import { once } from '@ember/runloop';
5
4
  import { DEBUG } from '@glimmer/env';
6
5
 
@@ -86,8 +85,8 @@ let AdapterPopulatedRecordArray = RecordArray.extend({
86
85
  this.setProperties({
87
86
  isLoaded: true,
88
87
  isUpdating: false,
89
- meta: assign({}, payload.meta),
90
- links: assign({}, payload.links),
88
+ meta: { ...payload.meta },
89
+ links: { ...payload.links },
91
90
  });
92
91
 
93
92
  this.manager._associateWithRecordArray(identifiersOrInternalModels, this);
@@ -4,7 +4,7 @@ import type CoreStore from './core-store';
4
4
 
5
5
  type UnsubscribeToken = Object;
6
6
 
7
- const Cache = new WeakMap<StableRecordIdentifier, NotificationCallback>();
7
+ const Cache = new WeakMap<StableRecordIdentifier, Map<UnsubscribeToken, NotificationCallback>>();
8
8
  const Tokens = new WeakMap<UnsubscribeToken, StableRecordIdentifier>();
9
9
 
10
10
  export type NotificationType =
@@ -29,7 +29,8 @@ export function unsubscribe(token: UnsubscribeToken) {
29
29
  throw new Error('Passed unknown unsubscribe token to unsubscribe');
30
30
  }
31
31
  Tokens.delete(token);
32
- Cache.delete(identifier);
32
+ const map = Cache.get(identifier);
33
+ map?.delete(token);
33
34
  }
34
35
  /*
35
36
  Currently only support a single callback per identifier
@@ -39,8 +40,13 @@ export default class NotificationManager {
39
40
 
40
41
  subscribe(identifier: RecordIdentifier, callback: NotificationCallback): UnsubscribeToken {
41
42
  let stableIdentifier = identifierCacheFor(this.store).getOrCreateRecordIdentifier(identifier);
42
- Cache.set(stableIdentifier, callback);
43
+ let map = Cache.get(stableIdentifier);
44
+ if (map === undefined) {
45
+ map = new Map();
46
+ Cache.set(stableIdentifier, map);
47
+ }
43
48
  let unsubToken = {};
49
+ map.set(unsubToken, callback);
44
50
  Tokens.set(unsubToken, stableIdentifier);
45
51
  return unsubToken;
46
52
  }
@@ -49,11 +55,13 @@ export default class NotificationManager {
49
55
  notify(identifier: RecordIdentifier, value: 'errors' | 'meta' | 'identity' | 'unload' | 'state'): boolean;
50
56
  notify(identifier: RecordIdentifier, value: NotificationType, key?: string): boolean {
51
57
  let stableIdentifier = identifierCacheFor(this.store).getOrCreateRecordIdentifier(identifier);
52
- let callback = Cache.get(stableIdentifier);
53
- if (!callback) {
58
+ let callbackMap = Cache.get(stableIdentifier);
59
+ if (!callbackMap || !callbackMap.size) {
54
60
  return false;
55
61
  }
56
- callback(stableIdentifier, value, key);
62
+ callbackMap.forEach((cb) => {
63
+ cb(stableIdentifier, value, key);
64
+ });
57
65
  return true;
58
66
  }
59
67
  }