@ember-data/store 4.8.0-alpha.4 → 4.8.0-beta.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.
@@ -1,71 +1,73 @@
1
1
  /**
2
2
  @module @ember-data/store
3
3
  */
4
- const isFastBoot = typeof FastBoot !== 'undefined';
5
- const CRYPTO: Crypto = isFastBoot ? (FastBoot.require('crypto') as Crypto) : window.crypto;
6
-
7
4
  interface FastbootCrypto {
8
5
  randomFillSync(v: Uint8Array): Uint8Array;
9
6
  }
10
7
 
11
- if (!CRYPTO.randomUUID) {
12
- // we might be able to optimize this by requesting more bytes than we need at a time
13
- const rng = function (): Uint8Array {
14
- // WHATWG crypto RNG - http://wiki.whatwg.org/wiki/Crypto
15
- let rnds8 = new Uint8Array(16);
8
+ export default function installPolyfill() {
9
+ const isFastBoot = typeof FastBoot !== 'undefined';
10
+ const CRYPTO: Crypto = isFastBoot ? (FastBoot.require('crypto') as Crypto) : window.crypto;
16
11
 
17
- if (!CRYPTO.getRandomValues && !isFastBoot) {
18
- throw new Error(`Unable to generate bytes for UUID`);
19
- }
12
+ if (!CRYPTO.randomUUID) {
13
+ // we might be able to optimize this by requesting more bytes than we need at a time
14
+ const rng = function (): Uint8Array {
15
+ // WHATWG crypto RNG - http://wiki.whatwg.org/wiki/Crypto
16
+ let rnds8 = new Uint8Array(16);
20
17
 
21
- return CRYPTO.getRandomValues
22
- ? CRYPTO.getRandomValues(rnds8)
23
- : (CRYPTO as unknown as FastbootCrypto).randomFillSync(rnds8);
24
- };
18
+ if (!CRYPTO.getRandomValues && !isFastBoot) {
19
+ throw new Error(`Unable to generate bytes for UUID`);
20
+ }
25
21
 
26
- /*
27
- * Convert array of 16 byte values to UUID string format of the form:
28
- * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
29
- */
30
- const byteToHex: string[] = [];
31
- for (let i = 0; i < 256; ++i) {
32
- byteToHex[i] = (i + 0x100).toString(16).substr(1);
33
- }
22
+ return CRYPTO.getRandomValues
23
+ ? CRYPTO.getRandomValues(rnds8)
24
+ : (CRYPTO as unknown as FastbootCrypto).randomFillSync(rnds8);
25
+ };
34
26
 
35
- const bytesToUuid = function (buf: Uint8Array) {
36
- let bth = byteToHex;
37
- // join used to fix memory issue caused by concatenation: https://bugs.chromium.org/p/v8/issues/detail?id=3175#c4
38
- return [
39
- bth[buf[0]],
40
- bth[buf[1]],
41
- bth[buf[2]],
42
- bth[buf[3]],
43
- '-',
44
- bth[buf[4]],
45
- bth[buf[5]],
46
- '-',
47
- bth[buf[6]],
48
- bth[buf[7]],
49
- '-',
50
- bth[buf[8]],
51
- bth[buf[9]],
52
- '-',
53
- bth[buf[10]],
54
- bth[buf[11]],
55
- bth[buf[12]],
56
- bth[buf[13]],
57
- bth[buf[14]],
58
- bth[buf[15]],
59
- ].join('');
60
- };
27
+ /*
28
+ * Convert array of 16 byte values to UUID string format of the form:
29
+ * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
30
+ */
31
+ const byteToHex: string[] = [];
32
+ for (let i = 0; i < 256; ++i) {
33
+ byteToHex[i] = (i + 0x100).toString(16).substr(1);
34
+ }
35
+
36
+ const bytesToUuid = function (buf: Uint8Array) {
37
+ let bth = byteToHex;
38
+ // join used to fix memory issue caused by concatenation: https://bugs.chromium.org/p/v8/issues/detail?id=3175#c4
39
+ return [
40
+ bth[buf[0]],
41
+ bth[buf[1]],
42
+ bth[buf[2]],
43
+ bth[buf[3]],
44
+ '-',
45
+ bth[buf[4]],
46
+ bth[buf[5]],
47
+ '-',
48
+ bth[buf[6]],
49
+ bth[buf[7]],
50
+ '-',
51
+ bth[buf[8]],
52
+ bth[buf[9]],
53
+ '-',
54
+ bth[buf[10]],
55
+ bth[buf[11]],
56
+ bth[buf[12]],
57
+ bth[buf[13]],
58
+ bth[buf[14]],
59
+ bth[buf[15]],
60
+ ].join('');
61
+ };
61
62
 
62
- CRYPTO.randomUUID = function uuidv4(): string {
63
- let rnds = rng();
63
+ CRYPTO.randomUUID = function uuidv4(): string {
64
+ let rnds = rng();
64
65
 
65
- // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
66
- rnds[6] = (rnds[6] & 0x0f) | 0x40;
67
- rnds[8] = (rnds[8] & 0x3f) | 0x80;
66
+ // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
67
+ rnds[6] = (rnds[6] & 0x0f) | 0x40;
68
+ rnds[8] = (rnds[8] & 0x3f) | 0x80;
68
69
 
69
- return bytesToUuid(rnds);
70
- };
70
+ return bytesToUuid(rnds);
71
+ };
72
+ }
71
73
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ember-data/store",
3
- "version": "4.8.0-alpha.4",
3
+ "version": "4.8.0-beta.0",
4
4
  "description": "The core of EmberData. Provides the Store service which coordinates the cache with the network and presentation layers.",
5
5
  "keywords": [
6
6
  "ember-addon"
@@ -21,8 +21,8 @@
21
21
  "start": "ember serve"
22
22
  },
23
23
  "dependencies": {
24
- "@ember-data/canary-features": "4.8.0-alpha.4",
25
- "@ember-data/private-build-infra": "4.8.0-alpha.4",
24
+ "@ember-data/canary-features": "4.8.0-beta.0",
25
+ "@ember-data/private-build-infra": "4.8.0-beta.0",
26
26
  "@ember/string": "^3.0.0",
27
27
  "@embroider/macros": "^1.8.3",
28
28
  "@glimmer/tracking": "^1.1.2",
@@ -33,7 +33,7 @@
33
33
  "ember-cli-typescript": "^5.1.0"
34
34
  },
35
35
  "devDependencies": {
36
- "@ember-data/unpublished-test-infra": "4.8.0-alpha.4",
36
+ "@ember-data/unpublished-test-infra": "4.8.0-beta.0",
37
37
  "@ember/optional-features": "^2.0.0",
38
38
  "@ember/test-helpers": "~2.7.0",
39
39
  "@types/ember": "^4.0.1",
@@ -66,7 +66,7 @@
66
66
  "configPath": "tests/dummy/config"
67
67
  },
68
68
  "volta": {
69
- "node": "16.16.0",
69
+ "node": "16.17.0",
70
70
  "yarn": "1.22.19"
71
71
  }
72
72
  }
@@ -1,25 +0,0 @@
1
- /**
2
- @module @ember-data/store
3
- */
4
-
5
- import { registerWaiter } from '@ember/test';
6
- import { DEBUG } from '@glimmer/env';
7
- import Ember from 'ember';
8
-
9
- // TODO: expose Ember._Backburner as `import { _Backburner } from '@ember/runloop'` in ember-rfc176-data + emberjs/ember.js
10
- /*
11
- syncRelationships is used by the UI to grab updates from the graph
12
- and update the ManyArrays.
13
-
14
- We may be able to remove this once the new relationship layer is
15
- complete.
16
- */
17
- const backburner = new Ember._Backburner(['coalesce', 'sync', 'notify']);
18
-
19
- if (DEBUG) {
20
- registerWaiter(() => {
21
- return !backburner.currentInstance && !backburner.hasTimers();
22
- });
23
- }
24
-
25
- export default backburner;
@@ -1,128 +0,0 @@
1
- import type NativeArray from '@ember/array/-private/native-array';
2
- import { assert } from '@ember/debug';
3
-
4
- import type { CollectionResourceDocument, Links, Meta, PaginationLinks } from '@ember-data/types/q/ember-data-json-api';
5
- import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
6
- import type { RecordInstance } from '@ember-data/types/q/record-instance';
7
- import type { FindOptions } from '@ember-data/types/q/store';
8
- import type { Dict } from '@ember-data/types/q/utils';
9
-
10
- import type RecordArrayManager from '../managers/record-array-manager';
11
- import SnapshotRecordArray from '../network/snapshot-record-array';
12
- import type { PromiseArray } from '../proxies/promise-proxies';
13
- import { promiseArray } from '../proxies/promise-proxies';
14
- import type Store from '../store-service';
15
- import RecordArray from './record-array';
16
-
17
- export interface AdapterPopulatedRecordArrayCreateArgs {
18
- modelName: string;
19
- store: Store;
20
- manager: RecordArrayManager;
21
- content: NativeArray<StableRecordIdentifier>;
22
- isLoaded: boolean;
23
- query?: Dict<unknown>;
24
- meta?: Meta;
25
- links?: Links | PaginationLinks | null;
26
- }
27
-
28
- /**
29
- @module @ember-data/store
30
- */
31
-
32
- /**
33
- Represents an ordered list of records whose order and membership is
34
- determined by the adapter. For example, a query sent to the adapter
35
- may trigger a search on the server, whose results would be loaded
36
- into an instance of the `AdapterPopulatedRecordArray`.
37
-
38
- This class should not be imported and instantiated by consuming applications.
39
-
40
- ---
41
-
42
- If you want to update the array and get the latest records from the
43
- adapter, you can invoke [`update()`](AdapterPopulatedRecordArray/methods/update?anchor=update):
44
-
45
- Example
46
-
47
- ```javascript
48
- // GET /users?isAdmin=true
49
- store.query('user', { isAdmin: true }).then(function(admins) {
50
-
51
- admins.get("length"); // 42
52
-
53
- // somewhere later in the app code, when new admins have been created
54
- // in the meantime
55
- //
56
- // GET /users?isAdmin=true
57
- admins.update().then(function() {
58
- admins.isUpdating; // false
59
- admins.get("length"); // 123
60
- });
61
-
62
- admins.isUpdating; // true
63
- }
64
- ```
65
-
66
- @class AdapterPopulatedRecordArray
67
- @public
68
- @extends RecordArray
69
- */
70
- export default class AdapterPopulatedRecordArray extends RecordArray {
71
- declare links: Links | PaginationLinks | null;
72
- declare meta: Dict<unknown> | null;
73
- declare query: Dict<unknown> | null;
74
-
75
- init(props?: AdapterPopulatedRecordArrayCreateArgs) {
76
- assert(`Cannot initialize AdapterPopulatedRecordArray with isUpdating`, !props || !('isUpdating' in props));
77
- super.init();
78
- this.query = this.query || null;
79
- this.links = this.links || null;
80
- this.meta = this.meta || null;
81
- }
82
-
83
- replace() {
84
- throw new Error(`The result of a server query (on ${this.modelName}) is immutable.`);
85
- }
86
-
87
- _update(): PromiseArray<RecordInstance, AdapterPopulatedRecordArray> {
88
- const { store, query } = this;
89
-
90
- // TODO save options from initial request?
91
- return promiseArray(store.query(this.modelName, query, { _recordArray: this }));
92
- }
93
-
94
- _setObjects(identifiers: StableRecordIdentifier[], payload: CollectionResourceDocument) {
95
- // TODO: initial load should not cause change events at all, only
96
- // subsequent. This requires changing the public api of adapter.query, but
97
- // hopefully we can do that soon.
98
- this.content.setObjects(identifiers);
99
-
100
- this.setProperties({
101
- isLoaded: true,
102
- isUpdating: false,
103
- // TODO this assign kills the root reference but a deep-copy would be required
104
- // for both meta and links to actually not be by-ref. We whould likely change
105
- // this to a dev-only deep-freeze.
106
- meta: Object.assign({}, payload.meta),
107
- links: Object.assign({}, payload.links),
108
- });
109
-
110
- this.manager._associateWithRecordArray(identifiers, this);
111
- }
112
-
113
- _createSnapshot(options: FindOptions) {
114
- // this is private for users, but public for ember-data internals
115
- // meta will only be present for an AdapterPopulatedRecordArray
116
- return new SnapshotRecordArray(this, this.meta, options);
117
- }
118
-
119
- /**
120
- @method _setIdentifiers
121
- @param {StableRecordIdentifier[]} identifiers
122
- @param {Object} payload normalized payload
123
- @private
124
- */
125
- _setIdentifiers(identifiers: StableRecordIdentifier[], payload: CollectionResourceDocument): void {
126
- this._setObjects(identifiers, payload);
127
- }
128
- }
@@ -1,328 +0,0 @@
1
- /**
2
- @module @ember-data/store
3
- */
4
- import type NativeArray from '@ember/array/-private/native-array';
5
- import ArrayProxy from '@ember/array/proxy';
6
- import { assert, deprecate } from '@ember/debug';
7
- import { set } from '@ember/object';
8
- import { tracked } from '@glimmer/tracking';
9
-
10
- import { Promise } from 'rsvp';
11
-
12
- import type { RecordArrayManager, Snapshot } from 'ember-data/-private';
13
-
14
- import { DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS } from '@ember-data/private-build-infra/deprecations';
15
- import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
16
- import type { RecordInstance } from '@ember-data/types/q/record-instance';
17
- import type { FindOptions } from '@ember-data/types/q/store';
18
-
19
- import SnapshotRecordArray from '../network/snapshot-record-array';
20
- import type { PromiseArray } from '../proxies/promise-proxies';
21
- import { promiseArray } from '../proxies/promise-proxies';
22
- import type Store from '../store-service';
23
-
24
- function recordForIdentifier(store: Store, identifier: StableRecordIdentifier): RecordInstance {
25
- return store._instanceCache.getRecord(identifier);
26
- }
27
-
28
- export interface RecordArrayCreateArgs {
29
- modelName: string;
30
- store: Store;
31
- manager: RecordArrayManager;
32
- content: NativeArray<StableRecordIdentifier>;
33
- isLoaded: boolean;
34
- }
35
-
36
- /**
37
- A record array is an array that contains records of a certain modelName. The record
38
- array materializes records as needed when they are retrieved for the first
39
- time. You should not create record arrays yourself. Instead, an instance of
40
- `RecordArray` or its subclasses will be returned by your application's store
41
- in response to queries.
42
-
43
- This class should not be imported and instantiated by consuming applications.
44
-
45
- @class RecordArray
46
- @public
47
- @extends Ember.ArrayProxy
48
- */
49
- export default class RecordArray extends ArrayProxy<StableRecordIdentifier, RecordInstance> {
50
- /**
51
- The array of client ids backing the record array. When a
52
- record is requested from the record array, the record
53
- for the client id at the same index is materialized, if
54
- necessary, by the store.
55
-
56
- @property content
57
- @private
58
- @type Ember.Array
59
- */
60
- declare content: NativeArray<StableRecordIdentifier>;
61
- declare _getDeprecatedEventedInfo: () => string;
62
- declare modelName: string;
63
- /**
64
- The flag to signal a `RecordArray` is finished loading data.
65
-
66
- Example
67
-
68
- ```javascript
69
- let people = store.peekAll('person');
70
- people.isLoaded; // true
71
- ```
72
-
73
- @property isLoaded
74
- @public
75
- @type Boolean
76
- */
77
- declare isLoaded: boolean;
78
- /**
79
- The store that created this record array.
80
-
81
- @property store
82
- @private
83
- @type Store
84
- */
85
- declare store: Store;
86
- declare _updatingPromise: PromiseArray<RecordInstance, RecordArray> | null;
87
- declare manager: RecordArrayManager;
88
-
89
- /**
90
- The flag to signal a `RecordArray` is currently loading data.
91
- Example
92
- ```javascript
93
- let people = store.peekAll('person');
94
- people.isUpdating; // false
95
- people.update();
96
- people.isUpdating; // true
97
- ```
98
- @property isUpdating
99
- @public
100
- @type Boolean
101
- */
102
- @tracked isUpdating: boolean = false;
103
-
104
- init(props?: RecordArrayCreateArgs) {
105
- assert(`Cannot initialize RecordArray with isUpdating`, !props || !('isUpdating' in props));
106
- assert(`Cannot initialize RecordArray with isUpdating`, !props || !('_updatingPromise' in props));
107
- super.init();
108
-
109
- // TODO can we get rid of this?
110
- this.content = this.content || null;
111
- this._updatingPromise = null;
112
- }
113
-
114
- replace() {
115
- throw new Error(
116
- `The result of a server query (for all ${this.modelName} types) is immutable. To modify contents, use toArray()`
117
- );
118
- }
119
-
120
- /**
121
- The modelClass represented by this record array.
122
-
123
- @property type
124
- @public
125
- @deprecated
126
- @type {subclass of Model}
127
- */
128
-
129
- /**
130
- Retrieves an object from the content by index.
131
-
132
- @method objectAtContent
133
- @private
134
- @param {Number} index
135
- @return {Model} record
136
- */
137
- objectAtContent(index: number): RecordInstance | undefined {
138
- let identifier = this.content.objectAt(index);
139
- return identifier ? recordForIdentifier(this.store, identifier) : undefined;
140
- }
141
-
142
- /**
143
- Used to get the latest version of all of the records in this array
144
- from the adapter.
145
-
146
- Example
147
-
148
- ```javascript
149
- let people = store.peekAll('person');
150
- people.isUpdating; // false
151
-
152
- people.update().then(function() {
153
- people.isUpdating; // false
154
- });
155
-
156
- people.isUpdating; // true
157
- ```
158
-
159
- @method update
160
- @public
161
- */
162
- update(): PromiseArray<RecordInstance, RecordArray> {
163
- if (this.isUpdating) {
164
- return this._updatingPromise!;
165
- }
166
-
167
- this.isUpdating = true;
168
-
169
- let updatingPromise = this._update();
170
- updatingPromise.finally(() => {
171
- this._updatingPromise = null;
172
- if (this.isDestroying || this.isDestroyed) {
173
- return;
174
- }
175
- this.isUpdating = false;
176
- });
177
-
178
- this._updatingPromise = updatingPromise;
179
-
180
- return updatingPromise;
181
- }
182
-
183
- /*
184
- Update this RecordArray and return a promise which resolves once the update
185
- is finished.
186
- */
187
- _update(): PromiseArray<RecordInstance, RecordArray> {
188
- return this.store.findAll(this.modelName, { reload: true });
189
- }
190
-
191
- /**
192
- Saves all of the records in the `RecordArray`.
193
-
194
- Example
195
-
196
- ```javascript
197
- let messages = store.peekAll('message');
198
- messages.forEach(function(message) {
199
- message.hasBeenSeen = true;
200
- });
201
- messages.save();
202
- ```
203
-
204
- @method save
205
- @public
206
- @return {PromiseArray} promise
207
- */
208
- save(): PromiseArray<RecordInstance, RecordArray> {
209
- let promiseLabel = `DS: RecordArray#save ${this.modelName}`;
210
- let promise = Promise.all(this.invoke('save'), promiseLabel).then(
211
- () => this,
212
- null,
213
- 'DS: RecordArray#save return RecordArray'
214
- );
215
-
216
- return promiseArray<RecordInstance, RecordArray>(promise);
217
- }
218
-
219
- /**
220
- @method _unregisterFromManager
221
- @internal
222
- */
223
- _unregisterFromManager() {
224
- this.manager.unregisterRecordArray(this);
225
- }
226
-
227
- willDestroy() {
228
- this._unregisterFromManager();
229
- this._dissociateFromOwnRecords();
230
- // TODO: we should not do work during destroy:
231
- // * when objects are destroyed, they should simply be left to do
232
- // * if logic errors do to this, that logic needs to be more careful during
233
- // teardown (ember provides isDestroying/isDestroyed) for this reason
234
- // * the exception being: if an dominator has a reference to this object,
235
- // and must be informed to release e.g. e.g. removing itself from th
236
- // recordArrayMananger
237
- // TODO we have to use set here vs dot notation because computed properties don't clear
238
- // otherwise for destroyed records and will not update their value.
239
- set(this, 'content', null as unknown as NativeArray<StableRecordIdentifier>);
240
- set(this, 'length', 0);
241
- super.willDestroy();
242
- }
243
-
244
- /**
245
- @method _createSnapshot
246
- @private
247
- */
248
- _createSnapshot(options: FindOptions) {
249
- // this is private for users, but public for ember-data internals
250
- // meta will only be present for an AdapterPopulatedRecordArray
251
- return new SnapshotRecordArray(this, null, options);
252
- }
253
-
254
- /**
255
- @method _dissociateFromOwnRecords
256
- @internal
257
- */
258
- _dissociateFromOwnRecords() {
259
- this.content.forEach((identifier) => {
260
- let recordArrays = this.manager.getRecordArraysForIdentifier(identifier);
261
-
262
- if (recordArrays) {
263
- recordArrays.delete(this);
264
- }
265
- });
266
- }
267
-
268
- /**
269
- Adds identifiers to the `RecordArray` without duplicates
270
-
271
- @method _pushIdentifiers
272
- @internal
273
- @param {StableRecordIdentifier[]} identifiers
274
- */
275
- _pushIdentifiers(identifiers: StableRecordIdentifier[]): void {
276
- this.content.pushObjects(identifiers);
277
- }
278
-
279
- /**
280
- Removes identifiers from the `RecordArray`.
281
-
282
- @method _removeIdentifiers
283
- @internal
284
- @param {StableRecordIdentifier[]} identifiers
285
- */
286
- _removeIdentifiers(identifiers: StableRecordIdentifier[]): void {
287
- // if we are unloading all there's no point in an expensive diff
288
- // and traversal.
289
- if (identifiers.length === this.content.length) {
290
- this.content.clear();
291
- } else {
292
- // TODO This is horribly innefficient, we should refactor RecordArray
293
- // to be a native class of our own.
294
- this.content.removeObjects(identifiers);
295
- }
296
- }
297
-
298
- /**
299
- @method _takeSnapshot
300
- @internal
301
- */
302
- _takeSnapshot(): Snapshot[] {
303
- return this.content.map((identifier) => this.store._instanceCache.createSnapshot(identifier));
304
- }
305
- }
306
-
307
- if (DEPRECATE_SNAPSHOT_MODEL_CLASS_ACCESS) {
308
- Object.defineProperty(RecordArray.prototype, 'type', {
309
- get() {
310
- deprecate(
311
- `Using RecordArray.type to access the ModelClass for a record is deprecated. Use store.modelFor(<modelName>) instead.`,
312
- false,
313
- {
314
- id: 'ember-data:deprecate-snapshot-model-class-access',
315
- until: '5.0',
316
- for: 'ember-data',
317
- since: { available: '4.5.0', enabled: '4.5.0' },
318
- }
319
- );
320
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
321
- if (!this.modelName) {
322
- return null;
323
- }
324
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
325
- return this.store.modelFor(this.modelName);
326
- },
327
- });
328
- }