@warp-drive/core 5.7.0-alpha.0 → 5.7.0-alpha.2
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/declarations/reactive/-private/schema.d.ts +42 -2
- package/declarations/store/-private/caches/instance-cache.d.ts +1 -8
- package/declarations/store/-private/store-service.d.ts +17 -777
- package/declarations/store/-private.d.ts +3 -2
- package/declarations/store/-types/q/schema-service.d.ts +37 -1
- package/declarations/store/deprecated/-private.d.ts +235 -0
- package/declarations/store/deprecated/store.d.ts +788 -0
- package/declarations/types/cache.d.ts +0 -2
- package/declarations/types/schema/fields.d.ts +13 -0
- package/declarations/types.d.ts +2 -1
- package/dist/graph/-private.js +1 -1
- package/dist/{handler-C2T-IyJK.js → handler-D2jjnIA-.js} +1 -1
- package/dist/index.js +2 -2
- package/dist/reactive.js +135 -10
- package/dist/{request-state-CjLph1LP.js → request-state-CejVJgdj.js} +839 -1336
- package/dist/store/-private.js +2 -2
- package/dist/types/-private.js +1 -1
- package/package.json +3 -3
- package/declarations/store/-private/legacy-model-support/record-reference.d.ts +0 -159
- package/declarations/store/-private/legacy-model-support/shim-model-class.d.ts +0 -17
- package/declarations/store/-types/q/ds-model.d.ts +0 -21
|
@@ -1139,6 +1139,7 @@ function gate(_target, key, desc) {
|
|
|
1139
1139
|
const getter = desc.get;
|
|
1140
1140
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
1141
1141
|
const setter = desc.set;
|
|
1142
|
+
const isLocal = desc.isLocal;
|
|
1142
1143
|
desc.get = function () {
|
|
1143
1144
|
const signals = withSignalStore(this);
|
|
1144
1145
|
let signal = peekInternalSignal(signals, key);
|
|
@@ -1165,6 +1166,11 @@ function gate(_target, key, desc) {
|
|
|
1165
1166
|
setter.call(this, v);
|
|
1166
1167
|
// when a gate is set, we do not notify the signal
|
|
1167
1168
|
// as its update is controlled externally.
|
|
1169
|
+
// unless it specifically sets itself to be locally managed
|
|
1170
|
+
if (isLocal) {
|
|
1171
|
+
signal.isStale = true;
|
|
1172
|
+
notifyInternalSignal(signal);
|
|
1173
|
+
}
|
|
1168
1174
|
};
|
|
1169
1175
|
}
|
|
1170
1176
|
return desc;
|
|
@@ -1557,185 +1563,6 @@ function _log(scope, prefix, subScop1, subScop2, subScop3, subScop4) {
|
|
|
1557
1563
|
}
|
|
1558
1564
|
return [];
|
|
1559
1565
|
}
|
|
1560
|
-
|
|
1561
|
-
/**
|
|
1562
|
-
A `RecordReference` is a low-level API that allows users and
|
|
1563
|
-
addon authors to perform meta-operations on a record.
|
|
1564
|
-
|
|
1565
|
-
@hideconstructor
|
|
1566
|
-
@public
|
|
1567
|
-
*/
|
|
1568
|
-
class RecordReference {
|
|
1569
|
-
// unsubscribe token given to us by the notification manager
|
|
1570
|
-
|
|
1571
|
-
constructor(store, identifier) {
|
|
1572
|
-
this.store = store;
|
|
1573
|
-
this.___identifier = identifier;
|
|
1574
|
-
this.___token = store.notifications.subscribe(identifier, (_, bucket, notifiedKey) => {
|
|
1575
|
-
if (bucket === 'identity' || bucket === 'attributes' && notifiedKey === 'id') {
|
|
1576
|
-
this._ref++;
|
|
1577
|
-
}
|
|
1578
|
-
});
|
|
1579
|
-
}
|
|
1580
|
-
|
|
1581
|
-
/** @internal */
|
|
1582
|
-
destroy() {
|
|
1583
|
-
this.store.notifications.unsubscribe(this.___token);
|
|
1584
|
-
}
|
|
1585
|
-
get type() {
|
|
1586
|
-
return this.identifier().type;
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
/**
|
|
1590
|
-
The `id` of the record that this reference refers to.
|
|
1591
|
-
Together, the `type` and `id` properties form a composite key for
|
|
1592
|
-
the identity map.
|
|
1593
|
-
Example
|
|
1594
|
-
```javascript
|
|
1595
|
-
let userRef = store.getReference('user', 1);
|
|
1596
|
-
userRef.id(); // '1'
|
|
1597
|
-
```
|
|
1598
|
-
@public
|
|
1599
|
-
*/
|
|
1600
|
-
id() {
|
|
1601
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
1602
|
-
this._ref; // consume the tracked prop
|
|
1603
|
-
return this.___identifier.id;
|
|
1604
|
-
}
|
|
1605
|
-
|
|
1606
|
-
/**
|
|
1607
|
-
The `identifier` of the record that this reference refers to.
|
|
1608
|
-
Together, the `type` and `id` properties form a composite key for
|
|
1609
|
-
the identity map.
|
|
1610
|
-
Example
|
|
1611
|
-
```javascript
|
|
1612
|
-
let userRef = store.getReference('user', 1);
|
|
1613
|
-
userRef.identifier(); // '1'
|
|
1614
|
-
```
|
|
1615
|
-
@public
|
|
1616
|
-
*/
|
|
1617
|
-
identifier() {
|
|
1618
|
-
return this.___identifier;
|
|
1619
|
-
}
|
|
1620
|
-
|
|
1621
|
-
/**
|
|
1622
|
-
How the reference will be looked up when it is loaded. Currently
|
|
1623
|
-
this always returns `identity` to signify that a record will be
|
|
1624
|
-
loaded by its `type` and `id`.
|
|
1625
|
-
Example
|
|
1626
|
-
```javascript
|
|
1627
|
-
const userRef = store.getReference('user', 1);
|
|
1628
|
-
userRef.remoteType(); // 'identity'
|
|
1629
|
-
```
|
|
1630
|
-
@public
|
|
1631
|
-
*/
|
|
1632
|
-
remoteType() {
|
|
1633
|
-
return 'identity';
|
|
1634
|
-
}
|
|
1635
|
-
|
|
1636
|
-
/**
|
|
1637
|
-
This API allows you to provide a reference with new data. The
|
|
1638
|
-
simplest usage of this API is similar to `store.push`: you provide a
|
|
1639
|
-
normalized hash of data and the object represented by the reference
|
|
1640
|
-
will update.
|
|
1641
|
-
If you pass a promise to `push`, Ember Data will not ask the adapter
|
|
1642
|
-
for the data if another attempt to fetch it is made in the
|
|
1643
|
-
interim. When the promise resolves, the underlying object is updated
|
|
1644
|
-
with the new data, and the promise returned by *this function* is resolved
|
|
1645
|
-
with that object.
|
|
1646
|
-
For example, `recordReference.push(promise)` will be resolved with a
|
|
1647
|
-
record.
|
|
1648
|
-
Example
|
|
1649
|
-
```javascript
|
|
1650
|
-
let userRef = store.getReference('user', 1);
|
|
1651
|
-
// provide data for reference
|
|
1652
|
-
userRef.push({
|
|
1653
|
-
data: {
|
|
1654
|
-
id: "1",
|
|
1655
|
-
type: "user",
|
|
1656
|
-
attributes: {
|
|
1657
|
-
username: "@user"
|
|
1658
|
-
}
|
|
1659
|
-
}
|
|
1660
|
-
}).then(function(user) {
|
|
1661
|
-
userRef.value() === user;
|
|
1662
|
-
});
|
|
1663
|
-
```
|
|
1664
|
-
@public
|
|
1665
|
-
@param objectOrPromise a JSON:API ResourceDocument or a promise resolving to one
|
|
1666
|
-
@return a promise for the value (record or relationship)
|
|
1667
|
-
*/
|
|
1668
|
-
push(objectOrPromise) {
|
|
1669
|
-
// TODO @deprecate pushing unresolved payloads
|
|
1670
|
-
return Promise.resolve(objectOrPromise).then(data => {
|
|
1671
|
-
return this.store.push(data);
|
|
1672
|
-
});
|
|
1673
|
-
}
|
|
1674
|
-
|
|
1675
|
-
/**
|
|
1676
|
-
If the entity referred to by the reference is already loaded, it is
|
|
1677
|
-
present as `reference.value`. Otherwise the value returned by this function
|
|
1678
|
-
is `null`.
|
|
1679
|
-
Example
|
|
1680
|
-
```javascript
|
|
1681
|
-
let userRef = store.getReference('user', 1);
|
|
1682
|
-
userRef.value(); // user
|
|
1683
|
-
```
|
|
1684
|
-
@public
|
|
1685
|
-
*/
|
|
1686
|
-
value() {
|
|
1687
|
-
return this.store.peekRecord(this.___identifier);
|
|
1688
|
-
}
|
|
1689
|
-
|
|
1690
|
-
/**
|
|
1691
|
-
Triggers a fetch for the backing entity based on its `remoteType`
|
|
1692
|
-
(see `remoteType` definitions per reference type).
|
|
1693
|
-
Example
|
|
1694
|
-
```javascript
|
|
1695
|
-
let userRef = store.getReference('user', 1);
|
|
1696
|
-
// load user (via store.find)
|
|
1697
|
-
userRef.load().then(...)
|
|
1698
|
-
```
|
|
1699
|
-
@public
|
|
1700
|
-
*/
|
|
1701
|
-
load() {
|
|
1702
|
-
const id = this.id();
|
|
1703
|
-
if (id !== null) {
|
|
1704
|
-
return this.store.findRecord(this.type, id);
|
|
1705
|
-
}
|
|
1706
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1707
|
-
{
|
|
1708
|
-
throw new Error(`Unable to fetch record of type ${this.type} without an id`);
|
|
1709
|
-
}
|
|
1710
|
-
})() : {};
|
|
1711
|
-
}
|
|
1712
|
-
|
|
1713
|
-
/**
|
|
1714
|
-
Reloads the record if it is already loaded. If the record is not
|
|
1715
|
-
loaded it will load the record via `store.findRecord`
|
|
1716
|
-
Example
|
|
1717
|
-
```javascript
|
|
1718
|
-
let userRef = store.getReference('user', 1);
|
|
1719
|
-
// or trigger a reload
|
|
1720
|
-
userRef.reload().then(...)
|
|
1721
|
-
```
|
|
1722
|
-
@public
|
|
1723
|
-
*/
|
|
1724
|
-
reload() {
|
|
1725
|
-
const id = this.id();
|
|
1726
|
-
if (id !== null) {
|
|
1727
|
-
return this.store.findRecord(this.type, id, {
|
|
1728
|
-
reload: true
|
|
1729
|
-
});
|
|
1730
|
-
}
|
|
1731
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1732
|
-
{
|
|
1733
|
-
throw new Error(`Unable to fetch record of type ${this.type} without an id`);
|
|
1734
|
-
}
|
|
1735
|
-
})() : {};
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
defineSignal(RecordReference.prototype, '_ref');
|
|
1739
1566
|
class CacheCapabilitiesManager {
|
|
1740
1567
|
constructor(_store) {
|
|
1741
1568
|
this._store = _store;
|
|
@@ -1921,7 +1748,6 @@ class InstanceCache {
|
|
|
1921
1748
|
this.store = store;
|
|
1922
1749
|
this.__instances = {
|
|
1923
1750
|
record: new Map(),
|
|
1924
|
-
reference: new WeakMap(),
|
|
1925
1751
|
document: new Map()
|
|
1926
1752
|
};
|
|
1927
1753
|
this._storeWrapper = new CacheCapabilitiesManager(this.store);
|
|
@@ -2015,15 +1841,6 @@ class InstanceCache {
|
|
|
2015
1841
|
}
|
|
2016
1842
|
return record;
|
|
2017
1843
|
}
|
|
2018
|
-
getReference(identifier) {
|
|
2019
|
-
const cache = this.__instances.reference;
|
|
2020
|
-
let reference = cache.get(identifier);
|
|
2021
|
-
if (!reference) {
|
|
2022
|
-
reference = new RecordReference(this.store, identifier);
|
|
2023
|
-
cache.set(identifier, reference);
|
|
2024
|
-
}
|
|
2025
|
-
return reference;
|
|
2026
|
-
}
|
|
2027
1844
|
recordIsLoaded(identifier, filterDeleted = false) {
|
|
2028
1845
|
const cache = this.cache;
|
|
2029
1846
|
if (!cache) {
|
|
@@ -2201,208 +2018,39 @@ class InstanceCache {
|
|
|
2201
2018
|
this.store.notifications.notify(identifier, 'identity');
|
|
2202
2019
|
}
|
|
2203
2020
|
}
|
|
2204
|
-
function
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
const cache = instanceCache.cache;
|
|
2209
|
-
return !cache || _resourceIsFullDeleted(identifier, cache);
|
|
2021
|
+
function _clearCaches() {
|
|
2022
|
+
RecordCache.clear();
|
|
2023
|
+
StoreMap.clear();
|
|
2024
|
+
CacheForIdentifierCache.clear();
|
|
2210
2025
|
}
|
|
2211
2026
|
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2027
|
+
/**
|
|
2028
|
+
* The CacheManager wraps a Cache enforcing that only
|
|
2029
|
+
* the public API surface area is exposed.
|
|
2030
|
+
*
|
|
2031
|
+
* Hence, it is the value of `Store.cache`, wrapping
|
|
2032
|
+
* the cache instance returned by `Store.createCache`.
|
|
2033
|
+
*
|
|
2034
|
+
* It handles translating between cache versions when
|
|
2035
|
+
* necessary, for instance when a Store is configured
|
|
2036
|
+
* to use both a v1 and a v2 cache depending on some
|
|
2037
|
+
* heuristic.
|
|
2038
|
+
*
|
|
2039
|
+
* Starting with the v2 spec, the cache is designed such
|
|
2040
|
+
* that it must be implemented as a singleton.
|
|
2041
|
+
*
|
|
2042
|
+
* @class CacheManager
|
|
2043
|
+
* @public
|
|
2044
|
+
*/
|
|
2045
|
+
class CacheManager {
|
|
2046
|
+
version = '2';
|
|
2047
|
+
#cache;
|
|
2048
|
+
constructor(cache) {
|
|
2049
|
+
this.#cache = cache;
|
|
2050
|
+
}
|
|
2219
2051
|
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
*/
|
|
2223
|
-
|
|
2224
|
-
function preloadData(store, identifier, preload) {
|
|
2225
|
-
const jsonPayload = {};
|
|
2226
|
-
//TODO(Igor) consider the polymorphic case
|
|
2227
|
-
const schemas = store.schema;
|
|
2228
|
-
const fields = schemas.fields(identifier);
|
|
2229
|
-
Object.keys(preload).forEach(key => {
|
|
2230
|
-
const preloadValue = preload[key];
|
|
2231
|
-
const field = fields.get(key);
|
|
2232
|
-
if (field && (field.kind === 'hasMany' || field.kind === 'belongsTo')) {
|
|
2233
|
-
if (!jsonPayload.relationships) {
|
|
2234
|
-
jsonPayload.relationships = {};
|
|
2235
|
-
}
|
|
2236
|
-
jsonPayload.relationships[key] = preloadRelationship(field, preloadValue);
|
|
2237
|
-
} else {
|
|
2238
|
-
if (!jsonPayload.attributes) {
|
|
2239
|
-
jsonPayload.attributes = {};
|
|
2240
|
-
}
|
|
2241
|
-
jsonPayload.attributes[key] = preloadValue;
|
|
2242
|
-
}
|
|
2243
|
-
});
|
|
2244
|
-
const cache = store.cache;
|
|
2245
|
-
const hasRecord = Boolean(store._instanceCache.peek(identifier));
|
|
2246
|
-
cache.upsert(identifier, jsonPayload, hasRecord);
|
|
2247
|
-
}
|
|
2248
|
-
function preloadRelationship(schema, preloadValue) {
|
|
2249
|
-
const relatedType = schema.type;
|
|
2250
|
-
if (schema.kind === 'hasMany') {
|
|
2251
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2252
|
-
if (!test) {
|
|
2253
|
-
throw new Error('You need to pass in an array to set a hasMany property on a record');
|
|
2254
|
-
}
|
|
2255
|
-
})(Array.isArray(preloadValue)) : {};
|
|
2256
|
-
return {
|
|
2257
|
-
data: preloadValue.map(value => _convertPreloadRelationshipToJSON(value, relatedType))
|
|
2258
|
-
};
|
|
2259
|
-
}
|
|
2260
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
2261
|
-
if (!test) {
|
|
2262
|
-
throw new Error('You should not pass in an array to set a belongsTo property on a record');
|
|
2263
|
-
}
|
|
2264
|
-
})(!Array.isArray(preloadValue)) : {};
|
|
2265
|
-
return {
|
|
2266
|
-
data: preloadValue ? _convertPreloadRelationshipToJSON(preloadValue, relatedType) : null
|
|
2267
|
-
};
|
|
2268
|
-
}
|
|
2269
|
-
|
|
2270
|
-
/*
|
|
2271
|
-
findRecord('user', '1', { preload: { friends: ['1'] }});
|
|
2272
|
-
findRecord('user', '1', { preload: { friends: [record] }});
|
|
2273
|
-
*/
|
|
2274
|
-
function _convertPreloadRelationshipToJSON(value, type) {
|
|
2275
|
-
if (typeof value === 'string' || typeof value === 'number') {
|
|
2276
|
-
return {
|
|
2277
|
-
type,
|
|
2278
|
-
id: ensureStringId(value)
|
|
2279
|
-
};
|
|
2280
|
-
}
|
|
2281
|
-
// TODO if not a record instance assert it's an identifier
|
|
2282
|
-
// and allow identifiers to be used
|
|
2283
|
-
return recordIdentifierFor(value);
|
|
2284
|
-
}
|
|
2285
|
-
function _clearCaches() {
|
|
2286
|
-
RecordCache.clear();
|
|
2287
|
-
StoreMap.clear();
|
|
2288
|
-
CacheForIdentifierCache.clear();
|
|
2289
|
-
}
|
|
2290
|
-
|
|
2291
|
-
// if modelFor turns out to be a bottleneck we should replace with a Map
|
|
2292
|
-
// and clear it during store teardown.
|
|
2293
|
-
const AvailableShims = getOrSetGlobal('AvailableShims', new WeakMap());
|
|
2294
|
-
function getShimClass(store, modelName) {
|
|
2295
|
-
let shims = AvailableShims.get(store);
|
|
2296
|
-
if (!shims) {
|
|
2297
|
-
shims = Object.create(null);
|
|
2298
|
-
AvailableShims.set(store, shims);
|
|
2299
|
-
}
|
|
2300
|
-
let shim = shims[modelName];
|
|
2301
|
-
if (shim === undefined) {
|
|
2302
|
-
shim = shims[modelName] = new ShimModelClass(store, modelName);
|
|
2303
|
-
}
|
|
2304
|
-
return shim;
|
|
2305
|
-
}
|
|
2306
|
-
|
|
2307
|
-
// Mimics the static apis of @ember-data/model
|
|
2308
|
-
class ShimModelClass {
|
|
2309
|
-
constructor(store, modelName) {
|
|
2310
|
-
this.__store = store;
|
|
2311
|
-
this.modelName = modelName;
|
|
2312
|
-
}
|
|
2313
|
-
get fields() {
|
|
2314
|
-
const fields = new Map();
|
|
2315
|
-
const fieldSchemas = this.__store.schema.fields({
|
|
2316
|
-
type: this.modelName
|
|
2317
|
-
});
|
|
2318
|
-
fieldSchemas.forEach((schema, key) => {
|
|
2319
|
-
if (schema.kind === 'attribute' || schema.kind === 'belongsTo' || schema.kind === 'hasMany') {
|
|
2320
|
-
fields.set(key, schema.kind);
|
|
2321
|
-
}
|
|
2322
|
-
});
|
|
2323
|
-
return fields;
|
|
2324
|
-
}
|
|
2325
|
-
get attributes() {
|
|
2326
|
-
const attrs = new Map();
|
|
2327
|
-
const fields = this.__store.schema.fields({
|
|
2328
|
-
type: this.modelName
|
|
2329
|
-
});
|
|
2330
|
-
fields.forEach((schema, key) => {
|
|
2331
|
-
if (schema.kind === 'attribute') {
|
|
2332
|
-
attrs.set(key, schema);
|
|
2333
|
-
}
|
|
2334
|
-
});
|
|
2335
|
-
return attrs;
|
|
2336
|
-
}
|
|
2337
|
-
get relationshipsByName() {
|
|
2338
|
-
const rels = new Map();
|
|
2339
|
-
const fields = this.__store.schema.fields({
|
|
2340
|
-
type: this.modelName
|
|
2341
|
-
});
|
|
2342
|
-
fields.forEach((schema, key) => {
|
|
2343
|
-
if (schema.kind === 'belongsTo' || schema.kind === 'hasMany') {
|
|
2344
|
-
rels.set(key, schema);
|
|
2345
|
-
}
|
|
2346
|
-
});
|
|
2347
|
-
return rels;
|
|
2348
|
-
}
|
|
2349
|
-
eachAttribute(callback, binding) {
|
|
2350
|
-
this.__store.schema.fields({
|
|
2351
|
-
type: this.modelName
|
|
2352
|
-
}).forEach((schema, key) => {
|
|
2353
|
-
if (schema.kind === 'attribute') {
|
|
2354
|
-
callback.call(binding, key, schema);
|
|
2355
|
-
}
|
|
2356
|
-
});
|
|
2357
|
-
}
|
|
2358
|
-
eachRelationship(callback, binding) {
|
|
2359
|
-
this.__store.schema.fields({
|
|
2360
|
-
type: this.modelName
|
|
2361
|
-
}).forEach((schema, key) => {
|
|
2362
|
-
if (schema.kind === 'belongsTo' || schema.kind === 'hasMany') {
|
|
2363
|
-
callback.call(binding, key, schema);
|
|
2364
|
-
}
|
|
2365
|
-
});
|
|
2366
|
-
}
|
|
2367
|
-
eachTransformedAttribute(callback, binding) {
|
|
2368
|
-
this.__store.schema.fields({
|
|
2369
|
-
type: this.modelName
|
|
2370
|
-
}).forEach((schema, key) => {
|
|
2371
|
-
if (schema.kind === 'attribute') {
|
|
2372
|
-
const type = schema.type;
|
|
2373
|
-
if (type) callback.call(binding, key, type);
|
|
2374
|
-
}
|
|
2375
|
-
});
|
|
2376
|
-
}
|
|
2377
|
-
}
|
|
2378
|
-
|
|
2379
|
-
/**
|
|
2380
|
-
* The CacheManager wraps a Cache enforcing that only
|
|
2381
|
-
* the public API surface area is exposed.
|
|
2382
|
-
*
|
|
2383
|
-
* Hence, it is the value of `Store.cache`, wrapping
|
|
2384
|
-
* the cache instance returned by `Store.createCache`.
|
|
2385
|
-
*
|
|
2386
|
-
* It handles translating between cache versions when
|
|
2387
|
-
* necessary, for instance when a Store is configured
|
|
2388
|
-
* to use both a v1 and a v2 cache depending on some
|
|
2389
|
-
* heuristic.
|
|
2390
|
-
*
|
|
2391
|
-
* Starting with the v2 spec, the cache is designed such
|
|
2392
|
-
* that it must be implemented as a singleton.
|
|
2393
|
-
*
|
|
2394
|
-
* @class CacheManager
|
|
2395
|
-
* @public
|
|
2396
|
-
*/
|
|
2397
|
-
class CacheManager {
|
|
2398
|
-
version = '2';
|
|
2399
|
-
#cache;
|
|
2400
|
-
constructor(cache) {
|
|
2401
|
-
this.#cache = cache;
|
|
2402
|
-
}
|
|
2403
|
-
|
|
2404
|
-
// Cache Management
|
|
2405
|
-
// ================
|
|
2052
|
+
// Cache Management
|
|
2053
|
+
// ================
|
|
2406
2054
|
|
|
2407
2055
|
/**
|
|
2408
2056
|
* Cache the response to a request
|
|
@@ -4426,57 +4074,6 @@ class RequestStateService {
|
|
|
4426
4074
|
return null;
|
|
4427
4075
|
}
|
|
4428
4076
|
}
|
|
4429
|
-
function isNonEmptyString(str) {
|
|
4430
|
-
return Boolean(str && typeof str === 'string');
|
|
4431
|
-
}
|
|
4432
|
-
function constructResource(type, id, lid) {
|
|
4433
|
-
if (typeof type === 'object' && type !== null) {
|
|
4434
|
-
const resource = type;
|
|
4435
|
-
if (isStableIdentifier(resource)) {
|
|
4436
|
-
return resource;
|
|
4437
|
-
}
|
|
4438
|
-
if ('id' in resource) {
|
|
4439
|
-
resource.id = coerceId(resource.id);
|
|
4440
|
-
}
|
|
4441
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4442
|
-
if (!test) {
|
|
4443
|
-
throw new Error('Expected either id or lid to be a valid string');
|
|
4444
|
-
}
|
|
4445
|
-
})('id' in resource && isNonEmptyString(resource.id) || isNonEmptyString(resource.lid)) : {};
|
|
4446
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4447
|
-
if (!test) {
|
|
4448
|
-
throw new Error('if id is present, the type must be a string');
|
|
4449
|
-
}
|
|
4450
|
-
})(!('id' in resource) || typeof resource.type === 'string') : {};
|
|
4451
|
-
return resource;
|
|
4452
|
-
} else {
|
|
4453
|
-
const trueId = coerceId(id);
|
|
4454
|
-
if (!isNonEmptyString(trueId)) {
|
|
4455
|
-
if (isNonEmptyString(lid)) {
|
|
4456
|
-
return {
|
|
4457
|
-
lid
|
|
4458
|
-
};
|
|
4459
|
-
}
|
|
4460
|
-
throw new Error('Expected either id or lid to be a valid string');
|
|
4461
|
-
}
|
|
4462
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
4463
|
-
if (!test) {
|
|
4464
|
-
throw new Error('type must be a string');
|
|
4465
|
-
}
|
|
4466
|
-
})(typeof type === 'string') : {};
|
|
4467
|
-
if (isNonEmptyString(lid)) {
|
|
4468
|
-
return {
|
|
4469
|
-
type,
|
|
4470
|
-
id: trueId,
|
|
4471
|
-
lid
|
|
4472
|
-
};
|
|
4473
|
-
}
|
|
4474
|
-
return {
|
|
4475
|
-
type,
|
|
4476
|
-
id: trueId
|
|
4477
|
-
};
|
|
4478
|
-
}
|
|
4479
|
-
}
|
|
4480
4077
|
|
|
4481
4078
|
// this import location is deprecated but breaks in 4.8 and older
|
|
4482
4079
|
// @ts-expect-error adding to globalThis
|
|
@@ -5023,46 +4620,6 @@ class Store extends BaseClass {
|
|
|
5023
4620
|
return future;
|
|
5024
4621
|
}
|
|
5025
4622
|
|
|
5026
|
-
/**
|
|
5027
|
-
Returns the schema for a particular resource type (modelName).
|
|
5028
|
-
When used with Model from @ember-data/model the return is the model class,
|
|
5029
|
-
but this is not guaranteed.
|
|
5030
|
-
If looking to query attribute or relationship information it is
|
|
5031
|
-
recommended to use `getSchemaDefinitionService` instead. This method
|
|
5032
|
-
should be considered legacy and exists primarily to continue to support
|
|
5033
|
-
Adapter/Serializer APIs which expect it's return value in their method
|
|
5034
|
-
signatures.
|
|
5035
|
-
The class of a model might be useful if you want to get a list of all the
|
|
5036
|
-
relationship names of the model, see
|
|
5037
|
-
[`relationshipNames`](/ember-data/release/classes/Model?anchor=relationshipNames)
|
|
5038
|
-
for example.
|
|
5039
|
-
@public
|
|
5040
|
-
@deprecated
|
|
5041
|
-
@param {String} type
|
|
5042
|
-
@return {ModelSchema}
|
|
5043
|
-
*/
|
|
5044
|
-
|
|
5045
|
-
modelFor(type) {
|
|
5046
|
-
// FIXME add deprecation and deprecation stripping
|
|
5047
|
-
// FIXME/TODO update RFC to remove this method
|
|
5048
|
-
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
5049
|
-
assertDestroyedStoreOnly(this, 'modelFor');
|
|
5050
|
-
}
|
|
5051
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5052
|
-
if (!test) {
|
|
5053
|
-
throw new Error(`You need to pass <type> to the store's modelFor method`);
|
|
5054
|
-
}
|
|
5055
|
-
})(typeof type === 'string' && type.length) : {};
|
|
5056
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5057
|
-
if (!test) {
|
|
5058
|
-
throw new Error(`No model was found for '${type}' and no schema handles the type`);
|
|
5059
|
-
}
|
|
5060
|
-
})(this.schema.hasResource({
|
|
5061
|
-
type
|
|
5062
|
-
})) : {};
|
|
5063
|
-
return getShimClass(this, type);
|
|
5064
|
-
}
|
|
5065
|
-
|
|
5066
4623
|
/**
|
|
5067
4624
|
Create a new record in the current store. The properties passed
|
|
5068
4625
|
to this method are set on the newly created record.
|
|
@@ -5203,403 +4760,27 @@ class Store extends BaseClass {
|
|
|
5203
4760
|
}
|
|
5204
4761
|
|
|
5205
4762
|
/**
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
4763
|
+
Get a record by a given type and ID without triggering a fetch.
|
|
4764
|
+
This method will synchronously return the record if it is available in the store,
|
|
4765
|
+
otherwise it will return `null`. A record is available if it has been fetched earlier, or
|
|
4766
|
+
pushed manually into the store.
|
|
4767
|
+
See [findRecord](../methods/findRecord?anchor=findRecord) if you would like to request this record from the backend.
|
|
4768
|
+
_Note: This is a synchronous method and does not return a promise._
|
|
5211
4769
|
**Example 1**
|
|
5212
|
-
```js
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
return this.store.findRecord('post', post_id);
|
|
5216
|
-
}
|
|
5217
|
-
}
|
|
4770
|
+
```js
|
|
4771
|
+
let post = store.peekRecord('post', '1');
|
|
4772
|
+
post.id; // '1'
|
|
5218
4773
|
```
|
|
5219
|
-
|
|
5220
|
-
`findRecord` can be called with a single identifier argument instead of the combination
|
|
4774
|
+
`peekRecord` can be called with a single identifier argument instead of the combination
|
|
5221
4775
|
of `type` (modelName) and `id` as separate arguments. You may recognize this combo as
|
|
5222
4776
|
the typical pairing from [JSON:API](https://jsonapi.org/format/#document-resource-object-identification)
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
}
|
|
5228
|
-
}
|
|
4777
|
+
**Example 2**
|
|
4778
|
+
```js
|
|
4779
|
+
let post = store.peekRecord({ type: 'post', id });
|
|
4780
|
+
post.id; // '1'
|
|
5229
4781
|
```
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
has already been assigned an id, you can find the record again using just the lid.
|
|
5233
|
-
```js [app/routes/post.js]
|
|
5234
|
-
store.findRecord({ lid });
|
|
5235
|
-
```
|
|
5236
|
-
If the record is not yet available, the store will ask the adapter's `findRecord`
|
|
5237
|
-
method to retrieve and supply the necessary data. If the record is already present
|
|
5238
|
-
in the store, it depends on the reload behavior _when_ the returned promise
|
|
5239
|
-
resolves.
|
|
5240
|
-
### Preloading
|
|
5241
|
-
You can optionally `preload` specific attributes and relationships that you know of
|
|
5242
|
-
by passing them via the passed `options`.
|
|
5243
|
-
For example, if your Ember route looks like `/posts/1/comments/2` and your API route
|
|
5244
|
-
for the comment also looks like `/posts/1/comments/2` if you want to fetch the comment
|
|
5245
|
-
without also fetching the post you can pass in the post to the `findRecord` call:
|
|
5246
|
-
```js [app/routes/post-comments.js]
|
|
5247
|
-
export default class PostRoute extends Route {
|
|
5248
|
-
model({ post_id, comment_id: id }) {
|
|
5249
|
-
return this.store.findRecord({ type: 'comment', id, { preload: { post: post_id }} });
|
|
5250
|
-
}
|
|
5251
|
-
}
|
|
5252
|
-
```
|
|
5253
|
-
In your adapter you can then access this id without triggering a network request via the
|
|
5254
|
-
snapshot:
|
|
5255
|
-
```js [app/adapters/application.js]
|
|
5256
|
-
export default class Adapter {
|
|
5257
|
-
findRecord(store, schema, id, snapshot) {
|
|
5258
|
-
let type = schema.modelName;
|
|
5259
|
-
if (type === 'comment')
|
|
5260
|
-
let postId = snapshot.belongsTo('post', { id: true });
|
|
5261
|
-
return fetch(`./posts/${postId}/comments/${id}`)
|
|
5262
|
-
.then(response => response.json())
|
|
5263
|
-
}
|
|
5264
|
-
}
|
|
5265
|
-
static create() {
|
|
5266
|
-
return new this();
|
|
5267
|
-
}
|
|
5268
|
-
}
|
|
5269
|
-
```
|
|
5270
|
-
This could also be achieved by supplying the post id to the adapter via the adapterOptions
|
|
5271
|
-
property on the options hash.
|
|
5272
|
-
```js [app/routes/post-comments.js]
|
|
5273
|
-
export default class PostRoute extends Route {
|
|
5274
|
-
model({ post_id, comment_id: id }) {
|
|
5275
|
-
return this.store.findRecord({ type: 'comment', id, { adapterOptions: { post: post_id }} });
|
|
5276
|
-
}
|
|
5277
|
-
}
|
|
5278
|
-
```
|
|
5279
|
-
```js [app/adapters/application.js]
|
|
5280
|
-
export default class Adapter {
|
|
5281
|
-
findRecord(store, schema, id, snapshot) {
|
|
5282
|
-
let type = schema.modelName;
|
|
5283
|
-
if (type === 'comment')
|
|
5284
|
-
let postId = snapshot.adapterOptions.post;
|
|
5285
|
-
return fetch(`./posts/${postId}/comments/${id}`)
|
|
5286
|
-
.then(response => response.json())
|
|
5287
|
-
}
|
|
5288
|
-
}
|
|
5289
|
-
static create() {
|
|
5290
|
-
return new this();
|
|
5291
|
-
}
|
|
5292
|
-
}
|
|
5293
|
-
```
|
|
5294
|
-
If you have access to the post model you can also pass the model itself to preload:
|
|
5295
|
-
```javascript
|
|
5296
|
-
let post = await store.findRecord('post', '1');
|
|
5297
|
-
let comment = await store.findRecord('comment', '2', { post: myPostModel });
|
|
5298
|
-
```
|
|
5299
|
-
### Reloading
|
|
5300
|
-
The reload behavior is configured either via the passed `options` hash or
|
|
5301
|
-
the result of the adapter's `shouldReloadRecord`.
|
|
5302
|
-
If `{ reload: true }` is passed or `adapter.shouldReloadRecord` evaluates
|
|
5303
|
-
to `true`, then the returned promise resolves once the adapter returns
|
|
5304
|
-
data, regardless if the requested record is already in the store:
|
|
5305
|
-
```js
|
|
5306
|
-
store.push({
|
|
5307
|
-
data: {
|
|
5308
|
-
id: 1,
|
|
5309
|
-
type: 'post',
|
|
5310
|
-
revision: 1
|
|
5311
|
-
}
|
|
5312
|
-
});
|
|
5313
|
-
// adapter#findRecord resolves with
|
|
5314
|
-
// [
|
|
5315
|
-
// {
|
|
5316
|
-
// id: 1,
|
|
5317
|
-
// type: 'post',
|
|
5318
|
-
// revision: 2
|
|
5319
|
-
// }
|
|
5320
|
-
// ]
|
|
5321
|
-
store.findRecord('post', '1', { reload: true }).then(function(post) {
|
|
5322
|
-
post.revision; // 2
|
|
5323
|
-
});
|
|
5324
|
-
```
|
|
5325
|
-
If no reload is indicated via the above mentioned ways, then the promise
|
|
5326
|
-
immediately resolves with the cached version in the store.
|
|
5327
|
-
### Background Reloading
|
|
5328
|
-
Optionally, if `adapter.shouldBackgroundReloadRecord` evaluates to `true`,
|
|
5329
|
-
then a background reload is started, which updates the records' data, once
|
|
5330
|
-
it is available:
|
|
5331
|
-
```js
|
|
5332
|
-
// app/adapters/post.js
|
|
5333
|
-
import ApplicationAdapter from "./application";
|
|
5334
|
-
export default class PostAdapter extends ApplicationAdapter {
|
|
5335
|
-
shouldReloadRecord(store, snapshot) {
|
|
5336
|
-
return false;
|
|
5337
|
-
},
|
|
5338
|
-
shouldBackgroundReloadRecord(store, snapshot) {
|
|
5339
|
-
return true;
|
|
5340
|
-
}
|
|
5341
|
-
});
|
|
5342
|
-
// ...
|
|
5343
|
-
store.push({
|
|
5344
|
-
data: {
|
|
5345
|
-
id: 1,
|
|
5346
|
-
type: 'post',
|
|
5347
|
-
revision: 1
|
|
5348
|
-
}
|
|
5349
|
-
});
|
|
5350
|
-
let blogPost = store.findRecord('post', '1').then(function(post) {
|
|
5351
|
-
post.revision; // 1
|
|
5352
|
-
});
|
|
5353
|
-
// later, once adapter#findRecord resolved with
|
|
5354
|
-
// [
|
|
5355
|
-
// {
|
|
5356
|
-
// id: 1,
|
|
5357
|
-
// type: 'post',
|
|
5358
|
-
// revision: 2
|
|
5359
|
-
// }
|
|
5360
|
-
// ]
|
|
5361
|
-
blogPost.revision; // 2
|
|
5362
|
-
```
|
|
5363
|
-
If you would like to force or prevent background reloading, you can set a
|
|
5364
|
-
boolean value for `backgroundReload` in the options object for
|
|
5365
|
-
`findRecord`.
|
|
5366
|
-
```js [app/routes/post/edit.js]
|
|
5367
|
-
export default class PostEditRoute extends Route {
|
|
5368
|
-
model(params) {
|
|
5369
|
-
return this.store.findRecord('post', params.post_id, { backgroundReload: false });
|
|
5370
|
-
}
|
|
5371
|
-
}
|
|
5372
|
-
```
|
|
5373
|
-
If you pass an object on the `adapterOptions` property of the options
|
|
5374
|
-
argument it will be passed to your adapter via the snapshot
|
|
5375
|
-
```js [app/routes/post/edit.js]
|
|
5376
|
-
export default class PostEditRoute extends Route {
|
|
5377
|
-
model(params) {
|
|
5378
|
-
return this.store.findRecord('post', params.post_id, {
|
|
5379
|
-
adapterOptions: { subscribe: false }
|
|
5380
|
-
});
|
|
5381
|
-
}
|
|
5382
|
-
}
|
|
5383
|
-
```
|
|
5384
|
-
```js [app/adapters/post.js]
|
|
5385
|
-
import MyCustomAdapter from './custom-adapter';
|
|
5386
|
-
export default class PostAdapter extends MyCustomAdapter {
|
|
5387
|
-
findRecord(store, type, id, snapshot) {
|
|
5388
|
-
if (snapshot.adapterOptions.subscribe) {
|
|
5389
|
-
// ...
|
|
5390
|
-
}
|
|
5391
|
-
// ...
|
|
5392
|
-
}
|
|
5393
|
-
}
|
|
5394
|
-
```
|
|
5395
|
-
See [peekRecord](../methods/peekRecord?anchor=peekRecord) to get the cached version of a record.
|
|
5396
|
-
### Retrieving Related Model Records
|
|
5397
|
-
If you use an adapter such as Ember's default
|
|
5398
|
-
[`JSONAPIAdapter`](/ember-data/release/classes/JSONAPIAdapter)
|
|
5399
|
-
that supports the [JSON API specification](http://jsonapi.org/) and if your server
|
|
5400
|
-
endpoint supports the use of an
|
|
5401
|
-
['include' query parameter](http://jsonapi.org/format/#fetching-includes),
|
|
5402
|
-
you can use `findRecord()` or `findAll()` to automatically retrieve additional records related to
|
|
5403
|
-
the one you request by supplying an `include` parameter in the `options` object.
|
|
5404
|
-
For example, given a `post` model that has a `hasMany` relationship with a `comment`
|
|
5405
|
-
model, when we retrieve a specific post we can have the server also return that post's
|
|
5406
|
-
comments in the same request:
|
|
5407
|
-
```js [app/routes/post.js]
|
|
5408
|
-
export default class PostRoute extends Route {
|
|
5409
|
-
model(params) {
|
|
5410
|
-
return this.store.findRecord('post', params.post_id, { include: ['comments'] });
|
|
5411
|
-
}
|
|
5412
|
-
}
|
|
5413
|
-
```
|
|
5414
|
-
```js [app/adapters/application.js]
|
|
5415
|
-
export default class Adapter {
|
|
5416
|
-
findRecord(store, schema, id, snapshot) {
|
|
5417
|
-
let type = schema.modelName;
|
|
5418
|
-
if (type === 'post')
|
|
5419
|
-
let includes = snapshot.adapterOptions.include;
|
|
5420
|
-
return fetch(`./posts/${postId}?include=${includes}`)
|
|
5421
|
-
.then(response => response.json())
|
|
5422
|
-
}
|
|
5423
|
-
}
|
|
5424
|
-
static create() {
|
|
5425
|
-
return new this();
|
|
5426
|
-
}
|
|
5427
|
-
}
|
|
5428
|
-
```
|
|
5429
|
-
In this case, the post's comments would then be available in your template as
|
|
5430
|
-
`model.comments`.
|
|
5431
|
-
Multiple relationships can be requested using an `include` parameter consisting of a
|
|
5432
|
-
list of relationship names, while nested relationships can be specified
|
|
5433
|
-
using a dot-separated sequence of relationship names. So to request both the post's
|
|
5434
|
-
comments and the authors of those comments the request would look like this:
|
|
5435
|
-
```js [app/routes/post.js]
|
|
5436
|
-
export default class PostRoute extends Route {
|
|
5437
|
-
model(params) {
|
|
5438
|
-
return this.store.findRecord('post', params.post_id, { include: ['comments','comments.author'] });
|
|
5439
|
-
}
|
|
5440
|
-
}
|
|
5441
|
-
```
|
|
5442
|
-
### Retrieving Specific Fields by Type
|
|
5443
|
-
If your server endpoint supports the use of a ['fields' query parameter](https://jsonapi.org/format/#fetching-sparse-fieldsets),
|
|
5444
|
-
you can use pass those fields through to your server. At this point in time, this requires a few manual steps on your part.
|
|
5445
|
-
1. Implement `buildQuery` in your adapter.
|
|
5446
|
-
```js [app/adapters/application.js]
|
|
5447
|
-
buildQuery(snapshot) {
|
|
5448
|
-
let query = super.buildQuery(...arguments);
|
|
5449
|
-
let { fields } = snapshot.adapterOptions;
|
|
5450
|
-
if (fields) {
|
|
5451
|
-
query.fields = fields;
|
|
5452
|
-
}
|
|
5453
|
-
return query;
|
|
5454
|
-
}
|
|
5455
|
-
```
|
|
5456
|
-
2. Then pass through the applicable fields to your `findRecord` request.
|
|
5457
|
-
Given a `post` model with attributes body, title, publishDate and meta, you can retrieve a filtered list of attributes.
|
|
5458
|
-
```js [app/routes/post.js]
|
|
5459
|
-
export default class extends Route {
|
|
5460
|
-
model(params) {
|
|
5461
|
-
return this.store.findRecord('post', params.post_id, { adapterOptions: { fields: { post: 'body,title' } });
|
|
5462
|
-
}
|
|
5463
|
-
}
|
|
5464
|
-
```
|
|
5465
|
-
Moreover, you can filter attributes on related models as well. If a `post` has a `belongsTo` relationship to a user,
|
|
5466
|
-
just include the relationship key and attributes.
|
|
5467
|
-
```js [app/routes/post.js]
|
|
5468
|
-
export default class extends Route {
|
|
5469
|
-
model(params) {
|
|
5470
|
-
return this.store.findRecord('post', params.post_id, { adapterOptions: { fields: { post: 'body,title', user: 'name,email' } });
|
|
5471
|
-
}
|
|
5472
|
-
}
|
|
5473
|
-
```
|
|
5474
|
-
@since 1.13.0
|
|
5475
|
-
@public
|
|
5476
|
-
@param {String|object} type - either a string representing the name of the resource or a ResourceIdentifier object containing both the type (a string) and the id (a string) for the record or an lid (a string) of an existing record
|
|
5477
|
-
@param {(String|Integer|Object)} id - optional object with options for the request only if the first param is a ResourceIdentifier, else the string id of the record to be retrieved
|
|
5478
|
-
@param {Object} [options] - if the first param is a string this will be the optional options for the request. See examples for available options.
|
|
5479
|
-
@return {Promise} promise
|
|
5480
|
-
*/
|
|
5481
|
-
|
|
5482
|
-
findRecord(resource, id, options) {
|
|
5483
|
-
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
5484
|
-
assertDestroyingStore(this, 'findRecord');
|
|
5485
|
-
}
|
|
5486
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5487
|
-
if (!test) {
|
|
5488
|
-
throw new Error(`You need to pass a modelName or resource identifier as the first argument to the store's findRecord method`);
|
|
5489
|
-
}
|
|
5490
|
-
})(resource) : {};
|
|
5491
|
-
if (isMaybeIdentifier(resource)) {
|
|
5492
|
-
options = id;
|
|
5493
|
-
} else {
|
|
5494
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5495
|
-
if (!test) {
|
|
5496
|
-
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${resource}`);
|
|
5497
|
-
}
|
|
5498
|
-
})(typeof resource === 'string') : {};
|
|
5499
|
-
const type = normalizeModelName(resource);
|
|
5500
|
-
const normalizedId = ensureStringId(id);
|
|
5501
|
-
resource = constructResource(type, normalizedId);
|
|
5502
|
-
}
|
|
5503
|
-
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
|
|
5504
|
-
options = options || {};
|
|
5505
|
-
if (options.preload) {
|
|
5506
|
-
// force reload if we preload to ensure we don't resolve the promise
|
|
5507
|
-
// until we are complete, else we will end up background-reloading
|
|
5508
|
-
// even for initial load.
|
|
5509
|
-
if (!this._instanceCache.recordIsLoaded(identifier)) {
|
|
5510
|
-
options.reload = true;
|
|
5511
|
-
}
|
|
5512
|
-
this._join(() => {
|
|
5513
|
-
preloadData(this, identifier, options.preload);
|
|
5514
|
-
});
|
|
5515
|
-
}
|
|
5516
|
-
const promise = this.request({
|
|
5517
|
-
op: 'findRecord',
|
|
5518
|
-
data: {
|
|
5519
|
-
record: identifier,
|
|
5520
|
-
options
|
|
5521
|
-
},
|
|
5522
|
-
cacheOptions: {
|
|
5523
|
-
[SkipCache]: true
|
|
5524
|
-
}
|
|
5525
|
-
});
|
|
5526
|
-
return promise.then(document => {
|
|
5527
|
-
return document.content;
|
|
5528
|
-
});
|
|
5529
|
-
}
|
|
5530
|
-
|
|
5531
|
-
/**
|
|
5532
|
-
Get the reference for the specified record.
|
|
5533
|
-
Example
|
|
5534
|
-
```javascript
|
|
5535
|
-
let userRef = store.getReference('user', '1');
|
|
5536
|
-
// check if the user is loaded
|
|
5537
|
-
let isLoaded = userRef.value() !== null;
|
|
5538
|
-
// get the record of the reference (null if not yet available)
|
|
5539
|
-
let user = userRef.value();
|
|
5540
|
-
// get the identifier of the reference
|
|
5541
|
-
if (userRef.remoteType() === 'id') {
|
|
5542
|
-
let id = userRef.id();
|
|
5543
|
-
}
|
|
5544
|
-
// load user (via store.find)
|
|
5545
|
-
userRef.load().then(...)
|
|
5546
|
-
// or trigger a reload
|
|
5547
|
-
userRef.reload().then(...)
|
|
5548
|
-
// provide data for reference
|
|
5549
|
-
userRef.push({ id: 1, username: '@user' }).then(function(user) {
|
|
5550
|
-
userRef.value() === user;
|
|
5551
|
-
});
|
|
5552
|
-
```
|
|
5553
|
-
@public
|
|
5554
|
-
@param {String|object} resource - modelName (string) or Identifier (object)
|
|
5555
|
-
@param {String|Integer} id
|
|
5556
|
-
@since 2.5.0
|
|
5557
|
-
@return {RecordReference}
|
|
5558
|
-
*/
|
|
5559
|
-
// TODO @deprecate getReference (and references generally)
|
|
5560
|
-
getReference(resource, id) {
|
|
5561
|
-
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
5562
|
-
assertDestroyingStore(this, 'getReference');
|
|
5563
|
-
}
|
|
5564
|
-
let resourceIdentifier;
|
|
5565
|
-
if (arguments.length === 1 && isMaybeIdentifier(resource)) {
|
|
5566
|
-
resourceIdentifier = resource;
|
|
5567
|
-
} else {
|
|
5568
|
-
const type = normalizeModelName(resource);
|
|
5569
|
-
const normalizedId = ensureStringId(id);
|
|
5570
|
-
resourceIdentifier = constructResource(type, normalizedId);
|
|
5571
|
-
}
|
|
5572
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5573
|
-
if (!test) {
|
|
5574
|
-
throw new Error('getReference expected to receive either a resource identifier or type and id as arguments');
|
|
5575
|
-
}
|
|
5576
|
-
})(isMaybeIdentifier(resourceIdentifier)) : {};
|
|
5577
|
-
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resourceIdentifier);
|
|
5578
|
-
return this._instanceCache.getReference(identifier);
|
|
5579
|
-
}
|
|
5580
|
-
|
|
5581
|
-
/**
|
|
5582
|
-
Get a record by a given type and ID without triggering a fetch.
|
|
5583
|
-
This method will synchronously return the record if it is available in the store,
|
|
5584
|
-
otherwise it will return `null`. A record is available if it has been fetched earlier, or
|
|
5585
|
-
pushed manually into the store.
|
|
5586
|
-
See [findRecord](../methods/findRecord?anchor=findRecord) if you would like to request this record from the backend.
|
|
5587
|
-
_Note: This is a synchronous method and does not return a promise._
|
|
5588
|
-
**Example 1**
|
|
5589
|
-
```js
|
|
5590
|
-
let post = store.peekRecord('post', '1');
|
|
5591
|
-
post.id; // '1'
|
|
5592
|
-
```
|
|
5593
|
-
`peekRecord` can be called with a single identifier argument instead of the combination
|
|
5594
|
-
of `type` (modelName) and `id` as separate arguments. You may recognize this combo as
|
|
5595
|
-
the typical pairing from [JSON:API](https://jsonapi.org/format/#document-resource-object-identification)
|
|
5596
|
-
**Example 2**
|
|
5597
|
-
```js
|
|
5598
|
-
let post = store.peekRecord({ type: 'post', id });
|
|
5599
|
-
post.id; // '1'
|
|
5600
|
-
```
|
|
5601
|
-
If you have previously received an lid from an Identifier for this record, you can lookup the record again using
|
|
5602
|
-
just the lid.
|
|
4782
|
+
If you have previously received an lid from an Identifier for this record, you can lookup the record again using
|
|
4783
|
+
just the lid.
|
|
5603
4784
|
**Example 3**
|
|
5604
4785
|
```js
|
|
5605
4786
|
let post = store.peekRecord({ lid });
|
|
@@ -5645,430 +4826,73 @@ class Store extends BaseClass {
|
|
|
5645
4826
|
}
|
|
5646
4827
|
|
|
5647
4828
|
/**
|
|
5648
|
-
This method
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
```
|
|
5659
|
-
The request made to the server will look something like this:
|
|
5660
|
-
```
|
|
5661
|
-
GET "/api/v1/person?page=1"
|
|
5662
|
-
```
|
|
5663
|
-
---
|
|
5664
|
-
If you do something like this:
|
|
4829
|
+
This method returns a filtered array that contains all of the
|
|
4830
|
+
known records for a given type in the store.
|
|
4831
|
+
Note that because it's just a filter, the result will contain any
|
|
4832
|
+
locally created records of the type, however, it will not make a
|
|
4833
|
+
request to the backend to retrieve additional records. If you
|
|
4834
|
+
would like to request all the records from the backend please use
|
|
4835
|
+
[store.findAll](../methods/findAll?anchor=findAll).
|
|
4836
|
+
Also note that multiple calls to `peekAll` for a given type will always
|
|
4837
|
+
return the same `RecordArray`.
|
|
4838
|
+
Example
|
|
5665
4839
|
```javascript
|
|
5666
|
-
store.
|
|
5667
|
-
```
|
|
5668
|
-
The request made to the server will look something like this:
|
|
5669
|
-
```
|
|
5670
|
-
GET "/api/v1/person?ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3"
|
|
5671
|
-
decoded: "/api/v1/person?ids[]=1&ids[]=2&ids[]=3"
|
|
4840
|
+
let localPosts = store.peekAll('post');
|
|
5672
4841
|
```
|
|
5673
|
-
This method returns a promise, which is resolved with a
|
|
5674
|
-
[`Collection`](/ember-data/release/classes/Collection)
|
|
5675
|
-
once the server returns.
|
|
5676
4842
|
@since 1.13.0
|
|
5677
4843
|
@public
|
|
5678
4844
|
@param {String} type the name of the resource
|
|
5679
|
-
@
|
|
5680
|
-
@param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.query
|
|
5681
|
-
@return {Promise} promise
|
|
4845
|
+
@return {RecordArray}
|
|
5682
4846
|
*/
|
|
5683
4847
|
|
|
5684
|
-
|
|
4848
|
+
peekAll(type) {
|
|
5685
4849
|
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
5686
|
-
assertDestroyingStore(this, '
|
|
4850
|
+
assertDestroyingStore(this, 'peekAll');
|
|
5687
4851
|
}
|
|
5688
4852
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5689
4853
|
if (!test) {
|
|
5690
|
-
throw new Error(`You need to pass a model name to the store's
|
|
4854
|
+
throw new Error(`You need to pass a model name to the store's peekAll method`);
|
|
5691
4855
|
}
|
|
5692
4856
|
})(type) : {};
|
|
5693
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5694
|
-
if (!test) {
|
|
5695
|
-
throw new Error(`You need to pass a query hash to the store's query method`);
|
|
5696
|
-
}
|
|
5697
|
-
})(query) : {};
|
|
5698
4857
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5699
4858
|
if (!test) {
|
|
5700
4859
|
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${type}`);
|
|
5701
4860
|
}
|
|
5702
4861
|
})(typeof type === 'string') : {};
|
|
5703
|
-
|
|
5704
|
-
op: 'query',
|
|
5705
|
-
data: {
|
|
5706
|
-
type: normalizeModelName(type),
|
|
5707
|
-
query,
|
|
5708
|
-
options: options
|
|
5709
|
-
},
|
|
5710
|
-
cacheOptions: {
|
|
5711
|
-
[SkipCache]: true
|
|
5712
|
-
}
|
|
5713
|
-
});
|
|
5714
|
-
return promise.then(document => document.content);
|
|
4862
|
+
return this.recordArrayManager.liveArrayFor(normalizeModelName(type));
|
|
5715
4863
|
}
|
|
5716
4864
|
|
|
5717
4865
|
/**
|
|
5718
|
-
This method
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
This method can be used when it is certain that the server will return a
|
|
5722
|
-
single object for the primary data.
|
|
5723
|
-
Each time this method is called a new request is made through the adapter.
|
|
5724
|
-
Let's assume our API provides an endpoint for the currently logged in user
|
|
5725
|
-
via:
|
|
5726
|
-
```
|
|
5727
|
-
// GET /api/current_user
|
|
5728
|
-
{
|
|
5729
|
-
user: {
|
|
5730
|
-
id: 1234,
|
|
5731
|
-
username: 'admin'
|
|
5732
|
-
}
|
|
5733
|
-
}
|
|
5734
|
-
```
|
|
5735
|
-
Since the specific `id` of the `user` is not known beforehand, we can use
|
|
5736
|
-
`queryRecord` to get the user:
|
|
5737
|
-
```javascript
|
|
5738
|
-
store.queryRecord('user', {}).then(function(user) {
|
|
5739
|
-
let username = user.username;
|
|
5740
|
-
// do thing
|
|
5741
|
-
});
|
|
5742
|
-
```
|
|
5743
|
-
The request is made through the adapters' `queryRecord`:
|
|
5744
|
-
```js [app/adapters/user.js]
|
|
5745
|
-
import Adapter from '@ember-data/adapter';
|
|
5746
|
-
import $ from 'jquery';
|
|
5747
|
-
export default class UserAdapter extends Adapter {
|
|
5748
|
-
queryRecord(modelName, query) {
|
|
5749
|
-
return $.getJSON('/api/current_user');
|
|
5750
|
-
}
|
|
5751
|
-
}
|
|
5752
|
-
```
|
|
5753
|
-
Note: the primary use case for `store.queryRecord` is when a single record
|
|
5754
|
-
is queried and the `id` is not known beforehand. In all other cases
|
|
5755
|
-
`store.query` and using the first item of the array is likely the preferred
|
|
5756
|
-
way:
|
|
5757
|
-
```
|
|
5758
|
-
// GET /users?username=unique
|
|
5759
|
-
{
|
|
5760
|
-
data: [{
|
|
5761
|
-
id: 1234,
|
|
5762
|
-
type: 'user',
|
|
5763
|
-
attributes: {
|
|
5764
|
-
username: "unique"
|
|
5765
|
-
}
|
|
5766
|
-
}]
|
|
5767
|
-
}
|
|
5768
|
-
```
|
|
5769
|
-
```javascript
|
|
5770
|
-
store.query('user', { username: 'unique' }).then(function(users) {
|
|
5771
|
-
return users.firstObject;
|
|
5772
|
-
}).then(function(user) {
|
|
5773
|
-
let id = user.id;
|
|
5774
|
-
});
|
|
5775
|
-
```
|
|
5776
|
-
This method returns a promise, which resolves with the found record.
|
|
5777
|
-
If the adapter returns no data for the primary data of the payload, then
|
|
5778
|
-
`queryRecord` resolves with `null`:
|
|
5779
|
-
```
|
|
5780
|
-
// GET /users?username=unique
|
|
5781
|
-
{
|
|
5782
|
-
data: null
|
|
5783
|
-
}
|
|
5784
|
-
```
|
|
4866
|
+
This method unloads all records in the store.
|
|
4867
|
+
It schedules unloading to happen during the next run loop.
|
|
4868
|
+
Optionally you can pass a type which unload all records for a given type.
|
|
5785
4869
|
```javascript
|
|
5786
|
-
store.
|
|
5787
|
-
|
|
5788
|
-
});
|
|
4870
|
+
store.unloadAll();
|
|
4871
|
+
store.unloadAll('post');
|
|
5789
4872
|
```
|
|
5790
|
-
@
|
|
4873
|
+
@param {String} type the name of the resource
|
|
5791
4874
|
@public
|
|
5792
|
-
@param {String} type
|
|
5793
|
-
@param {Object} query an opaque query to be used by the adapter
|
|
5794
|
-
@param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.queryRecord
|
|
5795
|
-
@return {Promise} promise which resolves with the found record or `null`
|
|
5796
4875
|
*/
|
|
5797
4876
|
|
|
5798
|
-
|
|
4877
|
+
unloadAll(type) {
|
|
5799
4878
|
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
5800
|
-
|
|
4879
|
+
assertDestroyedStoreOnly(this, 'unloadAll');
|
|
5801
4880
|
}
|
|
5802
4881
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5803
4882
|
if (!test) {
|
|
5804
|
-
throw new Error(`
|
|
4883
|
+
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${String(type)}`);
|
|
5805
4884
|
}
|
|
5806
|
-
})(type) : {};
|
|
5807
|
-
|
|
5808
|
-
if (
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
}
|
|
5816
|
-
|
|
5817
|
-
const promise = this.request({
|
|
5818
|
-
op: 'queryRecord',
|
|
5819
|
-
data: {
|
|
5820
|
-
type: normalizeModelName(type),
|
|
5821
|
-
query,
|
|
5822
|
-
options: options || {}
|
|
5823
|
-
},
|
|
5824
|
-
cacheOptions: {
|
|
5825
|
-
[SkipCache]: true
|
|
5826
|
-
}
|
|
5827
|
-
});
|
|
5828
|
-
return promise.then(document => document.content);
|
|
5829
|
-
}
|
|
5830
|
-
|
|
5831
|
-
/**
|
|
5832
|
-
`findAll` asks the adapter's `findAll` method to find the records for the
|
|
5833
|
-
given type, and returns a promise which will resolve with all records of
|
|
5834
|
-
this type present in the store, even if the adapter only returns a subset
|
|
5835
|
-
of them.
|
|
5836
|
-
```js [app/routes/authors.js]
|
|
5837
|
-
export default class AuthorsRoute extends Route {
|
|
5838
|
-
model(params) {
|
|
5839
|
-
return this.store.findAll('author');
|
|
5840
|
-
}
|
|
5841
|
-
}
|
|
5842
|
-
```
|
|
5843
|
-
_When_ the returned promise resolves depends on the reload behavior,
|
|
5844
|
-
configured via the passed `options` hash and the result of the adapter's
|
|
5845
|
-
`shouldReloadAll` method.
|
|
5846
|
-
### Reloading
|
|
5847
|
-
If `{ reload: true }` is passed or `adapter.shouldReloadAll` evaluates to
|
|
5848
|
-
`true`, then the returned promise resolves once the adapter returns data,
|
|
5849
|
-
regardless if there are already records in the store:
|
|
5850
|
-
```js
|
|
5851
|
-
store.push({
|
|
5852
|
-
data: {
|
|
5853
|
-
id: 'first',
|
|
5854
|
-
type: 'author'
|
|
5855
|
-
}
|
|
5856
|
-
});
|
|
5857
|
-
// adapter#findAll resolves with
|
|
5858
|
-
// [
|
|
5859
|
-
// {
|
|
5860
|
-
// id: 'second',
|
|
5861
|
-
// type: 'author'
|
|
5862
|
-
// }
|
|
5863
|
-
// ]
|
|
5864
|
-
store.findAll('author', { reload: true }).then(function(authors) {
|
|
5865
|
-
authors.getEach('id'); // ['first', 'second']
|
|
5866
|
-
});
|
|
5867
|
-
```
|
|
5868
|
-
If no reload is indicated via the above mentioned ways, then the promise
|
|
5869
|
-
immediately resolves with all the records currently loaded in the store.
|
|
5870
|
-
### Background Reloading
|
|
5871
|
-
Optionally, if `adapter.shouldBackgroundReloadAll` evaluates to `true`,
|
|
5872
|
-
then a background reload is started. Once this resolves, the array with
|
|
5873
|
-
which the promise resolves, is updated automatically so it contains all the
|
|
5874
|
-
records in the store:
|
|
5875
|
-
```js [app/adapters/application.js]
|
|
5876
|
-
import Adapter from '@ember-data/adapter';
|
|
5877
|
-
export default class ApplicationAdapter extends Adapter {
|
|
5878
|
-
shouldReloadAll(store, snapshotsArray) {
|
|
5879
|
-
return false;
|
|
5880
|
-
},
|
|
5881
|
-
shouldBackgroundReloadAll(store, snapshotsArray) {
|
|
5882
|
-
return true;
|
|
5883
|
-
}
|
|
5884
|
-
});
|
|
5885
|
-
// ...
|
|
5886
|
-
store.push({
|
|
5887
|
-
data: {
|
|
5888
|
-
id: 'first',
|
|
5889
|
-
type: 'author'
|
|
5890
|
-
}
|
|
5891
|
-
});
|
|
5892
|
-
let allAuthors;
|
|
5893
|
-
store.findAll('author').then(function(authors) {
|
|
5894
|
-
authors.getEach('id'); // ['first']
|
|
5895
|
-
allAuthors = authors;
|
|
5896
|
-
});
|
|
5897
|
-
// later, once adapter#findAll resolved with
|
|
5898
|
-
// [
|
|
5899
|
-
// {
|
|
5900
|
-
// id: 'second',
|
|
5901
|
-
// type: 'author'
|
|
5902
|
-
// }
|
|
5903
|
-
// ]
|
|
5904
|
-
allAuthors.getEach('id'); // ['first', 'second']
|
|
5905
|
-
```
|
|
5906
|
-
If you would like to force or prevent background reloading, you can set a
|
|
5907
|
-
boolean value for `backgroundReload` in the options object for
|
|
5908
|
-
`findAll`.
|
|
5909
|
-
```js [app/routes/post/edit.js]
|
|
5910
|
-
export default class PostEditRoute extends Route {
|
|
5911
|
-
model() {
|
|
5912
|
-
return this.store.findAll('post', { backgroundReload: false });
|
|
5913
|
-
}
|
|
5914
|
-
}
|
|
5915
|
-
```
|
|
5916
|
-
If you pass an object on the `adapterOptions` property of the options
|
|
5917
|
-
argument it will be passed to you adapter via the `snapshotRecordArray`
|
|
5918
|
-
```js [app/routes/posts.js]
|
|
5919
|
-
export default class PostsRoute extends Route {
|
|
5920
|
-
model(params) {
|
|
5921
|
-
return this.store.findAll('post', {
|
|
5922
|
-
adapterOptions: { subscribe: false }
|
|
5923
|
-
});
|
|
5924
|
-
}
|
|
5925
|
-
}
|
|
5926
|
-
```
|
|
5927
|
-
```js [app/adapters/post.js]
|
|
5928
|
-
import MyCustomAdapter from './custom-adapter';
|
|
5929
|
-
export default class UserAdapter extends MyCustomAdapter {
|
|
5930
|
-
findAll(store, type, sinceToken, snapshotRecordArray) {
|
|
5931
|
-
if (snapshotRecordArray.adapterOptions.subscribe) {
|
|
5932
|
-
// ...
|
|
5933
|
-
}
|
|
5934
|
-
// ...
|
|
5935
|
-
}
|
|
5936
|
-
}
|
|
5937
|
-
```
|
|
5938
|
-
See [peekAll](../methods/peekAll?anchor=peekAll) to get an array of current records in the
|
|
5939
|
-
store, without waiting until a reload is finished.
|
|
5940
|
-
### Retrieving Related Model Records
|
|
5941
|
-
If you use an adapter such as Ember's default
|
|
5942
|
-
[`JSONAPIAdapter`](/ember-data/release/classes/JSONAPIAdapter)
|
|
5943
|
-
that supports the [JSON API specification](http://jsonapi.org/) and if your server
|
|
5944
|
-
endpoint supports the use of an
|
|
5945
|
-
['include' query parameter](http://jsonapi.org/format/#fetching-includes),
|
|
5946
|
-
you can use `findAll()` to automatically retrieve additional records related to
|
|
5947
|
-
those requested by supplying an `include` parameter in the `options` object.
|
|
5948
|
-
For example, given a `post` model that has a `hasMany` relationship with a `comment`
|
|
5949
|
-
model, when we retrieve all of the post records we can have the server also return
|
|
5950
|
-
all of the posts' comments in the same request:
|
|
5951
|
-
```js [app/routes/posts.js]
|
|
5952
|
-
export default class PostsRoute extends Route {
|
|
5953
|
-
model() {
|
|
5954
|
-
return this.store.findAll('post', { include: ['comments'] });
|
|
5955
|
-
}
|
|
5956
|
-
}
|
|
5957
|
-
```
|
|
5958
|
-
Multiple relationships can be requested using an `include` parameter consisting of a
|
|
5959
|
-
list or relationship names, while nested relationships can be specified
|
|
5960
|
-
using a dot-separated sequence of relationship names. So to request both the posts'
|
|
5961
|
-
comments and the authors of those comments the request would look like this:
|
|
5962
|
-
```js [app/routes/posts.js]
|
|
5963
|
-
export default class PostsRoute extends Route {
|
|
5964
|
-
model() {
|
|
5965
|
-
return this.store.findAll('post', { include: ['comments','comments.author'] });
|
|
5966
|
-
}
|
|
5967
|
-
}
|
|
5968
|
-
```
|
|
5969
|
-
See [query](../methods/query?anchor=query) to only get a subset of records from the server.
|
|
5970
|
-
@since 1.13.0
|
|
5971
|
-
@public
|
|
5972
|
-
@param {String} type the name of the resource
|
|
5973
|
-
@param {Object} options
|
|
5974
|
-
@return {Promise} promise
|
|
5975
|
-
*/
|
|
5976
|
-
|
|
5977
|
-
findAll(type, options = {}) {
|
|
5978
|
-
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
5979
|
-
assertDestroyingStore(this, 'findAll');
|
|
5980
|
-
}
|
|
5981
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5982
|
-
if (!test) {
|
|
5983
|
-
throw new Error(`You need to pass a model name to the store's findAll method`);
|
|
5984
|
-
}
|
|
5985
|
-
})(type) : {};
|
|
5986
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5987
|
-
if (!test) {
|
|
5988
|
-
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${type}`);
|
|
5989
|
-
}
|
|
5990
|
-
})(typeof type === 'string') : {};
|
|
5991
|
-
const promise = this.request({
|
|
5992
|
-
op: 'findAll',
|
|
5993
|
-
data: {
|
|
5994
|
-
type: normalizeModelName(type),
|
|
5995
|
-
options: options || {}
|
|
5996
|
-
},
|
|
5997
|
-
cacheOptions: {
|
|
5998
|
-
[SkipCache]: true
|
|
5999
|
-
}
|
|
6000
|
-
});
|
|
6001
|
-
return promise.then(document => document.content);
|
|
6002
|
-
}
|
|
6003
|
-
|
|
6004
|
-
/**
|
|
6005
|
-
This method returns a filtered array that contains all of the
|
|
6006
|
-
known records for a given type in the store.
|
|
6007
|
-
Note that because it's just a filter, the result will contain any
|
|
6008
|
-
locally created records of the type, however, it will not make a
|
|
6009
|
-
request to the backend to retrieve additional records. If you
|
|
6010
|
-
would like to request all the records from the backend please use
|
|
6011
|
-
[store.findAll](../methods/findAll?anchor=findAll).
|
|
6012
|
-
Also note that multiple calls to `peekAll` for a given type will always
|
|
6013
|
-
return the same `RecordArray`.
|
|
6014
|
-
Example
|
|
6015
|
-
```javascript
|
|
6016
|
-
let localPosts = store.peekAll('post');
|
|
6017
|
-
```
|
|
6018
|
-
@since 1.13.0
|
|
6019
|
-
@public
|
|
6020
|
-
@param {String} type the name of the resource
|
|
6021
|
-
@return {RecordArray}
|
|
6022
|
-
*/
|
|
6023
|
-
|
|
6024
|
-
peekAll(type) {
|
|
6025
|
-
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
6026
|
-
assertDestroyingStore(this, 'peekAll');
|
|
6027
|
-
}
|
|
6028
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
6029
|
-
if (!test) {
|
|
6030
|
-
throw new Error(`You need to pass a model name to the store's peekAll method`);
|
|
6031
|
-
}
|
|
6032
|
-
})(type) : {};
|
|
6033
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
6034
|
-
if (!test) {
|
|
6035
|
-
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${type}`);
|
|
6036
|
-
}
|
|
6037
|
-
})(typeof type === 'string') : {};
|
|
6038
|
-
return this.recordArrayManager.liveArrayFor(normalizeModelName(type));
|
|
6039
|
-
}
|
|
6040
|
-
|
|
6041
|
-
/**
|
|
6042
|
-
This method unloads all records in the store.
|
|
6043
|
-
It schedules unloading to happen during the next run loop.
|
|
6044
|
-
Optionally you can pass a type which unload all records for a given type.
|
|
6045
|
-
```javascript
|
|
6046
|
-
store.unloadAll();
|
|
6047
|
-
store.unloadAll('post');
|
|
6048
|
-
```
|
|
6049
|
-
@param {String} type the name of the resource
|
|
6050
|
-
@public
|
|
6051
|
-
*/
|
|
6052
|
-
|
|
6053
|
-
unloadAll(type) {
|
|
6054
|
-
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
6055
|
-
assertDestroyedStoreOnly(this, 'unloadAll');
|
|
6056
|
-
}
|
|
6057
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
6058
|
-
if (!test) {
|
|
6059
|
-
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${String(type)}`);
|
|
6060
|
-
}
|
|
6061
|
-
})(!type || typeof type === 'string') : {};
|
|
6062
|
-
this._join(() => {
|
|
6063
|
-
if (type === undefined) {
|
|
6064
|
-
// destroy the graph before unloadAll
|
|
6065
|
-
// since then we avoid churning relationships
|
|
6066
|
-
// during unload
|
|
6067
|
-
this._graph?.identifiers.clear();
|
|
6068
|
-
this.recordArrayManager.clear();
|
|
6069
|
-
this._instanceCache.clear();
|
|
6070
|
-
} else {
|
|
6071
|
-
this._instanceCache.clear(normalizeModelName(type));
|
|
4885
|
+
})(!type || typeof type === 'string') : {};
|
|
4886
|
+
this._join(() => {
|
|
4887
|
+
if (type === undefined) {
|
|
4888
|
+
// destroy the graph before unloadAll
|
|
4889
|
+
// since then we avoid churning relationships
|
|
4890
|
+
// during unload
|
|
4891
|
+
this._graph?.identifiers.clear();
|
|
4892
|
+
this.recordArrayManager.clear();
|
|
4893
|
+
this._instanceCache.clear();
|
|
4894
|
+
} else {
|
|
4895
|
+
this._instanceCache.clear(normalizeModelName(type));
|
|
6072
4896
|
}
|
|
6073
4897
|
});
|
|
6074
4898
|
}
|
|
@@ -6241,81 +5065,10 @@ class Store extends BaseClass {
|
|
|
6241
5065
|
return 'data' in ret ? ret.data : null;
|
|
6242
5066
|
}
|
|
6243
5067
|
|
|
6244
|
-
/**
|
|
6245
|
-
* Trigger a save for a Record.
|
|
6246
|
-
*
|
|
6247
|
-
* Returns a promise resolving with the same record when the save is complete.
|
|
6248
|
-
*
|
|
6249
|
-
* @public
|
|
6250
|
-
* @param {unknown} record
|
|
6251
|
-
* @param options
|
|
6252
|
-
* @return {Promise<record>}
|
|
6253
|
-
*/
|
|
6254
|
-
saveRecord(record, options = {}) {
|
|
6255
|
-
if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
|
|
6256
|
-
assertDestroyingStore(this, 'saveRecord');
|
|
6257
|
-
}
|
|
6258
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
6259
|
-
if (!test) {
|
|
6260
|
-
throw new Error(`Unable to initiate save for a record in a disconnected state`);
|
|
6261
|
-
}
|
|
6262
|
-
})(storeFor(record)) : {};
|
|
6263
|
-
const identifier = recordIdentifierFor(record);
|
|
6264
|
-
const cache = this.cache;
|
|
6265
|
-
if (!identifier) {
|
|
6266
|
-
// this commonly means we're disconnected
|
|
6267
|
-
// but just in case we reject here to prevent bad things.
|
|
6268
|
-
return Promise.reject(new Error(`Record Is Disconnected`));
|
|
6269
|
-
}
|
|
6270
|
-
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
6271
|
-
if (!test) {
|
|
6272
|
-
throw new Error(`Cannot initiate a save request for an unloaded record: ${identifier.lid}`);
|
|
6273
|
-
}
|
|
6274
|
-
})(this._instanceCache.recordIsLoaded(identifier)) : {};
|
|
6275
|
-
if (resourceIsFullyDeleted(this._instanceCache, identifier)) {
|
|
6276
|
-
return Promise.resolve(record);
|
|
6277
|
-
}
|
|
6278
|
-
if (!options) {
|
|
6279
|
-
options = {};
|
|
6280
|
-
}
|
|
6281
|
-
let operation = 'updateRecord';
|
|
6282
|
-
if (cache.isNew(identifier)) {
|
|
6283
|
-
operation = 'createRecord';
|
|
6284
|
-
} else if (cache.isDeleted(identifier)) {
|
|
6285
|
-
operation = 'deleteRecord';
|
|
6286
|
-
}
|
|
6287
|
-
const request = {
|
|
6288
|
-
op: operation,
|
|
6289
|
-
data: {
|
|
6290
|
-
options,
|
|
6291
|
-
record: identifier
|
|
6292
|
-
},
|
|
6293
|
-
records: [identifier],
|
|
6294
|
-
cacheOptions: {
|
|
6295
|
-
[SkipCache]: true
|
|
6296
|
-
}
|
|
6297
|
-
};
|
|
6298
|
-
return this.request(request).then(document => document.content);
|
|
6299
|
-
}
|
|
6300
|
-
|
|
6301
|
-
/**
|
|
6302
|
-
* Instantiation hook allowing applications or addons to configure the store
|
|
6303
|
-
* to utilize a custom Cache implementation.
|
|
6304
|
-
*
|
|
6305
|
-
* This hook should not be called directly by consuming applications or libraries.
|
|
6306
|
-
* Use `Store.cache` to access the Cache instance.
|
|
6307
|
-
*
|
|
6308
|
-
* @public
|
|
6309
|
-
* @param storeWrapper
|
|
6310
|
-
* @return {Cache}
|
|
6311
|
-
*/
|
|
6312
|
-
|
|
6313
5068
|
/**
|
|
6314
5069
|
* Returns the cache instance associated to this Store, instantiates the Cache
|
|
6315
5070
|
* if necessary via `Store.createCache`
|
|
6316
5071
|
*
|
|
6317
|
-
* @property cache
|
|
6318
|
-
* @type {Cache}
|
|
6319
5072
|
* @public
|
|
6320
5073
|
*/
|
|
6321
5074
|
get cache() {
|
|
@@ -6330,6 +5083,8 @@ class Store extends BaseClass {
|
|
|
6330
5083
|
}
|
|
6331
5084
|
return cache;
|
|
6332
5085
|
}
|
|
5086
|
+
|
|
5087
|
+
/** @internal */
|
|
6333
5088
|
destroy() {
|
|
6334
5089
|
if (this.isDestroyed) {
|
|
6335
5090
|
// @ember/test-helpers will call destroy multiple times
|
|
@@ -6344,6 +5099,12 @@ class Store extends BaseClass {
|
|
|
6344
5099
|
this.unloadAll();
|
|
6345
5100
|
this.isDestroyed = true;
|
|
6346
5101
|
}
|
|
5102
|
+
|
|
5103
|
+
/**
|
|
5104
|
+
* This method
|
|
5105
|
+
*
|
|
5106
|
+
* @private
|
|
5107
|
+
*/
|
|
6347
5108
|
static create(args) {
|
|
6348
5109
|
return new this(args);
|
|
6349
5110
|
}
|
|
@@ -6487,6 +5248,748 @@ function extractIdentifierFromRecord$1(recordOrPromiseRecord) {
|
|
|
6487
5248
|
const extract = recordIdentifierFor;
|
|
6488
5249
|
return extract(recordOrPromiseRecord);
|
|
6489
5250
|
}
|
|
5251
|
+
|
|
5252
|
+
/*
|
|
5253
|
+
When a find request is triggered on the store, the user can optionally pass in
|
|
5254
|
+
attributes and relationships to be preloaded. These are meant to behave as if they
|
|
5255
|
+
came back from the server, except the user obtained them out of band and is informing
|
|
5256
|
+
the store of their existence. The most common use case is for supporting client side
|
|
5257
|
+
nested URLs, such as `/posts/1/comments/2` so the user can do
|
|
5258
|
+
`store.findRecord('comment', 2, { preload: { post: 1 } })` without having to fetch the post.
|
|
5259
|
+
|
|
5260
|
+
Preloaded data can be attributes and relationships passed in either as IDs or as actual
|
|
5261
|
+
models.
|
|
5262
|
+
*/
|
|
5263
|
+
function preloadData(store, identifier, preload) {
|
|
5264
|
+
const jsonPayload = {};
|
|
5265
|
+
//TODO(Igor) consider the polymorphic case
|
|
5266
|
+
const schemas = store.schema;
|
|
5267
|
+
const fields = schemas.fields(identifier);
|
|
5268
|
+
Object.keys(preload).forEach(key => {
|
|
5269
|
+
const preloadValue = preload[key];
|
|
5270
|
+
const field = fields.get(key);
|
|
5271
|
+
if (field && (field.kind === 'hasMany' || field.kind === 'belongsTo')) {
|
|
5272
|
+
if (!jsonPayload.relationships) {
|
|
5273
|
+
jsonPayload.relationships = {};
|
|
5274
|
+
}
|
|
5275
|
+
jsonPayload.relationships[key] = preloadRelationship(field, preloadValue);
|
|
5276
|
+
} else {
|
|
5277
|
+
if (!jsonPayload.attributes) {
|
|
5278
|
+
jsonPayload.attributes = {};
|
|
5279
|
+
}
|
|
5280
|
+
jsonPayload.attributes[key] = preloadValue;
|
|
5281
|
+
}
|
|
5282
|
+
});
|
|
5283
|
+
const cache = store.cache;
|
|
5284
|
+
const hasRecord = Boolean(store._instanceCache.peek(identifier));
|
|
5285
|
+
cache.upsert(identifier, jsonPayload, hasRecord);
|
|
5286
|
+
}
|
|
5287
|
+
function preloadRelationship(schema, preloadValue) {
|
|
5288
|
+
const relatedType = schema.type;
|
|
5289
|
+
if (schema.kind === 'hasMany') {
|
|
5290
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5291
|
+
if (!test) {
|
|
5292
|
+
throw new Error('You need to pass in an array to set a hasMany property on a record');
|
|
5293
|
+
}
|
|
5294
|
+
})(Array.isArray(preloadValue)) : {};
|
|
5295
|
+
return {
|
|
5296
|
+
data: preloadValue.map(value => _convertPreloadRelationshipToJSON(value, relatedType))
|
|
5297
|
+
};
|
|
5298
|
+
}
|
|
5299
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5300
|
+
if (!test) {
|
|
5301
|
+
throw new Error('You should not pass in an array to set a belongsTo property on a record');
|
|
5302
|
+
}
|
|
5303
|
+
})(!Array.isArray(preloadValue)) : {};
|
|
5304
|
+
return {
|
|
5305
|
+
data: preloadValue ? _convertPreloadRelationshipToJSON(preloadValue, relatedType) : null
|
|
5306
|
+
};
|
|
5307
|
+
}
|
|
5308
|
+
|
|
5309
|
+
/*
|
|
5310
|
+
findRecord('user', '1', { preload: { friends: ['1'] }});
|
|
5311
|
+
findRecord('user', '1', { preload: { friends: [record] }});
|
|
5312
|
+
*/
|
|
5313
|
+
function _convertPreloadRelationshipToJSON(value, type) {
|
|
5314
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
5315
|
+
return {
|
|
5316
|
+
type,
|
|
5317
|
+
id: ensureStringId(value)
|
|
5318
|
+
};
|
|
5319
|
+
}
|
|
5320
|
+
// TODO if not a record instance assert it's an identifier
|
|
5321
|
+
// and allow identifiers to be used
|
|
5322
|
+
return recordIdentifierFor(value);
|
|
5323
|
+
}
|
|
5324
|
+
|
|
5325
|
+
/**
|
|
5326
|
+
* Minimum subset of static schema methods and properties on the
|
|
5327
|
+
* "model" class.
|
|
5328
|
+
*
|
|
5329
|
+
* Only used when using the legacy schema-service implementation
|
|
5330
|
+
* for @ember-data/model or when wrapping schema for legacy
|
|
5331
|
+
* Adapters/Serializers.
|
|
5332
|
+
*
|
|
5333
|
+
*/
|
|
5334
|
+
|
|
5335
|
+
function _resourceIsFullDeleted(identifier, cache) {
|
|
5336
|
+
return cache.isDeletionCommitted(identifier) || cache.isNew(identifier) && cache.isDeleted(identifier);
|
|
5337
|
+
}
|
|
5338
|
+
function resourceIsFullyDeleted(instanceCache, identifier) {
|
|
5339
|
+
const cache = instanceCache.cache;
|
|
5340
|
+
return !cache || _resourceIsFullDeleted(identifier, cache);
|
|
5341
|
+
}
|
|
5342
|
+
|
|
5343
|
+
/**
|
|
5344
|
+
A `RecordReference` is a low-level API that allows users and
|
|
5345
|
+
addon authors to perform meta-operations on a record.
|
|
5346
|
+
|
|
5347
|
+
@hideconstructor
|
|
5348
|
+
@public
|
|
5349
|
+
*/
|
|
5350
|
+
class RecordReference {
|
|
5351
|
+
/** @internal */
|
|
5352
|
+
|
|
5353
|
+
// unsubscribe token given to us by the notification manager
|
|
5354
|
+
/** @internal */
|
|
5355
|
+
___token;
|
|
5356
|
+
/** @internal */
|
|
5357
|
+
___identifier;
|
|
5358
|
+
/** @internal */
|
|
5359
|
+
|
|
5360
|
+
constructor(store, identifier) {
|
|
5361
|
+
this.store = store;
|
|
5362
|
+
this.___identifier = identifier;
|
|
5363
|
+
this.___token = store.notifications.subscribe(identifier, (_, bucket, notifiedKey) => {
|
|
5364
|
+
if (bucket === 'identity' || bucket === 'attributes' && notifiedKey === 'id') {
|
|
5365
|
+
this._ref++;
|
|
5366
|
+
}
|
|
5367
|
+
});
|
|
5368
|
+
}
|
|
5369
|
+
|
|
5370
|
+
/** @internal */
|
|
5371
|
+
destroy() {
|
|
5372
|
+
this.store.notifications.unsubscribe(this.___token);
|
|
5373
|
+
}
|
|
5374
|
+
get type() {
|
|
5375
|
+
return this.identifier().type;
|
|
5376
|
+
}
|
|
5377
|
+
|
|
5378
|
+
/**
|
|
5379
|
+
The `id` of the record that this reference refers to.
|
|
5380
|
+
Together, the `type` and `id` properties form a composite key for
|
|
5381
|
+
the identity map.
|
|
5382
|
+
Example
|
|
5383
|
+
```javascript
|
|
5384
|
+
let userRef = store.getReference('user', 1);
|
|
5385
|
+
userRef.id(); // '1'
|
|
5386
|
+
```
|
|
5387
|
+
@public
|
|
5388
|
+
@return The id of the record.
|
|
5389
|
+
*/
|
|
5390
|
+
id() {
|
|
5391
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
5392
|
+
this._ref; // consume the tracked prop
|
|
5393
|
+
return this.___identifier.id;
|
|
5394
|
+
}
|
|
5395
|
+
|
|
5396
|
+
/**
|
|
5397
|
+
The `identifier` of the record that this reference refers to.
|
|
5398
|
+
Together, the `type` and `id` properties form a composite key for
|
|
5399
|
+
the identity map.
|
|
5400
|
+
Example
|
|
5401
|
+
```javascript
|
|
5402
|
+
let userRef = store.getReference('user', 1);
|
|
5403
|
+
userRef.identifier(); // '1'
|
|
5404
|
+
```
|
|
5405
|
+
@public
|
|
5406
|
+
@return The identifier of the record.
|
|
5407
|
+
*/
|
|
5408
|
+
identifier() {
|
|
5409
|
+
return this.___identifier;
|
|
5410
|
+
}
|
|
5411
|
+
|
|
5412
|
+
/**
|
|
5413
|
+
How the reference will be looked up when it is loaded. Currently
|
|
5414
|
+
this always returns `identity` to signify that a record will be
|
|
5415
|
+
loaded by its `type` and `id`.
|
|
5416
|
+
Example
|
|
5417
|
+
```javascript
|
|
5418
|
+
const userRef = store.getReference('user', 1);
|
|
5419
|
+
userRef.remoteType(); // 'identity'
|
|
5420
|
+
```
|
|
5421
|
+
@public
|
|
5422
|
+
*/
|
|
5423
|
+
remoteType() {
|
|
5424
|
+
return 'identity';
|
|
5425
|
+
}
|
|
5426
|
+
|
|
5427
|
+
/**
|
|
5428
|
+
This API allows you to provide a reference with new data. The
|
|
5429
|
+
simplest usage of this API is similar to `store.push`: you provide a
|
|
5430
|
+
normalized hash of data and the object represented by the reference
|
|
5431
|
+
will update.
|
|
5432
|
+
If you pass a promise to `push`, Ember Data will not ask the adapter
|
|
5433
|
+
for the data if another attempt to fetch it is made in the
|
|
5434
|
+
interim. When the promise resolves, the underlying object is updated
|
|
5435
|
+
with the new data, and the promise returned by *this function* is resolved
|
|
5436
|
+
with that object.
|
|
5437
|
+
For example, `recordReference.push(promise)` will be resolved with a
|
|
5438
|
+
record.
|
|
5439
|
+
Example
|
|
5440
|
+
```javascript
|
|
5441
|
+
let userRef = store.getReference('user', 1);
|
|
5442
|
+
// provide data for reference
|
|
5443
|
+
userRef.push({
|
|
5444
|
+
data: {
|
|
5445
|
+
id: "1",
|
|
5446
|
+
type: "user",
|
|
5447
|
+
attributes: {
|
|
5448
|
+
username: "@user"
|
|
5449
|
+
}
|
|
5450
|
+
}
|
|
5451
|
+
}).then(function(user) {
|
|
5452
|
+
userRef.value() === user;
|
|
5453
|
+
});
|
|
5454
|
+
```
|
|
5455
|
+
@public
|
|
5456
|
+
@param objectOrPromise a JSON:API ResourceDocument or a promise resolving to one
|
|
5457
|
+
@return a promise for the value (record or relationship)
|
|
5458
|
+
*/
|
|
5459
|
+
push(objectOrPromise) {
|
|
5460
|
+
// TODO @deprecate pushing unresolved payloads
|
|
5461
|
+
return Promise.resolve(objectOrPromise).then(data => {
|
|
5462
|
+
return this.store.push(data);
|
|
5463
|
+
});
|
|
5464
|
+
}
|
|
5465
|
+
|
|
5466
|
+
/**
|
|
5467
|
+
If the entity referred to by the reference is already loaded, it is
|
|
5468
|
+
present as `reference.value`. Otherwise the value returned by this function
|
|
5469
|
+
is `null`.
|
|
5470
|
+
Example
|
|
5471
|
+
```javascript
|
|
5472
|
+
let userRef = store.getReference('user', 1);
|
|
5473
|
+
userRef.value(); // user
|
|
5474
|
+
```
|
|
5475
|
+
@public
|
|
5476
|
+
@return the record for this RecordReference
|
|
5477
|
+
*/
|
|
5478
|
+
value() {
|
|
5479
|
+
return this.store.peekRecord(this.___identifier);
|
|
5480
|
+
}
|
|
5481
|
+
|
|
5482
|
+
/**
|
|
5483
|
+
Triggers a fetch for the backing entity based on its `remoteType`
|
|
5484
|
+
(see `remoteType` definitions per reference type).
|
|
5485
|
+
Example
|
|
5486
|
+
```javascript
|
|
5487
|
+
let userRef = store.getReference('user', 1);
|
|
5488
|
+
// load user (via store.find)
|
|
5489
|
+
userRef.load().then(...)
|
|
5490
|
+
```
|
|
5491
|
+
@public
|
|
5492
|
+
@return the record for this RecordReference
|
|
5493
|
+
*/
|
|
5494
|
+
load() {
|
|
5495
|
+
const id = this.id();
|
|
5496
|
+
if (id !== null) {
|
|
5497
|
+
return this.store.findRecord(this.type, id);
|
|
5498
|
+
}
|
|
5499
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5500
|
+
{
|
|
5501
|
+
throw new Error(`Unable to fetch record of type ${this.type} without an id`);
|
|
5502
|
+
}
|
|
5503
|
+
})() : {};
|
|
5504
|
+
}
|
|
5505
|
+
|
|
5506
|
+
/**
|
|
5507
|
+
Reloads the record if it is already loaded. If the record is not
|
|
5508
|
+
loaded it will load the record via `store.findRecord`
|
|
5509
|
+
Example
|
|
5510
|
+
```javascript
|
|
5511
|
+
let userRef = store.getReference('user', 1);
|
|
5512
|
+
// or trigger a reload
|
|
5513
|
+
userRef.reload().then(...)
|
|
5514
|
+
```
|
|
5515
|
+
@public
|
|
5516
|
+
@return the record for this RecordReference
|
|
5517
|
+
*/
|
|
5518
|
+
reload() {
|
|
5519
|
+
const id = this.id();
|
|
5520
|
+
if (id !== null) {
|
|
5521
|
+
return this.store.findRecord(this.type, id, {
|
|
5522
|
+
reload: true
|
|
5523
|
+
});
|
|
5524
|
+
}
|
|
5525
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5526
|
+
{
|
|
5527
|
+
throw new Error(`Unable to fetch record of type ${this.type} without an id`);
|
|
5528
|
+
}
|
|
5529
|
+
})() : {};
|
|
5530
|
+
}
|
|
5531
|
+
}
|
|
5532
|
+
defineSignal(RecordReference.prototype, '_ref');
|
|
5533
|
+
|
|
5534
|
+
// if modelFor turns out to be a bottleneck we should replace with a Map
|
|
5535
|
+
// and clear it during store teardown.
|
|
5536
|
+
const AvailableShims = getOrSetGlobal('AvailableShims', new WeakMap());
|
|
5537
|
+
function getShimClass(store, modelName) {
|
|
5538
|
+
let shims = AvailableShims.get(store);
|
|
5539
|
+
if (!shims) {
|
|
5540
|
+
shims = Object.create(null);
|
|
5541
|
+
AvailableShims.set(store, shims);
|
|
5542
|
+
}
|
|
5543
|
+
let shim = shims[modelName];
|
|
5544
|
+
if (shim === undefined) {
|
|
5545
|
+
shim = shims[modelName] = new ShimModelClass(store, modelName);
|
|
5546
|
+
}
|
|
5547
|
+
return shim;
|
|
5548
|
+
}
|
|
5549
|
+
|
|
5550
|
+
// Mimics the static apis of @ember-data/model
|
|
5551
|
+
class ShimModelClass {
|
|
5552
|
+
constructor(store, modelName) {
|
|
5553
|
+
this.__store = store;
|
|
5554
|
+
this.modelName = modelName;
|
|
5555
|
+
}
|
|
5556
|
+
get fields() {
|
|
5557
|
+
const fields = new Map();
|
|
5558
|
+
const fieldSchemas = this.__store.schema.fields({
|
|
5559
|
+
type: this.modelName
|
|
5560
|
+
});
|
|
5561
|
+
fieldSchemas.forEach((schema, key) => {
|
|
5562
|
+
if (schema.kind === 'attribute' || schema.kind === 'belongsTo' || schema.kind === 'hasMany') {
|
|
5563
|
+
fields.set(key, schema.kind);
|
|
5564
|
+
}
|
|
5565
|
+
});
|
|
5566
|
+
return fields;
|
|
5567
|
+
}
|
|
5568
|
+
get attributes() {
|
|
5569
|
+
const attrs = new Map();
|
|
5570
|
+
const fields = this.__store.schema.fields({
|
|
5571
|
+
type: this.modelName
|
|
5572
|
+
});
|
|
5573
|
+
fields.forEach((schema, key) => {
|
|
5574
|
+
if (schema.kind === 'attribute') {
|
|
5575
|
+
attrs.set(key, schema);
|
|
5576
|
+
}
|
|
5577
|
+
});
|
|
5578
|
+
return attrs;
|
|
5579
|
+
}
|
|
5580
|
+
get relationshipsByName() {
|
|
5581
|
+
const rels = new Map();
|
|
5582
|
+
const fields = this.__store.schema.fields({
|
|
5583
|
+
type: this.modelName
|
|
5584
|
+
});
|
|
5585
|
+
fields.forEach((schema, key) => {
|
|
5586
|
+
if (schema.kind === 'belongsTo' || schema.kind === 'hasMany') {
|
|
5587
|
+
rels.set(key, schema);
|
|
5588
|
+
}
|
|
5589
|
+
});
|
|
5590
|
+
return rels;
|
|
5591
|
+
}
|
|
5592
|
+
eachAttribute(callback, binding) {
|
|
5593
|
+
this.__store.schema.fields({
|
|
5594
|
+
type: this.modelName
|
|
5595
|
+
}).forEach((schema, key) => {
|
|
5596
|
+
if (schema.kind === 'attribute') {
|
|
5597
|
+
callback.call(binding, key, schema);
|
|
5598
|
+
}
|
|
5599
|
+
});
|
|
5600
|
+
}
|
|
5601
|
+
eachRelationship(callback, binding) {
|
|
5602
|
+
this.__store.schema.fields({
|
|
5603
|
+
type: this.modelName
|
|
5604
|
+
}).forEach((schema, key) => {
|
|
5605
|
+
if (schema.kind === 'belongsTo' || schema.kind === 'hasMany') {
|
|
5606
|
+
callback.call(binding, key, schema);
|
|
5607
|
+
}
|
|
5608
|
+
});
|
|
5609
|
+
}
|
|
5610
|
+
eachTransformedAttribute(callback, binding) {
|
|
5611
|
+
this.__store.schema.fields({
|
|
5612
|
+
type: this.modelName
|
|
5613
|
+
}).forEach((schema, key) => {
|
|
5614
|
+
if (schema.kind === 'attribute') {
|
|
5615
|
+
const type = schema.type;
|
|
5616
|
+
if (type) callback.call(binding, key, type);
|
|
5617
|
+
}
|
|
5618
|
+
});
|
|
5619
|
+
}
|
|
5620
|
+
}
|
|
5621
|
+
if (macroCondition(getGlobalConfig().WarpDrive.deprecations.ENABLE_LEGACY_REQUEST_METHODS)) {
|
|
5622
|
+
Store.prototype.findRecord = function (resource, id, options) {
|
|
5623
|
+
deprecate(`store.findRecord is deprecated. Use store.request instead.`, false, {
|
|
5624
|
+
id: 'warp-drive:deprecate-legacy-request-methods',
|
|
5625
|
+
until: '6.0',
|
|
5626
|
+
for: '@warp-drive/core',
|
|
5627
|
+
url: 'https://docs.warp-drive.io/api/@warp-drive/core/build-config/deprecations/variables/ENABLE_LEGACY_REQUEST_METHODS',
|
|
5628
|
+
since: {
|
|
5629
|
+
enabled: '5.7',
|
|
5630
|
+
available: '5.7'
|
|
5631
|
+
}
|
|
5632
|
+
});
|
|
5633
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5634
|
+
if (!test) {
|
|
5635
|
+
throw new Error(`Attempted to call store.findRecord(), but the store instance has already been destroyed.`);
|
|
5636
|
+
}
|
|
5637
|
+
})(!(this.isDestroying || this.isDestroyed)) : {};
|
|
5638
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5639
|
+
if (!test) {
|
|
5640
|
+
throw new Error(`You need to pass a modelName or resource identifier as the first argument to the store's findRecord method`);
|
|
5641
|
+
}
|
|
5642
|
+
})(resource) : {};
|
|
5643
|
+
if (isMaybeIdentifier(resource)) {
|
|
5644
|
+
options = id;
|
|
5645
|
+
} else {
|
|
5646
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5647
|
+
if (!test) {
|
|
5648
|
+
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${resource}`);
|
|
5649
|
+
}
|
|
5650
|
+
})(typeof resource === 'string') : {};
|
|
5651
|
+
const type = normalizeModelName(resource);
|
|
5652
|
+
const normalizedId = ensureStringId(id);
|
|
5653
|
+
resource = constructResource(type, normalizedId);
|
|
5654
|
+
}
|
|
5655
|
+
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resource);
|
|
5656
|
+
options = options || {};
|
|
5657
|
+
if (options.preload) {
|
|
5658
|
+
// force reload if we preload to ensure we don't resolve the promise
|
|
5659
|
+
// until we are complete, else we will end up background-reloading
|
|
5660
|
+
// even for initial load.
|
|
5661
|
+
if (!this._instanceCache.recordIsLoaded(identifier)) {
|
|
5662
|
+
options.reload = true;
|
|
5663
|
+
}
|
|
5664
|
+
this._join(() => {
|
|
5665
|
+
preloadData(this, identifier, options.preload);
|
|
5666
|
+
});
|
|
5667
|
+
}
|
|
5668
|
+
const promise = this.request({
|
|
5669
|
+
op: 'findRecord',
|
|
5670
|
+
data: {
|
|
5671
|
+
record: identifier,
|
|
5672
|
+
options
|
|
5673
|
+
},
|
|
5674
|
+
cacheOptions: {
|
|
5675
|
+
[SkipCache]: true
|
|
5676
|
+
}
|
|
5677
|
+
});
|
|
5678
|
+
return promise.then(document => {
|
|
5679
|
+
return document.content;
|
|
5680
|
+
});
|
|
5681
|
+
};
|
|
5682
|
+
Store.prototype.findAll = function (type, options = {}) {
|
|
5683
|
+
deprecate(`store.findAll is deprecated. Use store.request instead.`, false, {
|
|
5684
|
+
id: 'warp-drive:deprecate-legacy-request-methods',
|
|
5685
|
+
until: '6.0',
|
|
5686
|
+
for: '@warp-drive/core',
|
|
5687
|
+
url: 'https://docs.warp-drive.io/api/@warp-drive/core/build-config/deprecations/variables/ENABLE_LEGACY_REQUEST_METHODS',
|
|
5688
|
+
since: {
|
|
5689
|
+
enabled: '5.7',
|
|
5690
|
+
available: '5.7'
|
|
5691
|
+
}
|
|
5692
|
+
});
|
|
5693
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5694
|
+
if (!test) {
|
|
5695
|
+
throw new Error(`Attempted to call store.findAll(), but the store instance has already been destroyed.`);
|
|
5696
|
+
}
|
|
5697
|
+
})(!(this.isDestroying || this.isDestroyed)) : {};
|
|
5698
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5699
|
+
if (!test) {
|
|
5700
|
+
throw new Error(`You need to pass a model name to the store's findAll method`);
|
|
5701
|
+
}
|
|
5702
|
+
})(type) : {};
|
|
5703
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5704
|
+
if (!test) {
|
|
5705
|
+
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${type}`);
|
|
5706
|
+
}
|
|
5707
|
+
})(typeof type === 'string') : {};
|
|
5708
|
+
const promise = this.request({
|
|
5709
|
+
op: 'findAll',
|
|
5710
|
+
data: {
|
|
5711
|
+
type: normalizeModelName(type),
|
|
5712
|
+
options: options || {}
|
|
5713
|
+
},
|
|
5714
|
+
cacheOptions: {
|
|
5715
|
+
[SkipCache]: true
|
|
5716
|
+
}
|
|
5717
|
+
});
|
|
5718
|
+
return promise.then(document => document.content);
|
|
5719
|
+
};
|
|
5720
|
+
Store.prototype.query = function (type, query, options = {}) {
|
|
5721
|
+
deprecate(`store.query is deprecated. Use store.request instead.`, false, {
|
|
5722
|
+
id: 'warp-drive:deprecate-legacy-request-methods',
|
|
5723
|
+
until: '6.0',
|
|
5724
|
+
for: '@warp-drive/core',
|
|
5725
|
+
url: 'https://docs.warp-drive.io/api/@warp-drive/core/build-config/deprecations/variables/ENABLE_LEGACY_REQUEST_METHODS',
|
|
5726
|
+
since: {
|
|
5727
|
+
enabled: '5.7',
|
|
5728
|
+
available: '5.7'
|
|
5729
|
+
}
|
|
5730
|
+
});
|
|
5731
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5732
|
+
if (!test) {
|
|
5733
|
+
throw new Error(`Attempted to call store.query(), but the store instance has already been destroyed.`);
|
|
5734
|
+
}
|
|
5735
|
+
})(!(this.isDestroying || this.isDestroyed)) : {};
|
|
5736
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5737
|
+
if (!test) {
|
|
5738
|
+
throw new Error(`You need to pass a model name to the store's query method`);
|
|
5739
|
+
}
|
|
5740
|
+
})(type) : {};
|
|
5741
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5742
|
+
if (!test) {
|
|
5743
|
+
throw new Error(`You need to pass a query hash to the store's query method`);
|
|
5744
|
+
}
|
|
5745
|
+
})(query) : {};
|
|
5746
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5747
|
+
if (!test) {
|
|
5748
|
+
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${type}`);
|
|
5749
|
+
}
|
|
5750
|
+
})(typeof type === 'string') : {};
|
|
5751
|
+
const promise = this.request({
|
|
5752
|
+
op: 'query',
|
|
5753
|
+
data: {
|
|
5754
|
+
type: normalizeModelName(type),
|
|
5755
|
+
query,
|
|
5756
|
+
options: options
|
|
5757
|
+
},
|
|
5758
|
+
cacheOptions: {
|
|
5759
|
+
[SkipCache]: true
|
|
5760
|
+
}
|
|
5761
|
+
});
|
|
5762
|
+
return promise.then(document => document.content);
|
|
5763
|
+
};
|
|
5764
|
+
Store.prototype.queryRecord = function (type, query, options) {
|
|
5765
|
+
deprecate(`store.queryRecord is deprecated. Use store.request instead.`, false, {
|
|
5766
|
+
id: 'warp-drive:deprecate-legacy-request-methods',
|
|
5767
|
+
until: '6.0',
|
|
5768
|
+
for: '@warp-drive/core',
|
|
5769
|
+
url: 'https://docs.warp-drive.io/api/@warp-drive/core/build-config/deprecations/variables/ENABLE_LEGACY_REQUEST_METHODS',
|
|
5770
|
+
since: {
|
|
5771
|
+
enabled: '5.7',
|
|
5772
|
+
available: '5.7'
|
|
5773
|
+
}
|
|
5774
|
+
});
|
|
5775
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5776
|
+
if (!test) {
|
|
5777
|
+
throw new Error(`Attempted to call store.queryRecord(), but the store instance has already been destroyed.`);
|
|
5778
|
+
}
|
|
5779
|
+
})(!(this.isDestroying || this.isDestroyed)) : {};
|
|
5780
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5781
|
+
if (!test) {
|
|
5782
|
+
throw new Error(`You need to pass a model name to the store's queryRecord method`);
|
|
5783
|
+
}
|
|
5784
|
+
})(type) : {};
|
|
5785
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5786
|
+
if (!test) {
|
|
5787
|
+
throw new Error(`You need to pass a query hash to the store's queryRecord method`);
|
|
5788
|
+
}
|
|
5789
|
+
})(query) : {};
|
|
5790
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5791
|
+
if (!test) {
|
|
5792
|
+
throw new Error(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${type}`);
|
|
5793
|
+
}
|
|
5794
|
+
})(typeof type === 'string') : {};
|
|
5795
|
+
const promise = this.request({
|
|
5796
|
+
op: 'queryRecord',
|
|
5797
|
+
data: {
|
|
5798
|
+
type: normalizeModelName(type),
|
|
5799
|
+
query,
|
|
5800
|
+
options: options || {}
|
|
5801
|
+
},
|
|
5802
|
+
cacheOptions: {
|
|
5803
|
+
[SkipCache]: true
|
|
5804
|
+
}
|
|
5805
|
+
});
|
|
5806
|
+
return promise.then(document => document.content);
|
|
5807
|
+
};
|
|
5808
|
+
Store.prototype.getReference = function (resource, id) {
|
|
5809
|
+
deprecate(`store.getReference is deprecated. There is no direct replacement. For working with the cache and relationships, use the cache with the appropriate identifiers. To load, use store.request.`, false, {
|
|
5810
|
+
id: 'warp-drive:deprecate-legacy-request-methods',
|
|
5811
|
+
until: '6.0',
|
|
5812
|
+
for: '@warp-drive/core',
|
|
5813
|
+
url: 'https://docs.warp-drive.io/api/@warp-drive/core/build-config/deprecations/variables/ENABLE_LEGACY_REQUEST_METHODS',
|
|
5814
|
+
since: {
|
|
5815
|
+
enabled: '5.7',
|
|
5816
|
+
available: '5.7'
|
|
5817
|
+
}
|
|
5818
|
+
});
|
|
5819
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5820
|
+
if (!test) {
|
|
5821
|
+
throw new Error(`Attempted to call store.getReference(), but the store instance has already been destroyed.`);
|
|
5822
|
+
}
|
|
5823
|
+
})(!(this.isDestroying || this.isDestroyed)) : {};
|
|
5824
|
+
let resourceIdentifier;
|
|
5825
|
+
if (arguments.length === 1 && isMaybeIdentifier(resource)) {
|
|
5826
|
+
resourceIdentifier = resource;
|
|
5827
|
+
} else {
|
|
5828
|
+
const type = normalizeModelName(resource);
|
|
5829
|
+
const normalizedId = ensureStringId(id);
|
|
5830
|
+
resourceIdentifier = constructResource(type, normalizedId);
|
|
5831
|
+
}
|
|
5832
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5833
|
+
if (!test) {
|
|
5834
|
+
throw new Error('getReference expected to receive either a resource identifier or type and id as arguments');
|
|
5835
|
+
}
|
|
5836
|
+
})(isMaybeIdentifier(resourceIdentifier)) : {};
|
|
5837
|
+
const identifier = this.identifierCache.getOrCreateRecordIdentifier(resourceIdentifier);
|
|
5838
|
+
const cache = upgradeInstanceCaches(this._instanceCache.__instances).reference;
|
|
5839
|
+
let reference = cache.get(identifier);
|
|
5840
|
+
if (!reference) {
|
|
5841
|
+
reference = new RecordReference(this, identifier);
|
|
5842
|
+
cache.set(identifier, reference);
|
|
5843
|
+
}
|
|
5844
|
+
return reference;
|
|
5845
|
+
};
|
|
5846
|
+
Store.prototype.modelFor = function (type) {
|
|
5847
|
+
deprecate(`store.modelFor is deprecated, please use store.schema.fields({ type: '${type}' }) to access schema information instead.`, false, {
|
|
5848
|
+
id: 'warp-drive:deprecate-legacy-request-methods',
|
|
5849
|
+
until: '6.0',
|
|
5850
|
+
for: '@warp-drive/core',
|
|
5851
|
+
url: 'https://docs.warp-drive.io/api/@warp-drive/core/build-config/deprecations/variables/ENABLE_LEGACY_REQUEST_METHODS',
|
|
5852
|
+
since: {
|
|
5853
|
+
enabled: '5.7',
|
|
5854
|
+
available: '5.7'
|
|
5855
|
+
}
|
|
5856
|
+
});
|
|
5857
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5858
|
+
if (!test) {
|
|
5859
|
+
throw new Error(`Attempted to call store.modelFor(), but the store instance has already been destroyed.`);
|
|
5860
|
+
}
|
|
5861
|
+
})(!this.isDestroyed) : {};
|
|
5862
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5863
|
+
if (!test) {
|
|
5864
|
+
throw new Error(`You need to pass <type> to the store's modelFor method`);
|
|
5865
|
+
}
|
|
5866
|
+
})(typeof type === 'string' && type.length) : {};
|
|
5867
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5868
|
+
if (!test) {
|
|
5869
|
+
throw new Error(`No model was found for '${type}' and no schema handles the type`);
|
|
5870
|
+
}
|
|
5871
|
+
})(this.schema.hasResource({
|
|
5872
|
+
type
|
|
5873
|
+
})) : {};
|
|
5874
|
+
return getShimClass(this, type);
|
|
5875
|
+
};
|
|
5876
|
+
Store.prototype.saveRecord = function (record, options = {}) {
|
|
5877
|
+
deprecate(`store.saveRecord is deprecated, please use store.request to initiate a save request instead.`, false, {
|
|
5878
|
+
id: 'warp-drive:deprecate-legacy-request-methods',
|
|
5879
|
+
until: '6.0',
|
|
5880
|
+
for: '@warp-drive/core',
|
|
5881
|
+
url: 'https://docs.warp-drive.io/api/@warp-drive/core/build-config/deprecations/variables/ENABLE_LEGACY_REQUEST_METHODS',
|
|
5882
|
+
since: {
|
|
5883
|
+
enabled: '5.7',
|
|
5884
|
+
available: '5.7'
|
|
5885
|
+
}
|
|
5886
|
+
});
|
|
5887
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5888
|
+
if (!test) {
|
|
5889
|
+
throw new Error(`Attempted to call store.saveRecord(), but the store instance has already been destroyed.`);
|
|
5890
|
+
}
|
|
5891
|
+
})(!(this.isDestroying || this.isDestroyed)) : {};
|
|
5892
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5893
|
+
if (!test) {
|
|
5894
|
+
throw new Error(`Unable to initiate save for a record in a disconnected state`);
|
|
5895
|
+
}
|
|
5896
|
+
})(storeFor(record)) : {};
|
|
5897
|
+
const identifier = recordIdentifierFor(record);
|
|
5898
|
+
const cache = this.cache;
|
|
5899
|
+
if (!identifier) {
|
|
5900
|
+
// this commonly means we're disconnected
|
|
5901
|
+
// but just in case we reject here to prevent bad things.
|
|
5902
|
+
return Promise.reject(new Error(`Record Is Disconnected`));
|
|
5903
|
+
}
|
|
5904
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5905
|
+
if (!test) {
|
|
5906
|
+
throw new Error(`Cannot initiate a save request for an unloaded record: ${identifier.lid}`);
|
|
5907
|
+
}
|
|
5908
|
+
})(this._instanceCache.recordIsLoaded(identifier)) : {};
|
|
5909
|
+
if (resourceIsFullyDeleted(this._instanceCache, identifier)) {
|
|
5910
|
+
return Promise.resolve(record);
|
|
5911
|
+
}
|
|
5912
|
+
if (!options) {
|
|
5913
|
+
options = {};
|
|
5914
|
+
}
|
|
5915
|
+
let operation = 'updateRecord';
|
|
5916
|
+
if (cache.isNew(identifier)) {
|
|
5917
|
+
operation = 'createRecord';
|
|
5918
|
+
} else if (cache.isDeleted(identifier)) {
|
|
5919
|
+
operation = 'deleteRecord';
|
|
5920
|
+
}
|
|
5921
|
+
const request = {
|
|
5922
|
+
op: operation,
|
|
5923
|
+
data: {
|
|
5924
|
+
options,
|
|
5925
|
+
record: identifier
|
|
5926
|
+
},
|
|
5927
|
+
records: [identifier],
|
|
5928
|
+
cacheOptions: {
|
|
5929
|
+
[SkipCache]: true
|
|
5930
|
+
}
|
|
5931
|
+
};
|
|
5932
|
+
return this.request(request).then(document => document.content);
|
|
5933
|
+
};
|
|
5934
|
+
}
|
|
5935
|
+
function upgradeInstanceCaches(cache) {
|
|
5936
|
+
const withReferences = cache;
|
|
5937
|
+
if (!withReferences.reference) {
|
|
5938
|
+
withReferences.reference = new WeakMap();
|
|
5939
|
+
}
|
|
5940
|
+
return withReferences;
|
|
5941
|
+
}
|
|
5942
|
+
function isNonEmptyString(str) {
|
|
5943
|
+
return Boolean(str && typeof str === 'string');
|
|
5944
|
+
}
|
|
5945
|
+
function constructResource(type, id, lid) {
|
|
5946
|
+
if (typeof type === 'object' && type !== null) {
|
|
5947
|
+
const resource = type;
|
|
5948
|
+
if (isStableIdentifier(resource)) {
|
|
5949
|
+
return resource;
|
|
5950
|
+
}
|
|
5951
|
+
if ('id' in resource) {
|
|
5952
|
+
resource.id = coerceId(resource.id);
|
|
5953
|
+
}
|
|
5954
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5955
|
+
if (!test) {
|
|
5956
|
+
throw new Error('Expected either id or lid to be a valid string');
|
|
5957
|
+
}
|
|
5958
|
+
})('id' in resource && isNonEmptyString(resource.id) || isNonEmptyString(resource.lid)) : {};
|
|
5959
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5960
|
+
if (!test) {
|
|
5961
|
+
throw new Error('if id is present, the type must be a string');
|
|
5962
|
+
}
|
|
5963
|
+
})(!('id' in resource) || typeof resource.type === 'string') : {};
|
|
5964
|
+
return resource;
|
|
5965
|
+
} else {
|
|
5966
|
+
const trueId = coerceId(id);
|
|
5967
|
+
if (!isNonEmptyString(trueId)) {
|
|
5968
|
+
if (isNonEmptyString(lid)) {
|
|
5969
|
+
return {
|
|
5970
|
+
lid
|
|
5971
|
+
};
|
|
5972
|
+
}
|
|
5973
|
+
throw new Error('Expected either id or lid to be a valid string');
|
|
5974
|
+
}
|
|
5975
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
5976
|
+
if (!test) {
|
|
5977
|
+
throw new Error('type must be a string');
|
|
5978
|
+
}
|
|
5979
|
+
})(typeof type === 'string') : {};
|
|
5980
|
+
if (isNonEmptyString(lid)) {
|
|
5981
|
+
return {
|
|
5982
|
+
type,
|
|
5983
|
+
id: trueId,
|
|
5984
|
+
lid
|
|
5985
|
+
};
|
|
5986
|
+
}
|
|
5987
|
+
return {
|
|
5988
|
+
type,
|
|
5989
|
+
id: trueId
|
|
5990
|
+
};
|
|
5991
|
+
}
|
|
5992
|
+
}
|
|
6490
5993
|
function _MUTATE(target, receiver, prop, args, _SIGNAL) {
|
|
6491
5994
|
const collection = receiver;
|
|
6492
5995
|
switch (prop) {
|
|
@@ -8136,4 +7639,4 @@ function getRequestState(future) {
|
|
|
8136
7639
|
}
|
|
8137
7640
|
return state;
|
|
8138
7641
|
}
|
|
8139
|
-
export {
|
|
7642
|
+
export { defineNonEnumerableSignal as A, Signals as B, Collection as C, DISPOSE as D, peekInternalSignal as E, withSignalStore as F, notifyInternalSignal as G, consumeInternalSignal as H, IdentifierArray as I, getOrCreateInternalSignal as J, ReactiveDocument as K, setIdentifierGenerationMethod as L, MUTATE as M, setIdentifierUpdateMethod as N, setIdentifierForgetMethod as O, setIdentifierResetMethod as P, setKeyInfoForResource as Q, RecordArrayManager as R, Store as S, isExtensionProp as T, performExtensionSet as U, performArrayExtensionGet as V, performObjectExtensionGet as W, _clearCaches as _, isDocumentIdentifier as a, coerceId as b, constructResource as c, SOURCE as d, ensureStringId as e, fastPush as f, removeRecordDataFor as g, setRecordIdentifier as h, isStableIdentifier as i, StoreMap as j, setCacheFor as k, RelatedCollection as l, log as m, normalizeModelName as n, logGroup as o, peekCache as p, getPromiseState as q, recordIdentifierFor as r, storeFor as s, createRequestSubscription as t, getRequestState as u, memoized as v, gate as w, entangleSignal as x, defineSignal as y, defineGate as z };
|