@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.
- package/addon/-debug/index.js +34 -12
- package/addon/-private/caches/identifier-cache.ts +44 -36
- package/addon/-private/caches/instance-cache.ts +112 -124
- package/addon/-private/caches/record-data-for.ts +1 -6
- package/addon/-private/index.ts +10 -7
- package/addon/-private/legacy-model-support/shim-model-class.ts +11 -8
- package/addon/-private/managers/record-array-manager.ts +282 -326
- package/addon/-private/managers/record-data-manager.ts +143 -128
- package/addon/-private/managers/record-data-store-wrapper.ts +18 -10
- package/addon/-private/managers/record-notification-manager.ts +31 -12
- package/addon/-private/network/fetch-manager.ts +18 -3
- package/addon/-private/network/finders.js +11 -6
- package/addon/-private/network/request-cache.ts +20 -17
- package/addon/-private/network/snapshot-record-array.ts +12 -29
- package/addon/-private/proxies/promise-proxies.ts +72 -11
- package/addon/-private/record-arrays/identifier-array.ts +924 -0
- package/addon/-private/store-service.ts +203 -108
- package/addon/-private/utils/is-non-empty-string.ts +1 -1
- package/addon/-private/utils/promise-record.ts +2 -3
- package/addon/-private/utils/uuid-polyfill.ts +58 -56
- package/package.json +5 -5
- package/addon/-private/backburner.js +0 -25
- package/addon/-private/record-arrays/adapter-populated-record-array.ts +0 -128
- package/addon/-private/record-arrays/record-array.ts +0 -328
- package/addon/-private/utils/weak-cache.ts +0 -125
|
@@ -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
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
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
|
-
|
|
18
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
if (!CRYPTO.getRandomValues && !isFastBoot) {
|
|
19
|
+
throw new Error(`Unable to generate bytes for UUID`);
|
|
20
|
+
}
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
bth
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
63
|
-
|
|
63
|
+
CRYPTO.randomUUID = function uuidv4(): string {
|
|
64
|
+
let rnds = rng();
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
25
|
-
"@ember-data/private-build-infra": "4.8.0-
|
|
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-
|
|
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.
|
|
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
|
-
}
|