@ember-data/store 5.4.1-beta.0 → 5.4.1-beta.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/dist/-private.js +2 -1
- package/dist/-private.js.map +1 -1
- package/dist/configure-BfLLW6GY.js +161 -0
- package/dist/configure-BfLLW6GY.js.map +1 -0
- package/dist/configure.js +1 -0
- package/dist/configure.js.map +1 -0
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/{many-array-BwVo-2vv.js → request-state-uRtpn0Lc.js} +919 -129
- package/dist/request-state-uRtpn0Lc.js.map +1 -0
- package/package.json +19 -11
- package/unstable-preview-types/-private/cache-handler/types.d.ts +2 -2
- package/unstable-preview-types/-private/document.d.ts +9 -9
- package/unstable-preview-types/-private/document.d.ts.map +1 -1
- package/unstable-preview-types/-private/legacy-model-support/record-reference.d.ts.map +1 -1
- package/unstable-preview-types/-private/managers/cache-manager.d.ts +7 -7
- package/unstable-preview-types/-private/managers/notification-manager.d.ts.map +1 -1
- package/unstable-preview-types/-private/managers/record-array-manager.d.ts.map +1 -1
- package/unstable-preview-types/-private/network/request-cache.d.ts +8 -8
- package/unstable-preview-types/-private/network/request-cache.d.ts.map +1 -1
- package/unstable-preview-types/-private/new-core-tmp/promise-state.d.ts +289 -0
- package/unstable-preview-types/-private/new-core-tmp/promise-state.d.ts.map +1 -0
- package/unstable-preview-types/-private/new-core-tmp/reactivity/configure.d.ts +92 -0
- package/unstable-preview-types/-private/new-core-tmp/reactivity/configure.d.ts.map +1 -0
- package/unstable-preview-types/-private/new-core-tmp/reactivity/internal.d.ts +172 -0
- package/unstable-preview-types/-private/new-core-tmp/reactivity/internal.d.ts.map +1 -0
- package/unstable-preview-types/-private/new-core-tmp/reactivity/signal.d.ts +32 -0
- package/unstable-preview-types/-private/new-core-tmp/reactivity/signal.d.ts.map +1 -0
- package/unstable-preview-types/-private/new-core-tmp/request-state.d.ts +276 -0
- package/unstable-preview-types/-private/new-core-tmp/request-state.d.ts.map +1 -0
- package/unstable-preview-types/-private/record-arrays/identifier-array.d.ts +4 -9
- package/unstable-preview-types/-private/record-arrays/identifier-array.d.ts.map +1 -1
- package/unstable-preview-types/-private/record-arrays/many-array.d.ts +10 -6
- package/unstable-preview-types/-private/record-arrays/many-array.d.ts.map +1 -1
- package/unstable-preview-types/-private/store-service.d.ts +21 -15
- package/unstable-preview-types/-private/store-service.d.ts.map +1 -1
- package/unstable-preview-types/-private.d.ts +7 -2
- package/unstable-preview-types/-private.d.ts.map +1 -1
- package/unstable-preview-types/-types/q/cache-capabilities-manager.d.ts +4 -3
- package/unstable-preview-types/-types/q/cache-capabilities-manager.d.ts.map +1 -1
- package/unstable-preview-types/-types/q/schema-service.d.ts +36 -48
- package/unstable-preview-types/-types/q/schema-service.d.ts.map +1 -1
- package/unstable-preview-types/configure.d.ts +21 -0
- package/unstable-preview-types/configure.d.ts.map +1 -0
- package/unstable-preview-types/index.d.ts +35 -29
- package/unstable-preview-types/index.d.ts.map +1 -1
- package/dist/many-array-BwVo-2vv.js.map +0 -1
|
@@ -3,11 +3,10 @@ import { macroCondition, getGlobalConfig, dependencySatisfies, importSync } from
|
|
|
3
3
|
import { EnableHydration, SkipCache } from '@warp-drive/core-types/request';
|
|
4
4
|
import { setLogging, getRuntimeConfig } from '@warp-drive/core-types/runtime';
|
|
5
5
|
import { getOrSetGlobal, peekTransient, setTransient } from '@warp-drive/core-types/-private';
|
|
6
|
-
import {
|
|
7
|
-
import { defineSubscription, notifySignal, defineSignal, createSignal, subscribe, createArrayTags, addToTransaction, addTransactionCB } from '@ember-data/tracking/-private';
|
|
6
|
+
import { a as createSignal, b as consumeSignal, n as notifySignal, c as createMemo, w as willSyncFlushWatchers, A as ARRAY_SIGNAL } from "./configure-BfLLW6GY.js";
|
|
8
7
|
import { CACHE_OWNER, DEBUG_STALE_CACHE_OWNER, DEBUG_IDENTIFIER_BUCKET, DEBUG_CLIENT_ORIGINATED } from '@warp-drive/core-types/identifier';
|
|
9
8
|
import { dasherize } from '@ember-data/request-utils/string';
|
|
10
|
-
import {
|
|
9
|
+
import { getPromiseResult, setPromiseResult } from '@ember-data/request';
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
12
|
@module @ember-data/store
|
|
@@ -902,9 +901,245 @@ function _log(scope, prefix, subScop1, subScop2, subScop3, subScop4) {
|
|
|
902
901
|
return [];
|
|
903
902
|
}
|
|
904
903
|
|
|
904
|
+
/**
|
|
905
|
+
* A WarpDriveSignal is a wrapper around a framework specific or TC39 signal
|
|
906
|
+
* that enables us to store and manage the signal in a universal way.
|
|
907
|
+
*
|
|
908
|
+
* WarpDrive uses signals to manage three separate concepts:
|
|
909
|
+
*
|
|
910
|
+
* - as a `storage` for a value local to the object that we want to be reactive
|
|
911
|
+
* (see `@local` schema field for an example)
|
|
912
|
+
* - as a `gate` for a memoized getter that we want to act as a reactive property
|
|
913
|
+
* but whose value is computed/pulled from a non-reactive source elsewhere
|
|
914
|
+
* and whose latest value is stored in the signal
|
|
915
|
+
* (see `field` schema field for an example)
|
|
916
|
+
* - as a `gate` with a manually managed value updated on pull when `isStale` is true
|
|
917
|
+
*
|
|
918
|
+
*
|
|
919
|
+
* It offers
|
|
920
|
+
*
|
|
921
|
+
* - a non-reactive way to access/update the current value
|
|
922
|
+
* - a non-reactive way to mark the signal as dirtied
|
|
923
|
+
* - a non-reactive way to store content for why the signal was dirtied
|
|
924
|
+
* - access to the underlying Signal(s) in-use
|
|
925
|
+
*
|
|
926
|
+
* For debugging:
|
|
927
|
+
* - the "key" or "name" of the signal
|
|
928
|
+
* - the "object identity" or "context" to which the signal is attached
|
|
929
|
+
*
|
|
930
|
+
* @internal
|
|
931
|
+
*/
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* We attach signals to their context object via
|
|
935
|
+
* a Map attached to the object via this symbol.
|
|
936
|
+
*
|
|
937
|
+
* This allows us to store multiple signals
|
|
938
|
+
* on the same object with smaller memory
|
|
939
|
+
* overhead and no WeakMap lookups.
|
|
940
|
+
*
|
|
941
|
+
* Performance sensitive objects should
|
|
942
|
+
* pre-warm their shape by assigning this
|
|
943
|
+
* during initialization.
|
|
944
|
+
*
|
|
945
|
+
* ```ts
|
|
946
|
+
* initializeSignalStore(obj);
|
|
947
|
+
* ```
|
|
948
|
+
*
|
|
949
|
+
* @internal
|
|
950
|
+
*/
|
|
951
|
+
const Signals = getOrSetGlobal('Signals', Symbol('Signals'));
|
|
952
|
+
|
|
953
|
+
/**
|
|
954
|
+
* A util that will create a signal store on the object
|
|
955
|
+
* if it does not already exist and returns the associated
|
|
956
|
+
* signal store.
|
|
957
|
+
*
|
|
958
|
+
* @internal
|
|
959
|
+
*/
|
|
960
|
+
function withSignalStore(obj) {
|
|
961
|
+
if (obj[Signals] === undefined) {
|
|
962
|
+
initializeSignalStore(obj);
|
|
963
|
+
}
|
|
964
|
+
return obj[Signals];
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* A util that will create a signal store on the object
|
|
969
|
+
* if it does not already exist.
|
|
970
|
+
*
|
|
971
|
+
* Useful for pre-warming the shape of an object to ensure
|
|
972
|
+
* a key-transition to add it is not required later.
|
|
973
|
+
*
|
|
974
|
+
* @internal
|
|
975
|
+
*/
|
|
976
|
+
function initializeSignalStore(obj) {
|
|
977
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
978
|
+
if (!test) {
|
|
979
|
+
throw new Error(`Signal store already exists on object`);
|
|
980
|
+
}
|
|
981
|
+
})(obj[Signals] === undefined) : {};
|
|
982
|
+
obj[Signals] = new Map();
|
|
983
|
+
}
|
|
984
|
+
function createInternalSignal(signals, obj, key, initialValue) {
|
|
985
|
+
const warpDriveSignal = {
|
|
986
|
+
key,
|
|
987
|
+
context: obj,
|
|
988
|
+
signal: createSignal(obj, key),
|
|
989
|
+
value: initialValue,
|
|
990
|
+
isStale: false
|
|
991
|
+
};
|
|
992
|
+
signals.set(key, warpDriveSignal);
|
|
993
|
+
return warpDriveSignal;
|
|
994
|
+
}
|
|
995
|
+
function getOrCreateInternalSignal(signals, obj, key, initialValue) {
|
|
996
|
+
let signal = peekInternalSignal(signals, key);
|
|
997
|
+
if (!signal) {
|
|
998
|
+
signal = createInternalSignal(signals, obj, key, initialValue);
|
|
999
|
+
}
|
|
1000
|
+
return signal;
|
|
1001
|
+
}
|
|
1002
|
+
function peekInternalSignal(signals, key) {
|
|
1003
|
+
return signals?.get(key);
|
|
1004
|
+
}
|
|
1005
|
+
function consumeInternalSignal(signal) {
|
|
1006
|
+
consumeSignal(signal.signal);
|
|
1007
|
+
}
|
|
1008
|
+
function notifyInternalSignal(signal) {
|
|
1009
|
+
if (signal) {
|
|
1010
|
+
signal.isStale = true;
|
|
1011
|
+
notifySignal(signal.signal);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
function entangleSignal(signals, obj, key, initialValue) {
|
|
1015
|
+
let signal = peekInternalSignal(signals, key);
|
|
1016
|
+
if (!signal) {
|
|
1017
|
+
signal = createInternalSignal(signals, obj, key, initialValue);
|
|
1018
|
+
}
|
|
1019
|
+
consumeInternalSignal(signal);
|
|
1020
|
+
return signal;
|
|
1021
|
+
}
|
|
1022
|
+
function createSignalDescriptor(key, intialValue) {
|
|
1023
|
+
return {
|
|
1024
|
+
enumerable: true,
|
|
1025
|
+
configurable: false,
|
|
1026
|
+
get() {
|
|
1027
|
+
const signals = withSignalStore(this);
|
|
1028
|
+
return entangleSignal(signals, this, key, intialValue).value;
|
|
1029
|
+
},
|
|
1030
|
+
set(value) {
|
|
1031
|
+
const signals = withSignalStore(this);
|
|
1032
|
+
const signal = getOrCreateInternalSignal(signals, this, key, intialValue);
|
|
1033
|
+
if (signal.value !== value) {
|
|
1034
|
+
signal.value = value;
|
|
1035
|
+
notifyInternalSignal(signal);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* define an enumerable signal property.
|
|
1043
|
+
*
|
|
1044
|
+
* Akin to Object.defineProperty.
|
|
1045
|
+
*
|
|
1046
|
+
* The signal will be lazily created when accessed and scoped to the
|
|
1047
|
+
* instance of the object.
|
|
1048
|
+
*
|
|
1049
|
+
* @internal
|
|
1050
|
+
*/
|
|
1051
|
+
function defineSignal(obj, key, v) {
|
|
1052
|
+
Object.defineProperty(obj, key, createSignalDescriptor(key, v));
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
/**
|
|
1056
|
+
* Define a non-enumerable signal property.
|
|
1057
|
+
*
|
|
1058
|
+
* @internal
|
|
1059
|
+
*/
|
|
1060
|
+
function defineNonEnumerableSignal(obj, key, v) {
|
|
1061
|
+
const desc = createSignalDescriptor(key, v);
|
|
1062
|
+
desc.enumerable = false;
|
|
1063
|
+
Object.defineProperty(obj, key, desc);
|
|
1064
|
+
}
|
|
1065
|
+
function memoized(target, key, descriptor) {
|
|
1066
|
+
// Error on `@memoized()`, `@memoized(...args)`, and `@memoized propName = value;`
|
|
1067
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1068
|
+
if (!test) {
|
|
1069
|
+
throw new Error('You attempted to use @memoized(), which is not necessary nor supported. Remove the parentheses and you will be good to go!');
|
|
1070
|
+
}
|
|
1071
|
+
})(target !== undefined) : {};
|
|
1072
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1073
|
+
if (!test) {
|
|
1074
|
+
throw new Error(`You attempted to use @memoized on with ${arguments.length > 1 ? 'arguments' : 'an argument'} ( @memoized(${Array.from(arguments).map(d => `'${d}'`).join(', ')}), which is not supported. Dependencies are automatically tracked, so you can just use ${'`@memoized`'}`);
|
|
1075
|
+
}
|
|
1076
|
+
})(typeof target === 'object' && typeof key === 'string' && typeof descriptor === 'object' && arguments.length === 3) : {};
|
|
1077
|
+
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
1078
|
+
if (!test) {
|
|
1079
|
+
throw new Error(`The @memoized decorator must be applied to getters. '${key}' is not a getter.`);
|
|
1080
|
+
}
|
|
1081
|
+
})(typeof descriptor.get === 'function') : {};
|
|
1082
|
+
|
|
1083
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
1084
|
+
const getter = descriptor.get;
|
|
1085
|
+
descriptor.get = function () {
|
|
1086
|
+
const signals = withSignalStore(this);
|
|
1087
|
+
let memoSignal = signals.get(key);
|
|
1088
|
+
if (!memoSignal) {
|
|
1089
|
+
memoSignal = createMemo(this, key, getter.bind(this));
|
|
1090
|
+
signals.set(key, memoSignal);
|
|
1091
|
+
}
|
|
1092
|
+
return memoSignal();
|
|
1093
|
+
};
|
|
1094
|
+
return descriptor;
|
|
1095
|
+
}
|
|
1096
|
+
function gate(_target, key, desc) {
|
|
1097
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
1098
|
+
const getter = desc.get;
|
|
1099
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
1100
|
+
const setter = desc.set;
|
|
1101
|
+
desc.get = function () {
|
|
1102
|
+
const signals = withSignalStore(this);
|
|
1103
|
+
let signal = peekInternalSignal(signals, key);
|
|
1104
|
+
if (!signal) {
|
|
1105
|
+
signal = createInternalSignal(signals, this, key, getter.call(this));
|
|
1106
|
+
} else if (signal.isStale) {
|
|
1107
|
+
signal.isStale = false;
|
|
1108
|
+
signal.value = getter.call(this);
|
|
1109
|
+
}
|
|
1110
|
+
consumeInternalSignal(signal);
|
|
1111
|
+
return signal.value;
|
|
1112
|
+
};
|
|
1113
|
+
if (setter) {
|
|
1114
|
+
desc.set = function (v) {
|
|
1115
|
+
const signals = withSignalStore(this);
|
|
1116
|
+
let signal = peekInternalSignal(signals, key);
|
|
1117
|
+
if (!signal) {
|
|
1118
|
+
// we can't use `v` as initialValue here because setters don't
|
|
1119
|
+
// return the value and the final value may be different
|
|
1120
|
+
// than what the setter was called with.
|
|
1121
|
+
signal = createInternalSignal(signals, this, key, undefined);
|
|
1122
|
+
signal.isStale = true;
|
|
1123
|
+
}
|
|
1124
|
+
setter.call(this, v);
|
|
1125
|
+
// when a gate is set, we do not notify the signal
|
|
1126
|
+
// as its update is controlled externally.
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
return desc;
|
|
1130
|
+
}
|
|
1131
|
+
function defineGate(obj, key, desc) {
|
|
1132
|
+
const options = Object.assign({
|
|
1133
|
+
enumerable: true,
|
|
1134
|
+
configurable: false
|
|
1135
|
+
}, gate(obj, key, desc));
|
|
1136
|
+
Object.defineProperty(obj, key, options);
|
|
1137
|
+
}
|
|
1138
|
+
|
|
905
1139
|
/**
|
|
906
1140
|
* @module @ember-data/store
|
|
907
1141
|
*/
|
|
1142
|
+
|
|
908
1143
|
function urlFromLink(link) {
|
|
909
1144
|
if (typeof link === 'string') return link;
|
|
910
1145
|
return link.href;
|
|
@@ -935,7 +1170,7 @@ class ReactiveDocument {
|
|
|
935
1170
|
* ```
|
|
936
1171
|
*
|
|
937
1172
|
* @property links
|
|
938
|
-
* @type {
|
|
1173
|
+
* @type {Object|undefined} - a links object
|
|
939
1174
|
* @public
|
|
940
1175
|
*/
|
|
941
1176
|
|
|
@@ -950,7 +1185,7 @@ class ReactiveDocument {
|
|
|
950
1185
|
*
|
|
951
1186
|
* @property data
|
|
952
1187
|
* @public
|
|
953
|
-
* @type {
|
|
1188
|
+
* @type {Object|Array<object>|null|undefined} - a data object
|
|
954
1189
|
*/
|
|
955
1190
|
|
|
956
1191
|
/**
|
|
@@ -958,7 +1193,7 @@ class ReactiveDocument {
|
|
|
958
1193
|
*
|
|
959
1194
|
* @property errors
|
|
960
1195
|
* @public
|
|
961
|
-
* @type {
|
|
1196
|
+
* @type {Object|undefined} - an errors object
|
|
962
1197
|
*/
|
|
963
1198
|
|
|
964
1199
|
/**
|
|
@@ -966,7 +1201,7 @@ class ReactiveDocument {
|
|
|
966
1201
|
*
|
|
967
1202
|
* @property meta
|
|
968
1203
|
* @public
|
|
969
|
-
* @type {
|
|
1204
|
+
* @type {Object|undefined} - a meta object
|
|
970
1205
|
*/
|
|
971
1206
|
|
|
972
1207
|
/**
|
|
@@ -981,6 +1216,7 @@ class ReactiveDocument {
|
|
|
981
1216
|
this._store = store;
|
|
982
1217
|
this._localCache = localCache;
|
|
983
1218
|
this.identifier = identifier;
|
|
1219
|
+
const signals = withSignalStore(this);
|
|
984
1220
|
|
|
985
1221
|
// TODO if we ever enable auto-cleanup of the cache, we will need to tear this down
|
|
986
1222
|
// in a destroy method
|
|
@@ -990,10 +1226,10 @@ class ReactiveDocument {
|
|
|
990
1226
|
case 'updated':
|
|
991
1227
|
// FIXME in the case of a collection we need to notify it's length
|
|
992
1228
|
// and have it recalc
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1229
|
+
notifyInternalSignal(peekInternalSignal(signals, 'data'));
|
|
1230
|
+
notifyInternalSignal(peekInternalSignal(signals, 'links'));
|
|
1231
|
+
notifyInternalSignal(peekInternalSignal(signals, 'meta'));
|
|
1232
|
+
notifyInternalSignal(peekInternalSignal(signals, 'errors'));
|
|
997
1233
|
break;
|
|
998
1234
|
}
|
|
999
1235
|
});
|
|
@@ -1019,7 +1255,7 @@ class ReactiveDocument {
|
|
|
1019
1255
|
*
|
|
1020
1256
|
* @method fetch
|
|
1021
1257
|
* @public
|
|
1022
|
-
* @param {
|
|
1258
|
+
* @param {Object} options
|
|
1023
1259
|
* @return Promise<Document>
|
|
1024
1260
|
*/
|
|
1025
1261
|
fetch(options = {}) {
|
|
@@ -1040,7 +1276,7 @@ class ReactiveDocument {
|
|
|
1040
1276
|
*
|
|
1041
1277
|
* @method next
|
|
1042
1278
|
* @public
|
|
1043
|
-
* @param {
|
|
1279
|
+
* @param {Object} options
|
|
1044
1280
|
* @return Promise<Document | null>
|
|
1045
1281
|
*/
|
|
1046
1282
|
next(options = {}) {
|
|
@@ -1054,7 +1290,7 @@ class ReactiveDocument {
|
|
|
1054
1290
|
*
|
|
1055
1291
|
* @method prev
|
|
1056
1292
|
* @public
|
|
1057
|
-
* @param {
|
|
1293
|
+
* @param {Object} options
|
|
1058
1294
|
* @return Promise<Document | null>
|
|
1059
1295
|
*/
|
|
1060
1296
|
prev(options = {}) {
|
|
@@ -1068,7 +1304,7 @@ class ReactiveDocument {
|
|
|
1068
1304
|
*
|
|
1069
1305
|
* @method first
|
|
1070
1306
|
* @public
|
|
1071
|
-
* @param {
|
|
1307
|
+
* @param {Object} options
|
|
1072
1308
|
* @return Promise<Document | null>
|
|
1073
1309
|
*/
|
|
1074
1310
|
first(options = {}) {
|
|
@@ -1082,7 +1318,7 @@ class ReactiveDocument {
|
|
|
1082
1318
|
*
|
|
1083
1319
|
* @method last
|
|
1084
1320
|
* @public
|
|
1085
|
-
* @param {
|
|
1321
|
+
* @param {Object} options
|
|
1086
1322
|
* @return Promise<Document | null>
|
|
1087
1323
|
*/
|
|
1088
1324
|
last(options = {}) {
|
|
@@ -1120,7 +1356,7 @@ class ReactiveDocument {
|
|
|
1120
1356
|
return data;
|
|
1121
1357
|
}
|
|
1122
1358
|
}
|
|
1123
|
-
|
|
1359
|
+
defineGate(ReactiveDocument.prototype, 'errors', {
|
|
1124
1360
|
get() {
|
|
1125
1361
|
const {
|
|
1126
1362
|
identifier
|
|
@@ -1143,7 +1379,7 @@ defineSubscription(ReactiveDocument.prototype, 'errors', {
|
|
|
1143
1379
|
return 'errors' in doc ? doc.errors : undefined;
|
|
1144
1380
|
}
|
|
1145
1381
|
});
|
|
1146
|
-
|
|
1382
|
+
defineGate(ReactiveDocument.prototype, 'data', {
|
|
1147
1383
|
get() {
|
|
1148
1384
|
const {
|
|
1149
1385
|
identifier,
|
|
@@ -1170,7 +1406,7 @@ defineSubscription(ReactiveDocument.prototype, 'data', {
|
|
|
1170
1406
|
}
|
|
1171
1407
|
}
|
|
1172
1408
|
});
|
|
1173
|
-
|
|
1409
|
+
defineGate(ReactiveDocument.prototype, 'links', {
|
|
1174
1410
|
get() {
|
|
1175
1411
|
const {
|
|
1176
1412
|
identifier
|
|
@@ -1187,7 +1423,7 @@ defineSubscription(ReactiveDocument.prototype, 'links', {
|
|
|
1187
1423
|
return data.links;
|
|
1188
1424
|
}
|
|
1189
1425
|
});
|
|
1190
|
-
|
|
1426
|
+
defineGate(ReactiveDocument.prototype, 'meta', {
|
|
1191
1427
|
get() {
|
|
1192
1428
|
const {
|
|
1193
1429
|
identifier
|
|
@@ -1209,6 +1445,10 @@ defineSubscription(ReactiveDocument.prototype, 'meta', {
|
|
|
1209
1445
|
@module @ember-data/store
|
|
1210
1446
|
*/
|
|
1211
1447
|
|
|
1448
|
+
/**
|
|
1449
|
+
@module @ember-data/store
|
|
1450
|
+
*/
|
|
1451
|
+
|
|
1212
1452
|
/**
|
|
1213
1453
|
A `RecordReference` is a low-level API that allows users and
|
|
1214
1454
|
addon authors to perform meta-operations on a record.
|
|
@@ -2431,7 +2671,7 @@ class CacheManager {
|
|
|
2431
2671
|
* @method hasChangedAttrs
|
|
2432
2672
|
* @public
|
|
2433
2673
|
* @param identifier
|
|
2434
|
-
* @return {
|
|
2674
|
+
* @return {Boolean}
|
|
2435
2675
|
*/
|
|
2436
2676
|
hasChangedAttrs(identifier) {
|
|
2437
2677
|
return this.#cache.hasChangedAttrs(identifier);
|
|
@@ -2489,7 +2729,7 @@ class CacheManager {
|
|
|
2489
2729
|
* @method hasChangedRelationships
|
|
2490
2730
|
* @public
|
|
2491
2731
|
* @param {StableRecordIdentifier} identifier
|
|
2492
|
-
* @return {
|
|
2732
|
+
* @return {Boolean}
|
|
2493
2733
|
*/
|
|
2494
2734
|
hasChangedRelationships(identifier) {
|
|
2495
2735
|
return this.#cache.hasChangedRelationships(identifier);
|
|
@@ -2505,7 +2745,7 @@ class CacheManager {
|
|
|
2505
2745
|
* @method rollbackRelationships
|
|
2506
2746
|
* @public
|
|
2507
2747
|
* @param {StableRecordIdentifier} identifier
|
|
2508
|
-
* @return {
|
|
2748
|
+
* @return {String[]} the names of relationships that were restored
|
|
2509
2749
|
*/
|
|
2510
2750
|
rollbackRelationships(identifier) {
|
|
2511
2751
|
return this.#cache.rollbackRelationships(identifier);
|
|
@@ -2571,7 +2811,7 @@ class CacheManager {
|
|
|
2571
2811
|
* @method isEmpty
|
|
2572
2812
|
* @public
|
|
2573
2813
|
* @param identifier
|
|
2574
|
-
* @return {
|
|
2814
|
+
* @return {Boolean}
|
|
2575
2815
|
*/
|
|
2576
2816
|
isEmpty(identifier) {
|
|
2577
2817
|
return this.#cache.isEmpty(identifier);
|
|
@@ -2584,7 +2824,7 @@ class CacheManager {
|
|
|
2584
2824
|
* @method isNew
|
|
2585
2825
|
* @public
|
|
2586
2826
|
* @param identifier
|
|
2587
|
-
* @return {
|
|
2827
|
+
* @return {Boolean}
|
|
2588
2828
|
*/
|
|
2589
2829
|
isNew(identifier) {
|
|
2590
2830
|
return this.#cache.isNew(identifier);
|
|
@@ -2597,7 +2837,7 @@ class CacheManager {
|
|
|
2597
2837
|
* @method isDeleted
|
|
2598
2838
|
* @public
|
|
2599
2839
|
* @param identifier
|
|
2600
|
-
* @return {
|
|
2840
|
+
* @return {Boolean}
|
|
2601
2841
|
*/
|
|
2602
2842
|
isDeleted(identifier) {
|
|
2603
2843
|
return this.#cache.isDeleted(identifier);
|
|
@@ -2610,7 +2850,7 @@ class CacheManager {
|
|
|
2610
2850
|
* @method isDeletionCommitted
|
|
2611
2851
|
* @public
|
|
2612
2852
|
* @param identifier
|
|
2613
|
-
* @return {
|
|
2853
|
+
* @return {Boolean}
|
|
2614
2854
|
*/
|
|
2615
2855
|
isDeletionCommitted(identifier) {
|
|
2616
2856
|
return this.#cache.isDeletionCommitted(identifier);
|
|
@@ -2624,10 +2864,6 @@ class CacheManager {
|
|
|
2624
2864
|
function isCacheOperationValue(value) {
|
|
2625
2865
|
return value === 'added' || value === 'state' || value === 'updated' || value === 'removed' || value === 'invalidated';
|
|
2626
2866
|
}
|
|
2627
|
-
function runLoopIsFlushing() {
|
|
2628
|
-
//@ts-expect-error
|
|
2629
|
-
return !!_backburner.currentInstance && _backburner._autorun !== true;
|
|
2630
|
-
}
|
|
2631
2867
|
function count(label) {
|
|
2632
2868
|
// @ts-expect-error
|
|
2633
2869
|
// eslint-disable-next-line
|
|
@@ -2823,11 +3059,11 @@ class NotificationManager {
|
|
|
2823
3059
|
_scheduleNotify() {
|
|
2824
3060
|
const asyncFlush = this.store._enableAsyncFlush;
|
|
2825
3061
|
if (this._hasFlush) {
|
|
2826
|
-
if (asyncFlush !== false && !
|
|
3062
|
+
if (asyncFlush !== false && !willSyncFlushWatchers()) {
|
|
2827
3063
|
return false;
|
|
2828
3064
|
}
|
|
2829
3065
|
}
|
|
2830
|
-
if (asyncFlush && !
|
|
3066
|
+
if (asyncFlush && !willSyncFlushWatchers()) {
|
|
2831
3067
|
this._hasFlush = true;
|
|
2832
3068
|
return false;
|
|
2833
3069
|
}
|
|
@@ -2890,24 +3126,11 @@ class NotificationManager {
|
|
|
2890
3126
|
*/
|
|
2891
3127
|
|
|
2892
3128
|
const NativeProxy = Proxy;
|
|
2893
|
-
function decorateMethodV2(prototype, prop, decorators) {
|
|
2894
|
-
const origDesc = Object.getOwnPropertyDescriptor(prototype, prop);
|
|
2895
|
-
let desc = {
|
|
2896
|
-
...origDesc
|
|
2897
|
-
};
|
|
2898
|
-
for (let decorator of decorators) {
|
|
2899
|
-
desc = decorator(prototype, prop, desc) || desc;
|
|
2900
|
-
}
|
|
2901
|
-
if (desc.initializer !== void 0) {
|
|
2902
|
-
desc.value = desc.initializer ? desc.initializer.call(prototype) : void 0;
|
|
2903
|
-
desc.initializer = void 0;
|
|
2904
|
-
}
|
|
2905
|
-
Object.defineProperty(prototype, prop, desc);
|
|
2906
|
-
}
|
|
2907
3129
|
|
|
2908
3130
|
/**
|
|
2909
3131
|
@module @ember-data/store
|
|
2910
3132
|
*/
|
|
3133
|
+
|
|
2911
3134
|
const ARRAY_GETTER_METHODS = new Set([Symbol.iterator, 'concat', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'flat', 'flatMap', 'forEach', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'map', 'reduce', 'reduceRight', 'slice', 'some', 'values']);
|
|
2912
3135
|
const ARRAY_SETTER_METHODS = new Set(['push', 'pop', 'unshift', 'shift', 'splice', 'sort']);
|
|
2913
3136
|
const SYNC_PROPS = new Set(['[]', 'length', 'links', 'meta']);
|
|
@@ -2920,14 +3143,9 @@ function isArraySetter(prop) {
|
|
|
2920
3143
|
function isSelfProp(self, prop) {
|
|
2921
3144
|
return prop in self;
|
|
2922
3145
|
}
|
|
2923
|
-
const ARRAY_SIGNAL = getOrSetGlobal('#signal', Symbol('#signal'));
|
|
2924
3146
|
const SOURCE = getOrSetGlobal('#source', Symbol('#source'));
|
|
2925
3147
|
const MUTATE = getOrSetGlobal('#update', Symbol('#update'));
|
|
2926
|
-
const NOTIFY = getOrSetGlobal('#notify', Symbol('#notify'));
|
|
2927
3148
|
const IS_COLLECTION = getOrSetGlobal('IS_COLLECTION', Symbol.for('Collection'));
|
|
2928
|
-
function notifyArray(arr) {
|
|
2929
|
-
addToTransaction(arr[ARRAY_SIGNAL]);
|
|
2930
|
-
}
|
|
2931
3149
|
function convertToInt(prop) {
|
|
2932
3150
|
if (typeof prop === 'symbol') return null;
|
|
2933
3151
|
const num = Number(prop);
|
|
@@ -2991,11 +3209,6 @@ class IdentifierArray {
|
|
|
2991
3209
|
isDestroyed = false;
|
|
2992
3210
|
_updatingPromise = null;
|
|
2993
3211
|
identifier;
|
|
2994
|
-
[IS_COLLECTION] = true;
|
|
2995
|
-
[SOURCE];
|
|
2996
|
-
[NOTIFY]() {
|
|
2997
|
-
notifyArray(this);
|
|
2998
|
-
}
|
|
2999
3212
|
|
|
3000
3213
|
/**
|
|
3001
3214
|
The store that created this record array.
|
|
@@ -3009,20 +3222,9 @@ class IdentifierArray {
|
|
|
3009
3222
|
// changing the reference breaks the Proxy
|
|
3010
3223
|
// this[SOURCE] = [];
|
|
3011
3224
|
this[SOURCE].length = 0;
|
|
3012
|
-
this[
|
|
3225
|
+
notifyInternalSignal(this[ARRAY_SIGNAL]);
|
|
3013
3226
|
this.isDestroyed = !clear;
|
|
3014
3227
|
}
|
|
3015
|
-
|
|
3016
|
-
// length must be on self for proxied methods to work properly
|
|
3017
|
-
get length() {
|
|
3018
|
-
return this[SOURCE].length;
|
|
3019
|
-
}
|
|
3020
|
-
static {
|
|
3021
|
-
decorateMethodV2(this.prototype, "length", [compat]);
|
|
3022
|
-
}
|
|
3023
|
-
set length(value) {
|
|
3024
|
-
this[SOURCE].length = value;
|
|
3025
|
-
}
|
|
3026
3228
|
constructor(options) {
|
|
3027
3229
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
3028
3230
|
const self = this;
|
|
@@ -3031,10 +3233,13 @@ class IdentifierArray {
|
|
|
3031
3233
|
this._manager = options.manager;
|
|
3032
3234
|
this.identifier = options.identifier || null;
|
|
3033
3235
|
this[SOURCE] = options.identifiers;
|
|
3034
|
-
this[
|
|
3236
|
+
this[IS_COLLECTION] = true;
|
|
3237
|
+
|
|
3238
|
+
// we attach the signal storage to the class
|
|
3239
|
+
// so that its easier to find debugging.
|
|
3240
|
+
const signals = withSignalStore(this);
|
|
3035
3241
|
const store = options.store;
|
|
3036
3242
|
const boundFns = new Map();
|
|
3037
|
-
const _SIGNAL = this[ARRAY_SIGNAL];
|
|
3038
3243
|
const PrivateState = {
|
|
3039
3244
|
links: options.links || null,
|
|
3040
3245
|
meta: options.meta || null
|
|
@@ -3044,31 +3249,36 @@ class IdentifierArray {
|
|
|
3044
3249
|
// when a mutation occurs
|
|
3045
3250
|
// we track all mutations within the call
|
|
3046
3251
|
// and forward them as one
|
|
3047
|
-
|
|
3252
|
+
let _SIGNAL = null;
|
|
3048
3253
|
const proxy = new NativeProxy(this[SOURCE], {
|
|
3049
3254
|
get(target, prop, receiver) {
|
|
3050
3255
|
const index = convertToInt(prop);
|
|
3051
|
-
if (_SIGNAL.
|
|
3256
|
+
if (_SIGNAL.isStale && (index !== null || SYNC_PROPS.has(prop) || isArrayGetter(prop))) {
|
|
3052
3257
|
options.manager._syncArray(receiver);
|
|
3053
|
-
_SIGNAL.
|
|
3054
|
-
_SIGNAL.shouldReset = false;
|
|
3258
|
+
_SIGNAL.isStale = false;
|
|
3055
3259
|
}
|
|
3056
3260
|
if (index !== null) {
|
|
3057
3261
|
const identifier = target[index];
|
|
3058
3262
|
if (!transaction) {
|
|
3059
|
-
|
|
3263
|
+
consumeInternalSignal(_SIGNAL);
|
|
3060
3264
|
}
|
|
3061
3265
|
return identifier && store._instanceCache.getRecord(identifier);
|
|
3062
3266
|
}
|
|
3063
|
-
if (prop ===
|
|
3064
|
-
|
|
3065
|
-
|
|
3267
|
+
if (prop === ARRAY_SIGNAL) {
|
|
3268
|
+
return _SIGNAL;
|
|
3269
|
+
}
|
|
3270
|
+
if (prop === 'length') {
|
|
3271
|
+
return consumeInternalSignal(_SIGNAL), target.length;
|
|
3272
|
+
}
|
|
3273
|
+
if (prop === 'meta') return consumeInternalSignal(_SIGNAL), PrivateState.meta;
|
|
3274
|
+
if (prop === 'links') return consumeInternalSignal(_SIGNAL), PrivateState.links;
|
|
3275
|
+
if (prop === '[]') return consumeInternalSignal(_SIGNAL), receiver;
|
|
3066
3276
|
if (isArrayGetter(prop)) {
|
|
3067
3277
|
let fn = boundFns.get(prop);
|
|
3068
3278
|
if (fn === undefined) {
|
|
3069
3279
|
if (prop === 'forEach') {
|
|
3070
3280
|
fn = function () {
|
|
3071
|
-
|
|
3281
|
+
consumeInternalSignal(_SIGNAL);
|
|
3072
3282
|
transaction = true;
|
|
3073
3283
|
const result = safeForEach(receiver, target, store, arguments[0], arguments[1]);
|
|
3074
3284
|
transaction = false;
|
|
@@ -3076,7 +3286,7 @@ class IdentifierArray {
|
|
|
3076
3286
|
};
|
|
3077
3287
|
} else {
|
|
3078
3288
|
fn = function () {
|
|
3079
|
-
|
|
3289
|
+
consumeInternalSignal(_SIGNAL);
|
|
3080
3290
|
// array functions must run through Reflect to work properly
|
|
3081
3291
|
// binding via other means will not work.
|
|
3082
3292
|
transaction = true;
|
|
@@ -3119,7 +3329,7 @@ class IdentifierArray {
|
|
|
3119
3329
|
return fn;
|
|
3120
3330
|
}
|
|
3121
3331
|
if (isSelfProp(self, prop)) {
|
|
3122
|
-
if (prop ===
|
|
3332
|
+
if (prop === SOURCE) {
|
|
3123
3333
|
return self[prop];
|
|
3124
3334
|
}
|
|
3125
3335
|
let fn = boundFns.get(prop);
|
|
@@ -3127,7 +3337,7 @@ class IdentifierArray {
|
|
|
3127
3337
|
const outcome = self[prop];
|
|
3128
3338
|
if (typeof outcome === 'function') {
|
|
3129
3339
|
fn = function () {
|
|
3130
|
-
|
|
3340
|
+
consumeInternalSignal(_SIGNAL);
|
|
3131
3341
|
// array functions must run through Reflect to work properly
|
|
3132
3342
|
// binding via other means will not work.
|
|
3133
3343
|
return Reflect.apply(outcome, receiver, arguments);
|
|
@@ -3135,7 +3345,7 @@ class IdentifierArray {
|
|
|
3135
3345
|
boundFns.set(prop, fn);
|
|
3136
3346
|
return fn;
|
|
3137
3347
|
}
|
|
3138
|
-
return
|
|
3348
|
+
return consumeInternalSignal(_SIGNAL), outcome;
|
|
3139
3349
|
}
|
|
3140
3350
|
return target[prop];
|
|
3141
3351
|
},
|
|
@@ -3253,8 +3463,10 @@ class IdentifierArray {
|
|
|
3253
3463
|
}
|
|
3254
3464
|
});
|
|
3255
3465
|
}
|
|
3256
|
-
|
|
3257
|
-
|
|
3466
|
+
|
|
3467
|
+
// we entangle the signal on the returned proxy since that is
|
|
3468
|
+
// the object that other code will be interfacing with.
|
|
3469
|
+
_SIGNAL = entangleSignal(signals, proxy, ARRAY_SIGNAL, undefined);
|
|
3258
3470
|
return proxy;
|
|
3259
3471
|
}
|
|
3260
3472
|
|
|
@@ -3345,7 +3557,7 @@ const desc = {
|
|
|
3345
3557
|
}
|
|
3346
3558
|
}
|
|
3347
3559
|
};
|
|
3348
|
-
compat(desc);
|
|
3560
|
+
// compat(desc);
|
|
3349
3561
|
Object.defineProperty(IdentifierArray.prototype, '[]', desc);
|
|
3350
3562
|
defineSignal(IdentifierArray.prototype, 'isUpdating', false);
|
|
3351
3563
|
class Collection extends IdentifierArray {
|
|
@@ -3418,6 +3630,7 @@ function extractIdentifierFromRecord$2(record) {
|
|
|
3418
3630
|
/**
|
|
3419
3631
|
@module @ember-data/store
|
|
3420
3632
|
*/
|
|
3633
|
+
|
|
3421
3634
|
const FAKE_ARR = getOrSetGlobal('FAKE_ARR', {});
|
|
3422
3635
|
const SLICE_BATCH_SIZE = 1200;
|
|
3423
3636
|
/**
|
|
@@ -3519,9 +3732,11 @@ class RecordArrayManager {
|
|
|
3519
3732
|
|
|
3520
3733
|
// then pull new state if required
|
|
3521
3734
|
if (isRequestArray) {
|
|
3522
|
-
const
|
|
3523
|
-
|
|
3524
|
-
|
|
3735
|
+
const signal = array[ARRAY_SIGNAL];
|
|
3736
|
+
|
|
3737
|
+
// we only need to rebuild the array from cache if a full sync is required
|
|
3738
|
+
// due to notification that the cache has changed
|
|
3739
|
+
if (signal.value === 'cache-sync') {
|
|
3525
3740
|
const doc = this.store.cache.peek(array.identifier);
|
|
3526
3741
|
macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
|
|
3527
3742
|
if (!test) {
|
|
@@ -3604,15 +3819,13 @@ class RecordArrayManager {
|
|
|
3604
3819
|
if (array === FAKE_ARR) {
|
|
3605
3820
|
return;
|
|
3606
3821
|
}
|
|
3607
|
-
const
|
|
3608
|
-
if (
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
} else if (delta > 0 && !tag.t) {
|
|
3615
|
-
addTransactionCB(array[NOTIFY]);
|
|
3822
|
+
const signal = array[ARRAY_SIGNAL];
|
|
3823
|
+
if (!signal.isStale || delta > 0) {
|
|
3824
|
+
notifyInternalSignal(signal);
|
|
3825
|
+
|
|
3826
|
+
// when the cache has updated for our array, we need to
|
|
3827
|
+
// do a full rebuild of the array
|
|
3828
|
+
signal.value = shouldSyncFromCache ? 'cache-sync' : 'patch';
|
|
3616
3829
|
}
|
|
3617
3830
|
}
|
|
3618
3831
|
_getPendingFor(identifier, includeManaged, isRemove) {
|
|
@@ -3675,9 +3888,11 @@ class RecordArrayManager {
|
|
|
3675
3888
|
source.length = 0;
|
|
3676
3889
|
fastPush(source, identifiers);
|
|
3677
3890
|
this._set.set(array, new Set(identifiers));
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3891
|
+
if (!isCollection(array)) {
|
|
3892
|
+
notifyInternalSignal(array[ARRAY_SIGNAL]);
|
|
3893
|
+
array.meta = payload?.meta || null;
|
|
3894
|
+
array.links = payload?.links || null;
|
|
3895
|
+
}
|
|
3681
3896
|
array.isLoaded = true;
|
|
3682
3897
|
disassociate(this._identifiers, array, old);
|
|
3683
3898
|
associate(this._identifiers, array, identifiers);
|
|
@@ -3977,7 +4192,7 @@ class RequestStateService {
|
|
|
3977
4192
|
* @method subscribeForRecord
|
|
3978
4193
|
* @public
|
|
3979
4194
|
* @param {StableRecordIdentifier} identifier
|
|
3980
|
-
* @param {(state:
|
|
4195
|
+
* @param {(state: RequestCacheRequestState) => void} callback
|
|
3981
4196
|
*/
|
|
3982
4197
|
subscribeForRecord(identifier, callback) {
|
|
3983
4198
|
let subscriptions = this._subscriptions.get(identifier);
|
|
@@ -3994,7 +4209,7 @@ class RequestStateService {
|
|
|
3994
4209
|
* @method getPendingRequestsForRecord
|
|
3995
4210
|
* @public
|
|
3996
4211
|
* @param {StableRecordIdentifier} identifier
|
|
3997
|
-
* @return {
|
|
4212
|
+
* @return {RequestCacheRequestState[]} an array of request states for any pending requests for the given identifier
|
|
3998
4213
|
*/
|
|
3999
4214
|
getPendingRequestsForRecord(identifier) {
|
|
4000
4215
|
return this._pending.get(identifier) || EMPTY_ARR;
|
|
@@ -4006,7 +4221,7 @@ class RequestStateService {
|
|
|
4006
4221
|
* @method getLastRequestForRecord
|
|
4007
4222
|
* @public
|
|
4008
4223
|
* @param {StableRecordIdentifier} identifier
|
|
4009
|
-
* @return {
|
|
4224
|
+
* @return {RequestCacheRequestState | null} the state of the most recent request for the given identifier
|
|
4010
4225
|
*/
|
|
4011
4226
|
getLastRequestForRecord(identifier) {
|
|
4012
4227
|
const requests = this._done.get(identifier);
|
|
@@ -4266,7 +4481,8 @@ class Store extends BaseClass {
|
|
|
4266
4481
|
* The NotificationManager can be used to subscribe to
|
|
4267
4482
|
* changes to the cache.
|
|
4268
4483
|
*
|
|
4269
|
-
* @property
|
|
4484
|
+
* @property notifications
|
|
4485
|
+
* @type {NotificationManager}
|
|
4270
4486
|
* @public
|
|
4271
4487
|
*/
|
|
4272
4488
|
|
|
@@ -4277,7 +4493,8 @@ class Store extends BaseClass {
|
|
|
4277
4493
|
* The SchemaService can be used to query for
|
|
4278
4494
|
* information about the schema of a resource.
|
|
4279
4495
|
*
|
|
4280
|
-
* @property
|
|
4496
|
+
* @property schema
|
|
4497
|
+
* @type {SchemaService}
|
|
4281
4498
|
* @public
|
|
4282
4499
|
*/
|
|
4283
4500
|
get schema() {
|
|
@@ -4294,7 +4511,8 @@ class Store extends BaseClass {
|
|
|
4294
4511
|
* The IdentifierCache can be used to generate or
|
|
4295
4512
|
* retrieve a stable unique identifier for any resource.
|
|
4296
4513
|
*
|
|
4297
|
-
* @property
|
|
4514
|
+
* @property identifierCache
|
|
4515
|
+
* @type {IdentifierCache}
|
|
4298
4516
|
* @public
|
|
4299
4517
|
*/
|
|
4300
4518
|
|
|
@@ -4320,7 +4538,8 @@ class Store extends BaseClass {
|
|
|
4320
4538
|
* ```
|
|
4321
4539
|
*
|
|
4322
4540
|
* @public
|
|
4323
|
-
* @property
|
|
4541
|
+
* @property requestManager
|
|
4542
|
+
* @type {RequestManager}
|
|
4324
4543
|
*/
|
|
4325
4544
|
|
|
4326
4545
|
/**
|
|
@@ -4350,7 +4569,8 @@ class Store extends BaseClass {
|
|
|
4350
4569
|
* ```
|
|
4351
4570
|
*
|
|
4352
4571
|
* @public
|
|
4353
|
-
* @property
|
|
4572
|
+
* @property lifetimes
|
|
4573
|
+
* @type {CachePolicy|undefined}
|
|
4354
4574
|
*/
|
|
4355
4575
|
|
|
4356
4576
|
// Private
|
|
@@ -4642,7 +4862,7 @@ class Store extends BaseClass {
|
|
|
4642
4862
|
@method modelFor
|
|
4643
4863
|
@public
|
|
4644
4864
|
@deprecated
|
|
4645
|
-
@param {
|
|
4865
|
+
@param {String} type
|
|
4646
4866
|
@return {ModelSchema}
|
|
4647
4867
|
*/
|
|
4648
4868
|
|
|
@@ -5287,7 +5507,7 @@ class Store extends BaseClass {
|
|
|
5287
5507
|
@method query
|
|
5288
5508
|
@public
|
|
5289
5509
|
@param {String} type the name of the resource
|
|
5290
|
-
@param {
|
|
5510
|
+
@param {Object} query a query to be used by the adapter
|
|
5291
5511
|
@param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.query
|
|
5292
5512
|
@return {Promise} promise
|
|
5293
5513
|
*/
|
|
@@ -5401,9 +5621,9 @@ class Store extends BaseClass {
|
|
|
5401
5621
|
@since 1.13.0
|
|
5402
5622
|
@method queryRecord
|
|
5403
5623
|
@public
|
|
5404
|
-
@param {
|
|
5405
|
-
@param {
|
|
5406
|
-
@param {
|
|
5624
|
+
@param {String} type
|
|
5625
|
+
@param {Object} query an opaque query to be used by the adapter
|
|
5626
|
+
@param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.queryRecord
|
|
5407
5627
|
@return {Promise} promise which resolves with the found record or `null`
|
|
5408
5628
|
*/
|
|
5409
5629
|
|
|
@@ -5582,8 +5802,8 @@ class Store extends BaseClass {
|
|
|
5582
5802
|
@since 1.13.0
|
|
5583
5803
|
@method findAll
|
|
5584
5804
|
@public
|
|
5585
|
-
@param {
|
|
5586
|
-
@param {
|
|
5805
|
+
@param {String} type the name of the resource
|
|
5806
|
+
@param {Object} options
|
|
5587
5807
|
@return {Promise} promise
|
|
5588
5808
|
*/
|
|
5589
5809
|
|
|
@@ -5631,7 +5851,7 @@ class Store extends BaseClass {
|
|
|
5631
5851
|
@since 1.13.0
|
|
5632
5852
|
@method peekAll
|
|
5633
5853
|
@public
|
|
5634
|
-
@param {
|
|
5854
|
+
@param {String} type the name of the resource
|
|
5635
5855
|
@return {RecordArray}
|
|
5636
5856
|
*/
|
|
5637
5857
|
|
|
@@ -5661,7 +5881,7 @@ class Store extends BaseClass {
|
|
|
5661
5881
|
store.unloadAll('post');
|
|
5662
5882
|
```
|
|
5663
5883
|
@method unloadAll
|
|
5664
|
-
@param {
|
|
5884
|
+
@param {String} type the name of the resource
|
|
5665
5885
|
@public
|
|
5666
5886
|
*/
|
|
5667
5887
|
|
|
@@ -5933,7 +6153,8 @@ class Store extends BaseClass {
|
|
|
5933
6153
|
* Returns the cache instance associated to this Store, instantiates the Cache
|
|
5934
6154
|
* if necessary via `Store.createCache`
|
|
5935
6155
|
*
|
|
5936
|
-
* @property
|
|
6156
|
+
* @property cache
|
|
6157
|
+
* @type {Cache}
|
|
5937
6158
|
* @public
|
|
5938
6159
|
*/
|
|
5939
6160
|
get cache() {
|
|
@@ -6495,13 +6716,15 @@ function fetchContentAndHydrate(next, context, identifier, priority) {
|
|
|
6495
6716
|
class RelatedCollection extends IdentifierArray {
|
|
6496
6717
|
/**
|
|
6497
6718
|
The loading state of this array
|
|
6498
|
-
@property
|
|
6719
|
+
@property isLoaded
|
|
6720
|
+
@type {Boolean}
|
|
6499
6721
|
@public
|
|
6500
6722
|
*/
|
|
6501
6723
|
|
|
6502
6724
|
/**
|
|
6503
6725
|
`true` if the relationship is polymorphic, `false` otherwise.
|
|
6504
|
-
@property
|
|
6726
|
+
@property isPolymorphic
|
|
6727
|
+
@type {Boolean}
|
|
6505
6728
|
@private
|
|
6506
6729
|
*/
|
|
6507
6730
|
|
|
@@ -6531,14 +6754,16 @@ class RelatedCollection extends IdentifierArray {
|
|
|
6531
6754
|
// meta.page => 1
|
|
6532
6755
|
// meta.total => 5
|
|
6533
6756
|
```
|
|
6534
|
-
@property
|
|
6757
|
+
@property meta
|
|
6758
|
+
@type {Object | null}
|
|
6535
6759
|
@public
|
|
6536
6760
|
*/
|
|
6537
6761
|
|
|
6538
6762
|
/**
|
|
6539
6763
|
* Retrieve the links for this relationship
|
|
6540
6764
|
*
|
|
6541
|
-
@property
|
|
6765
|
+
@property links
|
|
6766
|
+
@type {Object | null}
|
|
6542
6767
|
@public
|
|
6543
6768
|
*/
|
|
6544
6769
|
|
|
@@ -6746,9 +6971,7 @@ class RelatedCollection extends IdentifierArray {
|
|
|
6746
6971
|
}
|
|
6747
6972
|
}
|
|
6748
6973
|
notify() {
|
|
6749
|
-
|
|
6750
|
-
signal.shouldReset = true;
|
|
6751
|
-
notifyArray(this);
|
|
6974
|
+
notifyInternalSignal(this[ARRAY_SIGNAL]);
|
|
6752
6975
|
}
|
|
6753
6976
|
|
|
6754
6977
|
/**
|
|
@@ -6914,6 +7137,573 @@ function mutate(collection, mutation, _SIGNAL) {
|
|
|
6914
7137
|
}
|
|
6915
7138
|
})(typeof collection._manager.mutate === 'function') : {};
|
|
6916
7139
|
collection._manager.mutate(mutation);
|
|
6917
|
-
|
|
7140
|
+
notifyInternalSignal(_SIGNAL);
|
|
7141
|
+
}
|
|
7142
|
+
const PromiseCache = new WeakMap();
|
|
7143
|
+
|
|
7144
|
+
/**
|
|
7145
|
+
* The state of a promise in the "pending"
|
|
7146
|
+
* state. This is the default initial state.
|
|
7147
|
+
*
|
|
7148
|
+
* @typedoc
|
|
7149
|
+
*/
|
|
7150
|
+
|
|
7151
|
+
/**
|
|
7152
|
+
* The state of a promise in the "fulfilled" state.
|
|
7153
|
+
* This is the state of a promise that has resolved
|
|
7154
|
+
* successfully.
|
|
7155
|
+
*
|
|
7156
|
+
* @typedoc
|
|
7157
|
+
*/
|
|
7158
|
+
|
|
7159
|
+
/**
|
|
7160
|
+
* The state of a promise in the "rejected" state.
|
|
7161
|
+
* This is the state of a promise that has rejected
|
|
7162
|
+
* with an error.
|
|
7163
|
+
*
|
|
7164
|
+
* @typedoc
|
|
7165
|
+
*/
|
|
7166
|
+
|
|
7167
|
+
/**
|
|
7168
|
+
* The state of a promise. This is the type that is returned
|
|
7169
|
+
* from `getPromiseState`.
|
|
7170
|
+
*
|
|
7171
|
+
* See also:
|
|
7172
|
+
* - {@link PendingPromise}
|
|
7173
|
+
* - {@link ResolvedPromise}
|
|
7174
|
+
* - {@link RejectedPromise}
|
|
7175
|
+
*
|
|
7176
|
+
* @typedoc
|
|
7177
|
+
*/
|
|
7178
|
+
|
|
7179
|
+
const PromiseStateProto = {};
|
|
7180
|
+
|
|
7181
|
+
// TODO introduce a new mechanism for defining multiple properties
|
|
7182
|
+
// that share a common signal
|
|
7183
|
+
defineSignal(PromiseStateProto, 'reason', null);
|
|
7184
|
+
defineSignal(PromiseStateProto, 'value', null);
|
|
7185
|
+
defineSignal(PromiseStateProto, 'result', null);
|
|
7186
|
+
defineSignal(PromiseStateProto, 'error', null);
|
|
7187
|
+
defineSignal(PromiseStateProto, 'status', 'pending');
|
|
7188
|
+
defineSignal(PromiseStateProto, 'isPending', true);
|
|
7189
|
+
defineSignal(PromiseStateProto, 'isLoading', true);
|
|
7190
|
+
defineSignal(PromiseStateProto, 'isSuccess', false);
|
|
7191
|
+
defineSignal(PromiseStateProto, 'isError', false);
|
|
7192
|
+
function createPromiseState(promise) {
|
|
7193
|
+
const state = getPromiseResult(promise);
|
|
7194
|
+
const promiseState = Object.create(PromiseStateProto);
|
|
7195
|
+
if (state) {
|
|
7196
|
+
if (state.isError) {
|
|
7197
|
+
promiseState.error = state.result;
|
|
7198
|
+
promiseState.reason = state.result;
|
|
7199
|
+
promiseState.status = 'rejected';
|
|
7200
|
+
promiseState.isError = true;
|
|
7201
|
+
promiseState.isPending = false;
|
|
7202
|
+
promiseState.isLoading = false;
|
|
7203
|
+
} else {
|
|
7204
|
+
promiseState.result = state.result;
|
|
7205
|
+
promiseState.value = state.result;
|
|
7206
|
+
promiseState.status = 'fulfilled';
|
|
7207
|
+
promiseState.isSuccess = true;
|
|
7208
|
+
promiseState.isPending = false;
|
|
7209
|
+
promiseState.isLoading = false;
|
|
7210
|
+
}
|
|
7211
|
+
} else {
|
|
7212
|
+
void promise.then(result => {
|
|
7213
|
+
setPromiseResult(promise, {
|
|
7214
|
+
isError: false,
|
|
7215
|
+
result
|
|
7216
|
+
});
|
|
7217
|
+
promiseState.result = result;
|
|
7218
|
+
promiseState.value = result;
|
|
7219
|
+
promiseState.status = 'fulfilled';
|
|
7220
|
+
promiseState.isSuccess = true;
|
|
7221
|
+
promiseState.isPending = false;
|
|
7222
|
+
promiseState.isLoading = false;
|
|
7223
|
+
}, error => {
|
|
7224
|
+
setPromiseResult(promise, {
|
|
7225
|
+
isError: true,
|
|
7226
|
+
result: error
|
|
7227
|
+
});
|
|
7228
|
+
promiseState.error = error;
|
|
7229
|
+
promiseState.reason = error;
|
|
7230
|
+
promiseState.status = 'rejected';
|
|
7231
|
+
promiseState.isError = true;
|
|
7232
|
+
promiseState.isPending = false;
|
|
7233
|
+
promiseState.isLoading = false;
|
|
7234
|
+
});
|
|
7235
|
+
}
|
|
7236
|
+
return promiseState;
|
|
7237
|
+
}
|
|
7238
|
+
const LegacyPromiseProxy = Symbol.for('LegacyPromiseProxy');
|
|
7239
|
+
function isLegacyAwaitable(promise) {
|
|
7240
|
+
return LegacyPromiseProxy in promise && 'promise' in promise && promise[LegacyPromiseProxy] === true;
|
|
7241
|
+
}
|
|
7242
|
+
function getPromise(promise) {
|
|
7243
|
+
return isLegacyAwaitable(promise) ? promise.promise : promise;
|
|
7244
|
+
}
|
|
7245
|
+
|
|
7246
|
+
/**
|
|
7247
|
+
* Returns a reactive state-machine for the provided promise or awaitable.
|
|
7248
|
+
*
|
|
7249
|
+
* Repeat calls to `getPromiseState` with the same promise will return the same state object
|
|
7250
|
+
* making is safe and easy to use in templates and JavaScript code to produce reactive
|
|
7251
|
+
* behaviors around promises.
|
|
7252
|
+
*
|
|
7253
|
+
* `getPromiseState` can be used in both JavaScript and Template contexts.
|
|
7254
|
+
*
|
|
7255
|
+
* ```ts
|
|
7256
|
+
* import { getPromiseState } from '@warp-drive/ember';
|
|
7257
|
+
*
|
|
7258
|
+
* const state = getPromiseState(promise);
|
|
7259
|
+
* ```
|
|
7260
|
+
*
|
|
7261
|
+
* For instance, we could write a getter on a component that updates whenever
|
|
7262
|
+
* the promise state advances or the promise changes, by combining the function
|
|
7263
|
+
* with the use of `@cached`
|
|
7264
|
+
*
|
|
7265
|
+
* ```ts
|
|
7266
|
+
* class Component {
|
|
7267
|
+
* @cached
|
|
7268
|
+
* get title() {
|
|
7269
|
+
* const state = getPromiseState(this.args.request);
|
|
7270
|
+
* if (state.isPending) {
|
|
7271
|
+
* return 'loading...';
|
|
7272
|
+
* }
|
|
7273
|
+
* if (state.isError) { return null; }
|
|
7274
|
+
* return state.result.title;
|
|
7275
|
+
* }
|
|
7276
|
+
* }
|
|
7277
|
+
* ```
|
|
7278
|
+
*
|
|
7279
|
+
* Or in a template as a helper:
|
|
7280
|
+
*
|
|
7281
|
+
* ```gjs
|
|
7282
|
+
* import { getPromiseState } from '@warp-drive/ember';
|
|
7283
|
+
*
|
|
7284
|
+
* <template>
|
|
7285
|
+
* {{#let (getPromiseState @request) as |state|}}
|
|
7286
|
+
* {{#if state.isPending}} <Spinner />
|
|
7287
|
+
* {{else if state.isError}} <ErrorForm @error={{state.error}} />
|
|
7288
|
+
* {{else}}
|
|
7289
|
+
* <h1>{{state.result.title}}</h1>
|
|
7290
|
+
* {{/if}}
|
|
7291
|
+
* {{/let}}
|
|
7292
|
+
* </template>
|
|
7293
|
+
* ```
|
|
7294
|
+
*
|
|
7295
|
+
* If looking to use in a template, consider also the `<Await />` component.
|
|
7296
|
+
*
|
|
7297
|
+
* @typedoc
|
|
7298
|
+
*/
|
|
7299
|
+
function getPromiseState(promise) {
|
|
7300
|
+
const _promise = getPromise(promise);
|
|
7301
|
+
let state = PromiseCache.get(_promise);
|
|
7302
|
+
if (!state) {
|
|
7303
|
+
state = createPromiseState(_promise);
|
|
7304
|
+
PromiseCache.set(_promise, state);
|
|
7305
|
+
}
|
|
7306
|
+
return state;
|
|
7307
|
+
}
|
|
7308
|
+
const RequestCache = new WeakMap();
|
|
7309
|
+
function isAbortError(error) {
|
|
7310
|
+
return error instanceof DOMException && error.name === 'AbortError';
|
|
7311
|
+
}
|
|
7312
|
+
async function watchStream(stream, state) {
|
|
7313
|
+
const reader = stream.getReader();
|
|
7314
|
+
let bytesLoaded = 0;
|
|
7315
|
+
let shouldForward = state._stream !== null && state._stream.readable.locked;
|
|
7316
|
+
let isForwarding = shouldForward;
|
|
7317
|
+
let writer = state._stream?.writable.getWriter();
|
|
7318
|
+
const buffer = [];
|
|
7319
|
+
state._isPending = false;
|
|
7320
|
+
state._isStarted = true;
|
|
7321
|
+
state._startTime = performance.now();
|
|
7322
|
+
while (true) {
|
|
7323
|
+
const {
|
|
7324
|
+
value,
|
|
7325
|
+
done
|
|
7326
|
+
} = await reader.read();
|
|
7327
|
+
if (done) {
|
|
7328
|
+
break;
|
|
7329
|
+
}
|
|
7330
|
+
bytesLoaded += value.byteLength;
|
|
7331
|
+
state._bytesLoaded = bytesLoaded;
|
|
7332
|
+
state._lastPacketTime = performance.now();
|
|
7333
|
+
shouldForward = shouldForward || state._stream !== null && state._stream.readable.locked;
|
|
7334
|
+
if (shouldForward) {
|
|
7335
|
+
if (!isForwarding) {
|
|
7336
|
+
isForwarding = true;
|
|
7337
|
+
writer = state._stream.writable.getWriter();
|
|
7338
|
+
for (const item of buffer) {
|
|
7339
|
+
await writer.ready;
|
|
7340
|
+
await writer.write(item);
|
|
7341
|
+
}
|
|
7342
|
+
buffer.length = 0;
|
|
7343
|
+
}
|
|
7344
|
+
await writer.ready;
|
|
7345
|
+
await writer.write(value);
|
|
7346
|
+
} else {
|
|
7347
|
+
buffer.push(value);
|
|
7348
|
+
}
|
|
7349
|
+
}
|
|
7350
|
+
|
|
7351
|
+
// if we are still forwarding, we need to close the writer
|
|
7352
|
+
if (isForwarding) {
|
|
7353
|
+
await writer.ready;
|
|
7354
|
+
await writer.close();
|
|
7355
|
+
} else if (state._stream) {
|
|
7356
|
+
// if we are not forwarding, we need to cancel the stream
|
|
7357
|
+
await state._stream.readable.cancel('The Stream Has Already Ended');
|
|
7358
|
+
state._stream = null;
|
|
7359
|
+
}
|
|
7360
|
+
const endTime = performance.now();
|
|
7361
|
+
state._endTime = endTime;
|
|
7362
|
+
state._isComplete = true;
|
|
7363
|
+
state._isStarted = false;
|
|
7364
|
+
}
|
|
7365
|
+
|
|
7366
|
+
/**
|
|
7367
|
+
* Lazily consumes the stream of a request, providing a number of
|
|
7368
|
+
* reactive properties that can be used to build UIs that respond
|
|
7369
|
+
* to the progress of a request.
|
|
7370
|
+
*
|
|
7371
|
+
* @typedoc
|
|
7372
|
+
*/
|
|
7373
|
+
class RequestLoadingState {
|
|
7374
|
+
_stream = null;
|
|
7375
|
+
_future;
|
|
7376
|
+
_triggered = false;
|
|
7377
|
+
_trigger() {
|
|
7378
|
+
if (this._triggered) {
|
|
7379
|
+
return;
|
|
7380
|
+
}
|
|
7381
|
+
this._triggered = true;
|
|
7382
|
+
const future = this._future;
|
|
7383
|
+
const promise = future.getStream();
|
|
7384
|
+
if (promise.sizeHint) {
|
|
7385
|
+
this._sizeHint = promise.sizeHint;
|
|
7386
|
+
}
|
|
7387
|
+
this.promise = promise.then(stream => {
|
|
7388
|
+
if (!stream) {
|
|
7389
|
+
this._isPending = false;
|
|
7390
|
+
this._isComplete = true;
|
|
7391
|
+
return;
|
|
7392
|
+
}
|
|
7393
|
+
return watchStream(stream, this);
|
|
7394
|
+
}, error => {
|
|
7395
|
+
this._isPending = false;
|
|
7396
|
+
this._isStarted = false;
|
|
7397
|
+
if (isAbortError(error)) {
|
|
7398
|
+
this._isCancelled = true;
|
|
7399
|
+
this._isComplete = true;
|
|
7400
|
+
}
|
|
7401
|
+
this._isErrored = true;
|
|
7402
|
+
this._error = error;
|
|
7403
|
+
});
|
|
7404
|
+
}
|
|
7405
|
+
promise = null;
|
|
7406
|
+
get isPending() {
|
|
7407
|
+
this._trigger();
|
|
7408
|
+
return this._isPending;
|
|
7409
|
+
}
|
|
7410
|
+
get sizeHint() {
|
|
7411
|
+
this._trigger();
|
|
7412
|
+
return this._sizeHint;
|
|
7413
|
+
}
|
|
7414
|
+
get stream() {
|
|
7415
|
+
this._trigger();
|
|
7416
|
+
if (!this._stream) {
|
|
7417
|
+
if (this._isComplete || this._isCancelled || this._isErrored) {
|
|
7418
|
+
return null;
|
|
7419
|
+
}
|
|
7420
|
+
this._stream = new TransformStream();
|
|
7421
|
+
}
|
|
7422
|
+
return this._stream.readable;
|
|
7423
|
+
}
|
|
7424
|
+
get isStarted() {
|
|
7425
|
+
this._trigger();
|
|
7426
|
+
return this._isStarted;
|
|
7427
|
+
}
|
|
7428
|
+
get bytesLoaded() {
|
|
7429
|
+
this._trigger();
|
|
7430
|
+
return this._bytesLoaded;
|
|
7431
|
+
}
|
|
7432
|
+
get startTime() {
|
|
7433
|
+
this._trigger();
|
|
7434
|
+
return this._startTime;
|
|
7435
|
+
}
|
|
7436
|
+
get endTime() {
|
|
7437
|
+
this._trigger();
|
|
7438
|
+
return this._endTime;
|
|
7439
|
+
}
|
|
7440
|
+
get lastPacketTime() {
|
|
7441
|
+
this._trigger();
|
|
7442
|
+
return this._lastPacketTime;
|
|
7443
|
+
}
|
|
7444
|
+
get isComplete() {
|
|
7445
|
+
this._trigger();
|
|
7446
|
+
return this._isComplete;
|
|
7447
|
+
}
|
|
7448
|
+
get isCancelled() {
|
|
7449
|
+
this._trigger();
|
|
7450
|
+
return this._isCancelled;
|
|
7451
|
+
}
|
|
7452
|
+
get isErrored() {
|
|
7453
|
+
this._trigger();
|
|
7454
|
+
return this._isErrored;
|
|
7455
|
+
}
|
|
7456
|
+
get error() {
|
|
7457
|
+
this._trigger();
|
|
7458
|
+
return this._error;
|
|
7459
|
+
}
|
|
7460
|
+
get elapsedTime() {
|
|
7461
|
+
return (this.endTime || this.lastPacketTime) - this.startTime;
|
|
7462
|
+
}
|
|
7463
|
+
get completedRatio() {
|
|
7464
|
+
return this.sizeHint ? this.bytesLoaded / this.sizeHint : 0;
|
|
7465
|
+
}
|
|
7466
|
+
get remainingRatio() {
|
|
7467
|
+
return 1 - this.completedRatio;
|
|
7468
|
+
}
|
|
7469
|
+
get duration() {
|
|
7470
|
+
return this.endTime - this.startTime;
|
|
7471
|
+
}
|
|
7472
|
+
get speed() {
|
|
7473
|
+
// bytes per second
|
|
7474
|
+
return this.bytesLoaded / (this.elapsedTime / 1000);
|
|
7475
|
+
}
|
|
7476
|
+
constructor(future) {
|
|
7477
|
+
this._future = future;
|
|
7478
|
+
}
|
|
7479
|
+
abort = () => {
|
|
7480
|
+
this._future.abort();
|
|
7481
|
+
};
|
|
7482
|
+
}
|
|
7483
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isPending', true);
|
|
7484
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isStarted', false);
|
|
7485
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isComplete', false);
|
|
7486
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isCancelled', false);
|
|
7487
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_isErrored', false);
|
|
7488
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_error', null);
|
|
7489
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_sizeHint', 0);
|
|
7490
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_bytesLoaded', 0);
|
|
7491
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_startTime', 0);
|
|
7492
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_endTime', 0);
|
|
7493
|
+
defineNonEnumerableSignal(RequestLoadingState.prototype, '_lastPacketTime', 0);
|
|
7494
|
+
|
|
7495
|
+
/**
|
|
7496
|
+
* The state of a request in the "pending"
|
|
7497
|
+
* state. This is the default initial state.
|
|
7498
|
+
*
|
|
7499
|
+
* Extends the {@link PendingPromise} interface.
|
|
7500
|
+
*
|
|
7501
|
+
* @typedoc
|
|
7502
|
+
*/
|
|
7503
|
+
|
|
7504
|
+
/**
|
|
7505
|
+
* The state of a request in the "fulfilled" state.
|
|
7506
|
+
* This is the state of a request that has resolved
|
|
7507
|
+
* successfully.
|
|
7508
|
+
*
|
|
7509
|
+
* Extends the {@link ResolvedPromise} interface.
|
|
7510
|
+
*
|
|
7511
|
+
* @typedoc
|
|
7512
|
+
*/
|
|
7513
|
+
|
|
7514
|
+
/**
|
|
7515
|
+
* The state of a request in the "rejected" state.
|
|
7516
|
+
* This is the state of a request that has rejected
|
|
7517
|
+
* with an error.
|
|
7518
|
+
*
|
|
7519
|
+
* Extends the {@link RejectedPromise} interface.
|
|
7520
|
+
*
|
|
7521
|
+
* @typedoc
|
|
7522
|
+
*/
|
|
7523
|
+
|
|
7524
|
+
/**
|
|
7525
|
+
* The state of a request in the "cancelled" state.
|
|
7526
|
+
* This is the state of a promise that has been
|
|
7527
|
+
* cancelled.
|
|
7528
|
+
*
|
|
7529
|
+
* @typedoc
|
|
7530
|
+
*/
|
|
7531
|
+
|
|
7532
|
+
/**
|
|
7533
|
+
* RequestState extends the concept of PromiseState to provide a reactive
|
|
7534
|
+
* wrapper for a request `Future` which allows you write declarative code
|
|
7535
|
+
* around a Future's control flow.
|
|
7536
|
+
*
|
|
7537
|
+
* It is useful in both Template and JavaScript contexts, allowing you
|
|
7538
|
+
* to quickly derive behaviors and data from pending, error and success
|
|
7539
|
+
* states.
|
|
7540
|
+
*
|
|
7541
|
+
* The key difference between a Promise and a Future is that Futures provide
|
|
7542
|
+
* access to a stream of their content, the identity of the request (if any)
|
|
7543
|
+
* as well as the ability to attempt to abort the request.
|
|
7544
|
+
*
|
|
7545
|
+
* ```ts
|
|
7546
|
+
* interface Future<T> extends Promise<T>> {
|
|
7547
|
+
* getStream(): Promise<ReadableStream>;
|
|
7548
|
+
* abort(): void;
|
|
7549
|
+
* lid: StableDocumentIdentifier | null;
|
|
7550
|
+
* }
|
|
7551
|
+
* ```
|
|
7552
|
+
*
|
|
7553
|
+
* These additional APIs allow us to craft even richer state experiences.
|
|
7554
|
+
*
|
|
7555
|
+
* To get the state of a request, use `getRequestState`.
|
|
7556
|
+
*
|
|
7557
|
+
* See also:
|
|
7558
|
+
* - {@link PendingRequest}
|
|
7559
|
+
* - {@link ResolvedRequest}
|
|
7560
|
+
* - {@link RejectedRequest}
|
|
7561
|
+
* - {@link CancelledRequest}
|
|
7562
|
+
*
|
|
7563
|
+
* @typedoc
|
|
7564
|
+
*/
|
|
7565
|
+
|
|
7566
|
+
const RequestStateProto = {};
|
|
7567
|
+
|
|
7568
|
+
// TODO introduce a new mechanism for defining multiple properties
|
|
7569
|
+
// that share a common signal
|
|
7570
|
+
defineSignal(RequestStateProto, 'reason', null);
|
|
7571
|
+
defineSignal(RequestStateProto, 'value', null);
|
|
7572
|
+
defineSignal(RequestStateProto, 'result', null);
|
|
7573
|
+
defineSignal(RequestStateProto, 'error', null);
|
|
7574
|
+
defineSignal(RequestStateProto, 'status', 'pending');
|
|
7575
|
+
defineSignal(RequestStateProto, 'isPending', true);
|
|
7576
|
+
defineSignal(RequestStateProto, 'isLoading', true);
|
|
7577
|
+
defineSignal(RequestStateProto, 'isSuccess', false);
|
|
7578
|
+
defineSignal(RequestStateProto, 'isError', false);
|
|
7579
|
+
defineSignal(RequestStateProto, 'request', null);
|
|
7580
|
+
defineSignal(RequestStateProto, 'response', null);
|
|
7581
|
+
Object.defineProperty(RequestStateProto, 'isCancelled', {
|
|
7582
|
+
get() {
|
|
7583
|
+
return this.isError && isAbortError(this.reason);
|
|
7584
|
+
}
|
|
7585
|
+
});
|
|
7586
|
+
Object.defineProperty(RequestStateProto, 'loadingState', {
|
|
7587
|
+
get() {
|
|
7588
|
+
if (!this._loadingState) {
|
|
7589
|
+
this._loadingState = new RequestLoadingState(this._request);
|
|
7590
|
+
}
|
|
7591
|
+
return this._loadingState;
|
|
7592
|
+
}
|
|
7593
|
+
});
|
|
7594
|
+
function createRequestState(future) {
|
|
7595
|
+
const state = getPromiseResult(future);
|
|
7596
|
+
const promiseState = Object.create(RequestStateProto);
|
|
7597
|
+
promiseState._request = future;
|
|
7598
|
+
if (state) {
|
|
7599
|
+
if (state.isError) {
|
|
7600
|
+
promiseState.error = state.result;
|
|
7601
|
+
promiseState.reason = state.result;
|
|
7602
|
+
promiseState.status = 'rejected';
|
|
7603
|
+
promiseState.isError = true;
|
|
7604
|
+
promiseState.isPending = false;
|
|
7605
|
+
promiseState.isLoading = false;
|
|
7606
|
+
promiseState.request = state.result.request;
|
|
7607
|
+
promiseState.response = state.result.response;
|
|
7608
|
+
} else {
|
|
7609
|
+
promiseState.result = state.result.content;
|
|
7610
|
+
promiseState.value = state.result.content;
|
|
7611
|
+
promiseState.status = 'fulfilled';
|
|
7612
|
+
promiseState.isSuccess = true;
|
|
7613
|
+
promiseState.isPending = false;
|
|
7614
|
+
promiseState.isLoading = false;
|
|
7615
|
+
promiseState.request = state.result.request;
|
|
7616
|
+
promiseState.response = state.result.response;
|
|
7617
|
+
}
|
|
7618
|
+
} else {
|
|
7619
|
+
void future.then(result => {
|
|
7620
|
+
setPromiseResult(future, {
|
|
7621
|
+
isError: false,
|
|
7622
|
+
result
|
|
7623
|
+
});
|
|
7624
|
+
promiseState.result = result.content;
|
|
7625
|
+
promiseState.value = result.content;
|
|
7626
|
+
promiseState.status = 'fulfilled';
|
|
7627
|
+
promiseState.isSuccess = true;
|
|
7628
|
+
promiseState.isPending = false;
|
|
7629
|
+
promiseState.isLoading = false;
|
|
7630
|
+
promiseState.request = result.request;
|
|
7631
|
+
promiseState.response = result.response;
|
|
7632
|
+
}, error => {
|
|
7633
|
+
setPromiseResult(future, {
|
|
7634
|
+
isError: true,
|
|
7635
|
+
result: error
|
|
7636
|
+
});
|
|
7637
|
+
promiseState.error = error;
|
|
7638
|
+
promiseState.reason = error;
|
|
7639
|
+
promiseState.status = 'rejected';
|
|
7640
|
+
promiseState.isError = true;
|
|
7641
|
+
promiseState.isPending = false;
|
|
7642
|
+
promiseState.isLoading = false;
|
|
7643
|
+
promiseState.request = error.request;
|
|
7644
|
+
promiseState.response = error.response;
|
|
7645
|
+
});
|
|
7646
|
+
}
|
|
7647
|
+
return promiseState;
|
|
7648
|
+
}
|
|
7649
|
+
|
|
7650
|
+
/**
|
|
7651
|
+
* `getRequestState` can be used in both JavaScript and Template contexts.
|
|
7652
|
+
*
|
|
7653
|
+
* ```ts
|
|
7654
|
+
* import { getRequestState } from '@warp-drive/ember';
|
|
7655
|
+
*
|
|
7656
|
+
* const state = getRequestState(future);
|
|
7657
|
+
* ```
|
|
7658
|
+
*
|
|
7659
|
+
* For instance, we could write a getter on a component that updates whenever
|
|
7660
|
+
* the request state advances or the future changes, by combining the function
|
|
7661
|
+
* with the use of `@cached`
|
|
7662
|
+
*
|
|
7663
|
+
* ```ts
|
|
7664
|
+
* class Component {
|
|
7665
|
+
* @cached
|
|
7666
|
+
* get title() {
|
|
7667
|
+
* const state = getRequestState(this.args.request);
|
|
7668
|
+
* if (state.isPending) {
|
|
7669
|
+
* return 'loading...';
|
|
7670
|
+
* }
|
|
7671
|
+
* if (state.isError) { return null; }
|
|
7672
|
+
* return state.result.title;
|
|
7673
|
+
* }
|
|
7674
|
+
* }
|
|
7675
|
+
* ```
|
|
7676
|
+
*
|
|
7677
|
+
* Or in a template as a helper:
|
|
7678
|
+
*
|
|
7679
|
+
* ```gjs
|
|
7680
|
+
* import { getRequestState } from '@warp-drive/ember';
|
|
7681
|
+
*
|
|
7682
|
+
* <template>
|
|
7683
|
+
* {{#let (getRequestState @request) as |state|}}
|
|
7684
|
+
* {{#if state.isPending}}
|
|
7685
|
+
* <Spinner />
|
|
7686
|
+
* {{else if state.isError}}
|
|
7687
|
+
* <ErrorForm @error={{state.error}} />
|
|
7688
|
+
* {{else}}
|
|
7689
|
+
* <h1>{{state.result.title}}</h1>
|
|
7690
|
+
* {{/if}}
|
|
7691
|
+
* {{/let}}
|
|
7692
|
+
* </template>
|
|
7693
|
+
* ```
|
|
7694
|
+
*
|
|
7695
|
+
* If looking to use in a template, consider also the `<Request />` component
|
|
7696
|
+
* which offers a numbe of additional capabilities for requests *beyond* what
|
|
7697
|
+
* `RequestState` provides.
|
|
7698
|
+
*
|
|
7699
|
+
* @typedoc
|
|
7700
|
+
*/
|
|
7701
|
+
function getRequestState(future) {
|
|
7702
|
+
let state = RequestCache.get(future);
|
|
7703
|
+
if (!state) {
|
|
7704
|
+
state = createRequestState(future);
|
|
7705
|
+
RequestCache.set(future, state);
|
|
7706
|
+
}
|
|
7707
|
+
return state;
|
|
6918
7708
|
}
|
|
6919
|
-
export {
|
|
7709
|
+
export { memoized as A, gate as B, CacheHandler as C, entangleSignal as D, defineSignal as E, defineNonEnumerableSignal as F, Signals as G, peekInternalSignal as H, IdentifierArray as I, withSignalStore as J, notifyInternalSignal as K, consumeInternalSignal as L, MUTATE as M, getOrCreateInternalSignal as N, RecordArrayManager as R, Store as S, _clearCaches as _, setIdentifierGenerationMethod as a, setIdentifierUpdateMethod as b, setIdentifierForgetMethod as c, setIdentifierResetMethod as d, setKeyInfoForResource as e, isDocumentIdentifier as f, constructResource as g, coerceId as h, isStableIdentifier as i, ensureStringId as j, Collection as k, SOURCE as l, fastPush as m, removeRecordDataFor as n, setRecordIdentifier as o, peekCache as p, StoreMap as q, recordIdentifierFor as r, storeFor as s, setCacheFor as t, normalizeModelName as u, RelatedCollection as v, log as w, logGroup as x, getPromiseState as y, getRequestState as z };
|