@signalium/query 1.0.13 → 1.0.14
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/CHANGELOG.md +14 -0
- package/dist/cjs/development/index.js +2985 -0
- package/dist/cjs/development/index.js.map +1 -0
- package/dist/cjs/development/react/index.js +52 -0
- package/dist/cjs/development/react/index.js.map +1 -0
- package/dist/cjs/{stores/shared.js → development/shared-5acOO-tS.js} +11 -14
- package/dist/cjs/development/shared-5acOO-tS.js.map +1 -0
- package/dist/cjs/development/stores/async.js +304 -0
- package/dist/cjs/development/stores/async.js.map +1 -0
- package/dist/cjs/development/stores/sync.js +214 -0
- package/dist/cjs/development/stores/sync.js.map +1 -0
- package/dist/cjs/production/index.js +2985 -0
- package/dist/cjs/production/index.js.map +1 -0
- package/dist/cjs/production/package.json +3 -0
- package/dist/cjs/production/react/index.js +52 -0
- package/dist/cjs/production/react/index.js.map +1 -0
- package/dist/cjs/production/shared-5acOO-tS.js +20 -0
- package/dist/cjs/production/shared-5acOO-tS.js.map +1 -0
- package/dist/cjs/production/stores/async.js +304 -0
- package/dist/cjs/production/stores/async.js.map +1 -0
- package/dist/cjs/production/stores/sync.js +214 -0
- package/dist/cjs/production/stores/sync.js.map +1 -0
- package/dist/esm/EntityMap.d.ts +22 -0
- package/dist/esm/EntityMap.d.ts.map +1 -1
- package/dist/esm/MutationResult.d.ts +43 -0
- package/dist/esm/MutationResult.d.ts.map +1 -0
- package/dist/esm/QueryClient.d.ts +31 -2
- package/dist/esm/QueryClient.d.ts.map +1 -1
- package/dist/esm/development/index.js +2985 -0
- package/dist/esm/development/index.js.map +1 -0
- package/dist/esm/development/react/index.js +52 -0
- package/dist/esm/development/react/index.js.map +1 -0
- package/dist/esm/development/shared-Br5plsKm.js +21 -0
- package/dist/esm/development/shared-Br5plsKm.js.map +1 -0
- package/dist/esm/development/stores/async.js +304 -0
- package/dist/esm/development/stores/async.js.map +1 -0
- package/dist/esm/development/stores/sync.js +214 -0
- package/dist/esm/development/stores/sync.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/mutation.d.ts +82 -0
- package/dist/esm/mutation.d.ts.map +1 -0
- package/dist/esm/parseEntities.d.ts.map +1 -1
- package/dist/esm/production/index.js +2985 -0
- package/dist/esm/production/index.js.map +1 -0
- package/dist/esm/production/react/index.js +52 -0
- package/dist/esm/production/react/index.js.map +1 -0
- package/dist/esm/production/shared-Br5plsKm.js +21 -0
- package/dist/esm/production/shared-Br5plsKm.js.map +1 -0
- package/dist/esm/production/stores/async.js +304 -0
- package/dist/esm/production/stores/async.js.map +1 -0
- package/dist/esm/production/stores/sync.js +214 -0
- package/dist/esm/production/stores/sync.js.map +1 -0
- package/dist/esm/proxy.d.ts +6 -5
- package/dist/esm/proxy.d.ts.map +1 -1
- package/dist/esm/query.d.ts +3 -1
- package/dist/esm/query.d.ts.map +1 -1
- package/dist/esm/typeDefs.d.ts +4 -2
- package/dist/esm/typeDefs.d.ts.map +1 -1
- package/dist/esm/types.d.ts +71 -4
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/utils.d.ts +35 -0
- package/dist/esm/utils.d.ts.map +1 -1
- package/package.json +55 -21
- package/stores/async.js +1 -1
- package/stores/sync.js +1 -1
- package/dist/cjs/EntityMap.js +0 -103
- package/dist/cjs/EntityMap.js.map +0 -1
- package/dist/cjs/MemoryEvictionManager.js +0 -56
- package/dist/cjs/MemoryEvictionManager.js.map +0 -1
- package/dist/cjs/NetworkManager.js +0 -125
- package/dist/cjs/NetworkManager.js.map +0 -1
- package/dist/cjs/QueryClient.js +0 -162
- package/dist/cjs/QueryClient.js.map +0 -1
- package/dist/cjs/QueryResult.js +0 -920
- package/dist/cjs/QueryResult.js.map +0 -1
- package/dist/cjs/RefetchManager.js +0 -88
- package/dist/cjs/RefetchManager.js.map +0 -1
- package/dist/cjs/errors.js +0 -129
- package/dist/cjs/errors.js.map +0 -1
- package/dist/cjs/index.js +0 -43
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/parseEntities.js +0 -142
- package/dist/cjs/parseEntities.js.map +0 -1
- package/dist/cjs/pathInterpolator.js +0 -69
- package/dist/cjs/pathInterpolator.js.map +0 -1
- package/dist/cjs/proxy.js +0 -263
- package/dist/cjs/proxy.js.map +0 -1
- package/dist/cjs/query.js +0 -184
- package/dist/cjs/query.js.map +0 -1
- package/dist/cjs/react/index.js +0 -6
- package/dist/cjs/react/index.js.map +0 -1
- package/dist/cjs/react/use-query.js +0 -56
- package/dist/cjs/react/use-query.js.map +0 -1
- package/dist/cjs/stores/async.js +0 -344
- package/dist/cjs/stores/async.js.map +0 -1
- package/dist/cjs/stores/shared.js.map +0 -1
- package/dist/cjs/stores/sync.js +0 -240
- package/dist/cjs/stores/sync.js.map +0 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +0 -1
- package/dist/cjs/type-utils.js +0 -3
- package/dist/cjs/type-utils.js.map +0 -1
- package/dist/cjs/typeDefs.js +0 -620
- package/dist/cjs/typeDefs.js.map +0 -1
- package/dist/cjs/types.js +0 -33
- package/dist/cjs/types.js.map +0 -1
- package/dist/cjs/utils.js +0 -23
- package/dist/cjs/utils.js.map +0 -1
- package/dist/esm/EntityMap.js +0 -99
- package/dist/esm/EntityMap.js.map +0 -1
- package/dist/esm/MemoryEvictionManager.js +0 -51
- package/dist/esm/MemoryEvictionManager.js.map +0 -1
- package/dist/esm/NetworkManager.js +0 -120
- package/dist/esm/NetworkManager.js.map +0 -1
- package/dist/esm/QueryClient.js +0 -154
- package/dist/esm/QueryClient.js.map +0 -1
- package/dist/esm/QueryResult.js +0 -916
- package/dist/esm/QueryResult.js.map +0 -1
- package/dist/esm/RefetchManager.js +0 -83
- package/dist/esm/RefetchManager.js.map +0 -1
- package/dist/esm/errors.js +0 -125
- package/dist/esm/errors.js.map +0 -1
- package/dist/esm/index.js +0 -8
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/parseEntities.js +0 -135
- package/dist/esm/parseEntities.js.map +0 -1
- package/dist/esm/pathInterpolator.js +0 -66
- package/dist/esm/pathInterpolator.js.map +0 -1
- package/dist/esm/proxy.js +0 -254
- package/dist/esm/proxy.js.map +0 -1
- package/dist/esm/query.js +0 -177
- package/dist/esm/query.js.map +0 -1
- package/dist/esm/react/index.js +0 -2
- package/dist/esm/react/index.js.map +0 -1
- package/dist/esm/react/use-query.js +0 -53
- package/dist/esm/react/use-query.js.map +0 -1
- package/dist/esm/stores/async.js +0 -340
- package/dist/esm/stores/async.js.map +0 -1
- package/dist/esm/stores/shared.js +0 -13
- package/dist/esm/stores/shared.js.map +0 -1
- package/dist/esm/stores/sync.js +0 -234
- package/dist/esm/stores/sync.js.map +0 -1
- package/dist/esm/type-utils.js +0 -2
- package/dist/esm/type-utils.js.map +0 -1
- package/dist/esm/typeDefs.js +0 -606
- package/dist/esm/typeDefs.js.map +0 -1
- package/dist/esm/types.js +0 -30
- package/dist/esm/types.js.map +0 -1
- package/dist/esm/utils.js +0 -20
- package/dist/esm/utils.js.map +0 -1
- /package/dist/cjs/{package.json → development/package.json} +0 -0
package/dist/cjs/QueryResult.js
DELETED
|
@@ -1,920 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.QueryResultImpl = void 0;
|
|
4
|
-
const signalium_1 = require("signalium");
|
|
5
|
-
const utils_1 = require("signalium/utils");
|
|
6
|
-
const types_js_1 = require("./types.js");
|
|
7
|
-
const proxy_js_1 = require("./proxy.js");
|
|
8
|
-
const parseEntities_js_1 = require("./parseEntities.js");
|
|
9
|
-
const typeDefs_js_1 = require("./typeDefs.js");
|
|
10
|
-
const QueryClient_js_1 = require("./QueryClient.js");
|
|
11
|
-
// ======================================================
|
|
12
|
-
// QueryResultExtra - Manages stream orphans and optimistic inserts
|
|
13
|
-
// ======================================================
|
|
14
|
-
/**
|
|
15
|
-
* Manages extra data for a query result: stream orphans and optimistic inserts.
|
|
16
|
-
* Created lazily when first needed.
|
|
17
|
-
*/
|
|
18
|
-
class QueryResultExtra {
|
|
19
|
-
_streamOrphansNotifier = undefined;
|
|
20
|
-
_streamOrphans = undefined;
|
|
21
|
-
_optimisticInsertsNotifier = undefined;
|
|
22
|
-
_optimisticInserts = undefined;
|
|
23
|
-
onChanged;
|
|
24
|
-
constructor(onChanged) {
|
|
25
|
-
this.onChanged = onChanged;
|
|
26
|
-
}
|
|
27
|
-
get streamOrphansNotifier() {
|
|
28
|
-
return this._streamOrphansNotifier ?? (this._streamOrphansNotifier = (0, signalium_1.notifier)());
|
|
29
|
-
}
|
|
30
|
-
get optimisticInsertsNotifier() {
|
|
31
|
-
return this._optimisticInsertsNotifier ?? (this._optimisticInsertsNotifier = (0, signalium_1.notifier)());
|
|
32
|
-
}
|
|
33
|
-
get streamOrphans() {
|
|
34
|
-
return this._streamOrphans ?? (this._streamOrphans = new Set());
|
|
35
|
-
}
|
|
36
|
-
get optimisticInserts() {
|
|
37
|
-
return this._optimisticInserts ?? (this._optimisticInserts = new Set());
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Returns the QueryExtra object for public API consumption.
|
|
41
|
-
* Consumes the notifiers to establish reactive tracking.
|
|
42
|
-
*/
|
|
43
|
-
getExtra() {
|
|
44
|
-
this.streamOrphansNotifier.consume();
|
|
45
|
-
this.optimisticInsertsNotifier.consume();
|
|
46
|
-
return {
|
|
47
|
-
streamOrphans: this.streamOrphans,
|
|
48
|
-
optimisticInserts: this.optimisticInserts,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Add a stream orphan entity.
|
|
53
|
-
* Returns true if the orphan was added (not a duplicate).
|
|
54
|
-
*/
|
|
55
|
-
addStreamOrphan(entity) {
|
|
56
|
-
const orphans = this.streamOrphans;
|
|
57
|
-
const sizeBefore = orphans.size;
|
|
58
|
-
orphans.add(entity);
|
|
59
|
-
if (orphans.size !== sizeBefore) {
|
|
60
|
-
this.streamOrphansNotifier.notify();
|
|
61
|
-
// Check if this orphan was an optimistic insert - if so, remove it
|
|
62
|
-
const proxyId = (0, proxy_js_1.getProxyId)(entity);
|
|
63
|
-
if (proxyId !== undefined) {
|
|
64
|
-
this.removeOptimisticInsertById(proxyId);
|
|
65
|
-
}
|
|
66
|
-
this.onChanged();
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Add an optimistic insert entity.
|
|
73
|
-
* Returns true if the insert was added (not a duplicate).
|
|
74
|
-
*/
|
|
75
|
-
addOptimisticInsert(entity) {
|
|
76
|
-
const inserts = this.optimisticInserts;
|
|
77
|
-
const sizeBefore = inserts.size;
|
|
78
|
-
inserts.add(entity);
|
|
79
|
-
if (inserts.size !== sizeBefore) {
|
|
80
|
-
this.optimisticInsertsNotifier.notify();
|
|
81
|
-
this.onChanged();
|
|
82
|
-
return true;
|
|
83
|
-
}
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Remove an optimistic insert by its entity.
|
|
88
|
-
* Returns true if the insert was removed.
|
|
89
|
-
*/
|
|
90
|
-
removeOptimisticInsert(entity) {
|
|
91
|
-
const proxyId = (0, proxy_js_1.getProxyId)(entity);
|
|
92
|
-
if (proxyId === undefined) {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
return this.removeOptimisticInsertById(proxyId);
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Remove an optimistic insert by proxy ID.
|
|
99
|
-
*/
|
|
100
|
-
removeOptimisticInsertById(proxyId) {
|
|
101
|
-
const inserts = this._optimisticInserts;
|
|
102
|
-
if (inserts === undefined || inserts.size === 0) {
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
for (const existing of inserts) {
|
|
106
|
-
if ((0, proxy_js_1.getProxyId)(existing) === proxyId) {
|
|
107
|
-
inserts.delete(existing);
|
|
108
|
-
this.optimisticInsertsNotifier.notify();
|
|
109
|
-
this.onChanged();
|
|
110
|
-
return true;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Check if a proxy ID exists in stream orphans.
|
|
117
|
-
*/
|
|
118
|
-
hasOrphanWithId(proxyId) {
|
|
119
|
-
const orphans = this._streamOrphans;
|
|
120
|
-
if (orphans === undefined) {
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
for (const orphan of orphans) {
|
|
124
|
-
if ((0, proxy_js_1.getProxyId)(orphan) === proxyId) {
|
|
125
|
-
return true;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Reconcile orphans and optimistic inserts against the main response entity refs.
|
|
132
|
-
* Removes any that now exist in the main response.
|
|
133
|
-
*/
|
|
134
|
-
reconcile(allRefIds) {
|
|
135
|
-
// Check stream orphans for entities that now exist in main response
|
|
136
|
-
const orphans = this._streamOrphans;
|
|
137
|
-
if (orphans !== undefined && orphans.size > 0) {
|
|
138
|
-
let orphansChanged = false;
|
|
139
|
-
for (const orphan of orphans) {
|
|
140
|
-
const entityRefId = (0, proxy_js_1.getProxyId)(orphan);
|
|
141
|
-
if (entityRefId !== undefined && allRefIds.has(entityRefId)) {
|
|
142
|
-
orphans.delete(orphan);
|
|
143
|
-
orphansChanged = true;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
if (orphansChanged) {
|
|
147
|
-
this.streamOrphansNotifier.notify();
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
// Check optimistic inserts for entities that now exist in main response or stream orphans
|
|
151
|
-
const inserts = this._optimisticInserts;
|
|
152
|
-
if (inserts !== undefined && inserts.size > 0) {
|
|
153
|
-
let insertsChanged = false;
|
|
154
|
-
for (const insert of inserts) {
|
|
155
|
-
const entityRefId = (0, proxy_js_1.getProxyId)(insert);
|
|
156
|
-
if (entityRefId !== undefined) {
|
|
157
|
-
// Remove if entity is now in main response
|
|
158
|
-
if (allRefIds.has(entityRefId)) {
|
|
159
|
-
inserts.delete(insert);
|
|
160
|
-
insertsChanged = true;
|
|
161
|
-
}
|
|
162
|
-
// Also remove if entity is now in stream orphans
|
|
163
|
-
else if (orphans !== undefined && orphans.has(insert)) {
|
|
164
|
-
inserts.delete(insert);
|
|
165
|
-
insertsChanged = true;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
if (insertsChanged) {
|
|
170
|
-
this.optimisticInsertsNotifier.notify();
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Clear all stream orphans and optimistic inserts.
|
|
176
|
-
* Called on refetch.
|
|
177
|
-
*/
|
|
178
|
-
clear() {
|
|
179
|
-
let changed = false;
|
|
180
|
-
if (this._streamOrphans !== undefined && this._streamOrphans.size > 0) {
|
|
181
|
-
this._streamOrphans = undefined;
|
|
182
|
-
this.streamOrphansNotifier.notify();
|
|
183
|
-
changed = true;
|
|
184
|
-
}
|
|
185
|
-
if (this._optimisticInserts !== undefined && this._optimisticInserts.size > 0) {
|
|
186
|
-
this._optimisticInserts = undefined;
|
|
187
|
-
this.optimisticInsertsNotifier.notify();
|
|
188
|
-
changed = true;
|
|
189
|
-
}
|
|
190
|
-
if (changed) {
|
|
191
|
-
this.onChanged();
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Load extra data from cached values.
|
|
196
|
-
*/
|
|
197
|
-
loadFromCache(cachedExtra, queryClient, streamShape, optimisticInsertsShape) {
|
|
198
|
-
if (cachedExtra.streamOrphanRefs && cachedExtra.streamOrphanRefs.length > 0 && streamShape) {
|
|
199
|
-
const orphans = this.streamOrphans;
|
|
200
|
-
for (const refId of cachedExtra.streamOrphanRefs) {
|
|
201
|
-
const entityRecord = queryClient.hydrateEntity(refId, streamShape);
|
|
202
|
-
orphans.add(entityRecord.proxy);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
if (cachedExtra.optimisticInsertRefs && cachedExtra.optimisticInsertRefs.length > 0 && optimisticInsertsShape) {
|
|
206
|
-
const inserts = this.optimisticInserts;
|
|
207
|
-
for (const refId of cachedExtra.optimisticInsertRefs) {
|
|
208
|
-
const entityRecord = queryClient.hydrateEntity(refId, optimisticInsertsShape);
|
|
209
|
-
inserts.add(entityRecord.proxy);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Get extra data for persistence (converts Sets to arrays of entity ref IDs).
|
|
215
|
-
*/
|
|
216
|
-
getForPersistence() {
|
|
217
|
-
const orphans = this._streamOrphans;
|
|
218
|
-
const inserts = this._optimisticInserts;
|
|
219
|
-
if ((orphans === undefined || orphans.size === 0) && (inserts === undefined || inserts.size === 0)) {
|
|
220
|
-
return undefined;
|
|
221
|
-
}
|
|
222
|
-
const extra = {};
|
|
223
|
-
if (orphans !== undefined && orphans.size > 0) {
|
|
224
|
-
extra.streamOrphanRefs = [];
|
|
225
|
-
for (const orphan of orphans) {
|
|
226
|
-
const refId = (0, proxy_js_1.getProxyId)(orphan);
|
|
227
|
-
if (refId !== undefined) {
|
|
228
|
-
extra.streamOrphanRefs.push(refId);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
if (inserts !== undefined && inserts.size > 0) {
|
|
233
|
-
extra.optimisticInsertRefs = [];
|
|
234
|
-
for (const insert of inserts) {
|
|
235
|
-
const refId = (0, proxy_js_1.getProxyId)(insert);
|
|
236
|
-
if (refId !== undefined) {
|
|
237
|
-
extra.optimisticInsertRefs.push(refId);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
return extra;
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Check if there's any extra data.
|
|
245
|
-
*/
|
|
246
|
-
get hasData() {
|
|
247
|
-
return ((this._streamOrphans !== undefined && this._streamOrphans.size > 0) ||
|
|
248
|
-
(this._optimisticInserts !== undefined && this._optimisticInserts.size > 0));
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
// ======================================================
|
|
252
|
-
// QueryResultImpl
|
|
253
|
-
// ======================================================
|
|
254
|
-
/**
|
|
255
|
-
* QueryResult wraps a DiscriminatedReactivePromise and adds additional functionality
|
|
256
|
-
* like refetch, while forwarding all the base relay properties.
|
|
257
|
-
* This class combines the old QueryInstance and QueryResultImpl into a single entity.
|
|
258
|
-
*/
|
|
259
|
-
class QueryResultImpl {
|
|
260
|
-
def;
|
|
261
|
-
queryKey; // Instance key (includes Signal identity)
|
|
262
|
-
storageKey = -1; // Storage key (extracted values only)
|
|
263
|
-
queryClient;
|
|
264
|
-
initialized = false;
|
|
265
|
-
isRefetchingSignal = (0, signalium_1.signal)(false);
|
|
266
|
-
isFetchingMoreSignal = (0, signalium_1.signal)(false);
|
|
267
|
-
updatedAt = undefined;
|
|
268
|
-
params = undefined;
|
|
269
|
-
refIds = undefined;
|
|
270
|
-
allNestedRefIdsSignal = undefined;
|
|
271
|
-
refetchPromise = undefined;
|
|
272
|
-
fetchMorePromise = undefined;
|
|
273
|
-
unsubscribe = undefined;
|
|
274
|
-
relay;
|
|
275
|
-
_relayState = undefined;
|
|
276
|
-
wasPaused = false;
|
|
277
|
-
currentParams = undefined;
|
|
278
|
-
debounceTimer = undefined;
|
|
279
|
-
get relayState() {
|
|
280
|
-
const relayState = this._relayState;
|
|
281
|
-
if (!relayState) {
|
|
282
|
-
throw new Error('Relay state not initialized');
|
|
283
|
-
}
|
|
284
|
-
return relayState;
|
|
285
|
-
}
|
|
286
|
-
_extra = undefined;
|
|
287
|
-
get extraData() {
|
|
288
|
-
return this._extra ?? (this._extra = new QueryResultExtra(() => this.persistExtraData()));
|
|
289
|
-
}
|
|
290
|
-
_nextPageParams = undefined;
|
|
291
|
-
get nextPageParams() {
|
|
292
|
-
// Streams and non-infinite queries don't have pagination
|
|
293
|
-
if (this.def.type !== "infiniteQuery" /* QueryType.InfiniteQuery */) {
|
|
294
|
-
return null;
|
|
295
|
-
}
|
|
296
|
-
let params = this._nextPageParams;
|
|
297
|
-
const value = this.relayState.value;
|
|
298
|
-
if (params === undefined && value !== undefined) {
|
|
299
|
-
if (!Array.isArray(value)) {
|
|
300
|
-
throw new Error('Query result is not an array, this is a bug');
|
|
301
|
-
}
|
|
302
|
-
const infiniteDef = this.def;
|
|
303
|
-
const nextParams = infiniteDef.pagination?.getNextPageParams?.(value[value.length - 1]);
|
|
304
|
-
if (nextParams === undefined) {
|
|
305
|
-
// store null to indicate that there is no next page, but we've already calculated
|
|
306
|
-
params = null;
|
|
307
|
-
}
|
|
308
|
-
else {
|
|
309
|
-
// Clone current params
|
|
310
|
-
let hasDefinedParams = false;
|
|
311
|
-
const clonedParams = { ...this.currentParams };
|
|
312
|
-
// iterate over the next page params and copy any defined values to the
|
|
313
|
-
for (const [key, value] of Object.entries(nextParams)) {
|
|
314
|
-
if (value !== undefined && value !== null) {
|
|
315
|
-
clonedParams[key] = value;
|
|
316
|
-
hasDefinedParams = true;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
this._nextPageParams = params = hasDefinedParams ? clonedParams : null;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return params ?? null;
|
|
323
|
-
}
|
|
324
|
-
constructor(def, queryClient, queryKey, params) {
|
|
325
|
-
(0, utils_1.setReactivePromise)(this);
|
|
326
|
-
this.def = def;
|
|
327
|
-
this.queryClient = queryClient;
|
|
328
|
-
this.queryKey = queryKey; // Instance key (Signal identity)
|
|
329
|
-
this.params = params;
|
|
330
|
-
// Create the relay and handle activation/deactivation
|
|
331
|
-
this.relay = (0, signalium_1.relay)(state => {
|
|
332
|
-
this._relayState = state;
|
|
333
|
-
// Extract params (reading Signal values establishes tracking)
|
|
334
|
-
this.currentParams = (0, QueryClient_js_1.extractParamsForKey)(this.params);
|
|
335
|
-
this.storageKey = (0, QueryClient_js_1.queryKeyFor)(this.def, this.currentParams);
|
|
336
|
-
// Load from cache first, then fetch fresh data
|
|
337
|
-
this.queryClient.activateQuery(this);
|
|
338
|
-
// Store initial offline state
|
|
339
|
-
const isPaused = this.isPaused;
|
|
340
|
-
this.wasPaused = isPaused;
|
|
341
|
-
if (this.initialized) {
|
|
342
|
-
if (!isPaused) {
|
|
343
|
-
// For any query with streams, resubscribe on reactivation
|
|
344
|
-
if (this.def.type === "stream" /* QueryType.Stream */ ||
|
|
345
|
-
this.def.stream) {
|
|
346
|
-
this.setupSubscription();
|
|
347
|
-
}
|
|
348
|
-
if (this.def.type !== "stream" /* QueryType.Stream */ && this.isStale) {
|
|
349
|
-
this.refetch();
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
else {
|
|
354
|
-
this.initialize();
|
|
355
|
-
}
|
|
356
|
-
const deactivate = () => {
|
|
357
|
-
// Clear debounce timer if active
|
|
358
|
-
clearTimeout(this.debounceTimer);
|
|
359
|
-
this.debounceTimer = undefined;
|
|
360
|
-
// Last subscriber left, deactivate refetch and schedule memory eviction
|
|
361
|
-
// Unsubscribe from any active streams
|
|
362
|
-
this.unsubscribe?.();
|
|
363
|
-
this.unsubscribe = undefined;
|
|
364
|
-
// Remove from refetch manager if configured
|
|
365
|
-
if (this.def.type !== "stream" /* QueryType.Stream */ && this.def.cache?.refetchInterval) {
|
|
366
|
-
this.queryClient.refetchManager.removeQuery(this);
|
|
367
|
-
}
|
|
368
|
-
// Schedule removal from memory using the global eviction manager
|
|
369
|
-
// This allows quick reactivation from memory if needed again soon
|
|
370
|
-
// Disk cache (if configured) will still be available after eviction
|
|
371
|
-
// Use queryKey for instance eviction, storageKey for cache eviction
|
|
372
|
-
this.queryClient.memoryEvictionManager.scheduleEviction(this.queryKey);
|
|
373
|
-
};
|
|
374
|
-
// Return deactivation callback
|
|
375
|
-
return {
|
|
376
|
-
update: () => {
|
|
377
|
-
const { wasPaused, isPaused } = this;
|
|
378
|
-
this.wasPaused = isPaused;
|
|
379
|
-
if (isPaused) {
|
|
380
|
-
deactivate();
|
|
381
|
-
// TODO: Add abort signal
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
// Read Signal values again to establish tracking for any new Signals
|
|
385
|
-
// Extract params (reading Signal values establishes tracking)
|
|
386
|
-
const newExtractedParams = (0, QueryClient_js_1.extractParamsForKey)(this.params);
|
|
387
|
-
const newStorageKey = (0, QueryClient_js_1.queryKeyFor)(this.def, newExtractedParams);
|
|
388
|
-
const paramsDidChange = newStorageKey !== this.storageKey;
|
|
389
|
-
// Check if storage key changed (comparing hash values)
|
|
390
|
-
if (paramsDidChange) {
|
|
391
|
-
// Same storage key, just Signal instances changed but values are the same
|
|
392
|
-
// Update params and trigger debounced refetch
|
|
393
|
-
this.params = newExtractedParams;
|
|
394
|
-
this.storageKey = newStorageKey;
|
|
395
|
-
}
|
|
396
|
-
if (wasPaused) {
|
|
397
|
-
this.queryClient.activateQuery(this);
|
|
398
|
-
if (this.def.type !== "stream" /* QueryType.Stream */) {
|
|
399
|
-
const refreshStaleOnReconnect = this.def.cache?.refreshStaleOnReconnect ?? true;
|
|
400
|
-
if (refreshStaleOnReconnect && this.isStale) {
|
|
401
|
-
state.setPromise(this.runQuery(this.currentParams, true));
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
else {
|
|
405
|
-
this.setupSubscription();
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
else if (paramsDidChange) {
|
|
409
|
-
if (this.def.type !== "stream" /* QueryType.Stream */) {
|
|
410
|
-
this.debouncedRefetch();
|
|
411
|
-
}
|
|
412
|
-
else {
|
|
413
|
-
this.setupSubscription();
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
},
|
|
417
|
-
deactivate,
|
|
418
|
-
};
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
// ======================================================
|
|
422
|
-
// ReactivePromise properties
|
|
423
|
-
// =====================================================
|
|
424
|
-
get value() {
|
|
425
|
-
return this.relay.value;
|
|
426
|
-
}
|
|
427
|
-
get error() {
|
|
428
|
-
return this.relay.error;
|
|
429
|
-
}
|
|
430
|
-
get isPending() {
|
|
431
|
-
return this.relay.isPending;
|
|
432
|
-
}
|
|
433
|
-
get isRejected() {
|
|
434
|
-
return this.relay.isRejected;
|
|
435
|
-
}
|
|
436
|
-
get isResolved() {
|
|
437
|
-
return this.relay.isResolved;
|
|
438
|
-
}
|
|
439
|
-
get isSettled() {
|
|
440
|
-
return this.relay.isSettled;
|
|
441
|
-
}
|
|
442
|
-
get isReady() {
|
|
443
|
-
return this.relay.isReady;
|
|
444
|
-
}
|
|
445
|
-
// TODO: Intimate APIs needed for `useReactive`, this is a code smell and
|
|
446
|
-
// we should find a better way to entangle these more generically
|
|
447
|
-
get _version() {
|
|
448
|
-
return this.relay._version;
|
|
449
|
-
}
|
|
450
|
-
get _signal() {
|
|
451
|
-
return this.relay._signal;
|
|
452
|
-
}
|
|
453
|
-
get _flags() {
|
|
454
|
-
return this.relay._flags;
|
|
455
|
-
}
|
|
456
|
-
// Forward Promise methods
|
|
457
|
-
then(onfulfilled, onrejected) {
|
|
458
|
-
return this.relay.then(onfulfilled, onrejected);
|
|
459
|
-
}
|
|
460
|
-
catch(onrejected) {
|
|
461
|
-
return this.relay.catch(onrejected);
|
|
462
|
-
}
|
|
463
|
-
finally(onfinally) {
|
|
464
|
-
return this.relay.finally(onfinally);
|
|
465
|
-
}
|
|
466
|
-
get [Symbol.toStringTag]() {
|
|
467
|
-
return 'QueryResult';
|
|
468
|
-
}
|
|
469
|
-
// ======================================================
|
|
470
|
-
// Internal fetch methods
|
|
471
|
-
// ======================================================
|
|
472
|
-
getAllEntityRefs() {
|
|
473
|
-
let allNestedRefIdsSignal = this.allNestedRefIdsSignal;
|
|
474
|
-
if (!allNestedRefIdsSignal) {
|
|
475
|
-
const queryClient = this.queryClient;
|
|
476
|
-
this.allNestedRefIdsSignal = allNestedRefIdsSignal = (0, signalium_1.reactiveSignal)(() => {
|
|
477
|
-
// Entangle the relay value. Whenever the relay value is updated, the
|
|
478
|
-
// allNestedRefIdsSignal will be updated, so no need for a second signal.
|
|
479
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
480
|
-
this.relay.value;
|
|
481
|
-
const allRefIds = new Set();
|
|
482
|
-
if (this.refIds !== undefined) {
|
|
483
|
-
for (const refId of this.refIds) {
|
|
484
|
-
queryClient.getNestedEntityRefIds(refId, allRefIds);
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
// Reconcile extra data against the main response
|
|
488
|
-
this.extraData.reconcile(allRefIds);
|
|
489
|
-
return allRefIds;
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
return allNestedRefIdsSignal.value;
|
|
493
|
-
}
|
|
494
|
-
/**
|
|
495
|
-
* Initialize the query by loading from cache and fetching if stale
|
|
496
|
-
*/
|
|
497
|
-
async initialize() {
|
|
498
|
-
const state = this.relayState;
|
|
499
|
-
this.initialized = true;
|
|
500
|
-
let cached;
|
|
501
|
-
try {
|
|
502
|
-
// Load from cache first (use storage key for cache operations)
|
|
503
|
-
cached = await this.queryClient.loadCachedQuery(this.def, this.storageKey);
|
|
504
|
-
if (cached !== undefined) {
|
|
505
|
-
// Set the cached timestamp
|
|
506
|
-
this.updatedAt = cached.updatedAt;
|
|
507
|
-
// Set the cached reference IDs
|
|
508
|
-
this.refIds = cached.refIds;
|
|
509
|
-
// Load extra data (stream orphans and optimistic inserts) BEFORE setting state.value
|
|
510
|
-
// because setting state.value resolves the relay
|
|
511
|
-
if (cached.extra) {
|
|
512
|
-
const def = this.def;
|
|
513
|
-
this.extraData.loadFromCache(cached.extra, this.queryClient, def.stream?.shape, def.optimisticInserts?.shape);
|
|
514
|
-
}
|
|
515
|
-
// Set the value last - this resolves the relay
|
|
516
|
-
const shape = this.def.shape;
|
|
517
|
-
state.value =
|
|
518
|
-
shape instanceof typeDefs_js_1.ValidatorDef
|
|
519
|
-
? (0, parseEntities_js_1.parseEntities)(cached.value, shape, this.queryClient, new Set())
|
|
520
|
-
: (0, proxy_js_1.parseValue)(cached.value, shape, this.def.id);
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
catch (error) {
|
|
524
|
-
this.queryClient.deleteCachedQuery(this.storageKey);
|
|
525
|
-
this.queryClient
|
|
526
|
-
.getContext()
|
|
527
|
-
.log?.warn?.('Failed to initialize query, the query cache may be corrupted or invalid', error);
|
|
528
|
-
}
|
|
529
|
-
if (this.isPaused) {
|
|
530
|
-
return;
|
|
531
|
-
}
|
|
532
|
-
try {
|
|
533
|
-
// Setup subscriptions (handles both StreamQuery and Query/InfiniteQuery with stream)
|
|
534
|
-
if (this.def.type === "stream" /* QueryType.Stream */ ||
|
|
535
|
-
this.def.stream) {
|
|
536
|
-
this.setupSubscription();
|
|
537
|
-
}
|
|
538
|
-
// For non-stream queries, fetch if stale or no cache
|
|
539
|
-
if (this.def.type !== "stream" /* QueryType.Stream */) {
|
|
540
|
-
if (cached !== undefined) {
|
|
541
|
-
// Check if data is stale
|
|
542
|
-
if (this.isStale) {
|
|
543
|
-
// Data is stale, trigger background refetch (with debounce if configured)
|
|
544
|
-
if (this.def.debounce !== undefined && this.def.debounce > 0) {
|
|
545
|
-
this.debouncedRefetch();
|
|
546
|
-
}
|
|
547
|
-
else {
|
|
548
|
-
this.refetch();
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
else {
|
|
553
|
-
// No cached data, fetch fresh immediately (don't debounce initial fetch)
|
|
554
|
-
// Debounce only applies to refetches triggered by parameter changes
|
|
555
|
-
state.setPromise(this.runQuery(this.currentParams, true));
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
catch (error) {
|
|
560
|
-
// Relay will handle the error state automatically
|
|
561
|
-
state.setError(error);
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
/**
|
|
565
|
-
* Handle stream updates. This method handles both StreamQuery and Query/InfiniteQuery with stream options.
|
|
566
|
-
* - For StreamQuery: directly updates the relay state with the entity
|
|
567
|
-
* - For Query/InfiniteQuery with stream: updates entities in response or adds to orphans
|
|
568
|
-
*/
|
|
569
|
-
setupSubscription() {
|
|
570
|
-
this.unsubscribe?.();
|
|
571
|
-
let subscribeFn;
|
|
572
|
-
let shapeDef;
|
|
573
|
-
if (this.def.type === "stream" /* QueryType.Stream */) {
|
|
574
|
-
shapeDef = this.def.shape;
|
|
575
|
-
subscribeFn = this.def.subscribeFn;
|
|
576
|
-
}
|
|
577
|
-
else {
|
|
578
|
-
const stream = this.def.stream;
|
|
579
|
-
if (!stream) {
|
|
580
|
-
return;
|
|
581
|
-
}
|
|
582
|
-
shapeDef = stream.shape;
|
|
583
|
-
subscribeFn = stream.subscribeFn;
|
|
584
|
-
}
|
|
585
|
-
// Extract params (reading Signal values establishes tracking)
|
|
586
|
-
const extractedParams = this.currentParams;
|
|
587
|
-
this.unsubscribe = subscribeFn(this.queryClient.getContext(), extractedParams, update => {
|
|
588
|
-
const parsedData = (0, parseEntities_js_1.parseObjectEntities)(update, shapeDef, this.queryClient);
|
|
589
|
-
// Update the relay state
|
|
590
|
-
if (this.def.type === "stream" /* QueryType.Stream */) {
|
|
591
|
-
this.relayState.value = parsedData;
|
|
592
|
-
this.updatedAt = Date.now();
|
|
593
|
-
// Cache the data
|
|
594
|
-
// Use storage key for cache operations
|
|
595
|
-
this.queryClient.saveQueryData(this.def, this.storageKey, parsedData, this.updatedAt);
|
|
596
|
-
}
|
|
597
|
-
else {
|
|
598
|
-
const allRefIds = this.getAllEntityRefs();
|
|
599
|
-
const proxyId = (0, proxy_js_1.getProxyId)(parsedData);
|
|
600
|
-
// Add to orphans if not in main response
|
|
601
|
-
if (proxyId !== undefined && !allRefIds.has(proxyId)) {
|
|
602
|
-
this.extraData.addStreamOrphan(parsedData);
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
});
|
|
606
|
-
}
|
|
607
|
-
/**
|
|
608
|
-
* Fetches fresh data, updates the cache, and updates updatedAt timestamp
|
|
609
|
-
*/
|
|
610
|
-
async runQuery(params, reset = false) {
|
|
611
|
-
// Check if paused before attempting fetch
|
|
612
|
-
if (this.isPaused) {
|
|
613
|
-
throw new Error('Query is paused due to network status');
|
|
614
|
-
}
|
|
615
|
-
const { retries, retryDelay } = this.getRetryConfig();
|
|
616
|
-
let lastError;
|
|
617
|
-
// Attempt fetch with retries
|
|
618
|
-
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
619
|
-
try {
|
|
620
|
-
const queryDef = this.def;
|
|
621
|
-
const freshData = await queryDef.fetchFn(this.queryClient.getContext(), params);
|
|
622
|
-
// Parse and cache the fresh data
|
|
623
|
-
let entityRefs;
|
|
624
|
-
const isInfinite = this.def.type === "infiniteQuery" /* QueryType.InfiniteQuery */;
|
|
625
|
-
if (isInfinite && !reset && this.refIds !== undefined) {
|
|
626
|
-
entityRefs = this.refIds;
|
|
627
|
-
}
|
|
628
|
-
else {
|
|
629
|
-
entityRefs = this.refIds = new Set();
|
|
630
|
-
}
|
|
631
|
-
const shape = this.def.shape;
|
|
632
|
-
const parsedData = shape instanceof typeDefs_js_1.ValidatorDef
|
|
633
|
-
? (0, parseEntities_js_1.parseEntities)(freshData, shape, this.queryClient, entityRefs)
|
|
634
|
-
: (0, proxy_js_1.parseValue)(freshData, shape, this.def.id);
|
|
635
|
-
let queryData;
|
|
636
|
-
if (isInfinite) {
|
|
637
|
-
const prevQueryData = this.relayState.value;
|
|
638
|
-
queryData = reset || prevQueryData === undefined ? [parsedData] : [...prevQueryData, parsedData];
|
|
639
|
-
}
|
|
640
|
-
else {
|
|
641
|
-
queryData = parsedData;
|
|
642
|
-
}
|
|
643
|
-
let updatedAt;
|
|
644
|
-
if (reset) {
|
|
645
|
-
updatedAt = this.updatedAt = Date.now();
|
|
646
|
-
}
|
|
647
|
-
else {
|
|
648
|
-
updatedAt = this.updatedAt ??= Date.now();
|
|
649
|
-
}
|
|
650
|
-
this._nextPageParams = undefined;
|
|
651
|
-
// Cache the data (synchronous, fire-and-forget)
|
|
652
|
-
// Use storage key for cache operations
|
|
653
|
-
this.queryClient.saveQueryData(this.def, this.storageKey, queryData, updatedAt, entityRefs, this.getExtraForPersistence());
|
|
654
|
-
// Update the timestamp
|
|
655
|
-
this.updatedAt = Date.now();
|
|
656
|
-
return queryData;
|
|
657
|
-
}
|
|
658
|
-
catch (error) {
|
|
659
|
-
lastError = error;
|
|
660
|
-
// If we've exhausted retries, throw the error
|
|
661
|
-
if (attempt >= retries) {
|
|
662
|
-
throw error;
|
|
663
|
-
}
|
|
664
|
-
// Wait before retrying (unless paused)
|
|
665
|
-
const delay = retryDelay(attempt);
|
|
666
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
667
|
-
// Check if paused during retry delay
|
|
668
|
-
if (this.isPaused) {
|
|
669
|
-
throw new Error('Query is paused due to network status');
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
// Should never reach here, but TypeScript needs it
|
|
674
|
-
throw lastError;
|
|
675
|
-
}
|
|
676
|
-
// ======================================================
|
|
677
|
-
// Private debounce methods
|
|
678
|
-
// ======================================================
|
|
679
|
-
/**
|
|
680
|
-
* Triggers a debounced refetch. If debounce is configured, delays the fetch.
|
|
681
|
-
* Otherwise, calls refetch immediately.
|
|
682
|
-
*/
|
|
683
|
-
debouncedRefetch() {
|
|
684
|
-
// We know this is a non-stream query because we're calling refetch, which is only available on non-stream queries
|
|
685
|
-
const debounce = this.def.debounce;
|
|
686
|
-
if (debounce === undefined) {
|
|
687
|
-
this.refetch();
|
|
688
|
-
return;
|
|
689
|
-
}
|
|
690
|
-
// Clear existing timer
|
|
691
|
-
clearTimeout(this.debounceTimer);
|
|
692
|
-
// Set new timer
|
|
693
|
-
this.debounceTimer = setTimeout(() => {
|
|
694
|
-
this.debounceTimer = undefined;
|
|
695
|
-
this.refetch();
|
|
696
|
-
}, debounce);
|
|
697
|
-
}
|
|
698
|
-
// ======================================================
|
|
699
|
-
// Public methods
|
|
700
|
-
// ======================================================
|
|
701
|
-
refetch = () => {
|
|
702
|
-
if (this.def.type === "stream" /* QueryType.Stream */) {
|
|
703
|
-
throw new Error('Cannot refetch a stream query');
|
|
704
|
-
}
|
|
705
|
-
if (this.fetchMorePromise) {
|
|
706
|
-
throw new Error('Query is fetching more, cannot refetch');
|
|
707
|
-
}
|
|
708
|
-
if (this.refetchPromise) {
|
|
709
|
-
return this.refetchPromise;
|
|
710
|
-
}
|
|
711
|
-
// Clear debounce timer if active (manual refetch should bypass debounce)
|
|
712
|
-
clearTimeout(this.debounceTimer);
|
|
713
|
-
this.debounceTimer = undefined;
|
|
714
|
-
// Clear memoized nextPageParams so it's recalculated after refetch
|
|
715
|
-
this._nextPageParams = undefined;
|
|
716
|
-
// Set the signal before any async operations so it's immediately visible
|
|
717
|
-
// Use untrack to avoid reactive violations when called from reactive context
|
|
718
|
-
this.isRefetchingSignal.value = true;
|
|
719
|
-
this._version.update(v => v + 1);
|
|
720
|
-
const promise = this.runQuery(this.currentParams, true)
|
|
721
|
-
.then(result => {
|
|
722
|
-
this.relayState.value = result;
|
|
723
|
-
// Clear stream orphans and optimistic inserts on refetch
|
|
724
|
-
if (this._extra !== undefined) {
|
|
725
|
-
this._extra.clear();
|
|
726
|
-
}
|
|
727
|
-
return result;
|
|
728
|
-
})
|
|
729
|
-
.catch((error) => {
|
|
730
|
-
this.relayState.setError(error);
|
|
731
|
-
return Promise.reject(error);
|
|
732
|
-
})
|
|
733
|
-
.finally(() => {
|
|
734
|
-
this._version.update(v => v + 1);
|
|
735
|
-
this.isRefetchingSignal.value = false;
|
|
736
|
-
this.refetchPromise = undefined;
|
|
737
|
-
});
|
|
738
|
-
this.refetchPromise = promise;
|
|
739
|
-
return promise;
|
|
740
|
-
};
|
|
741
|
-
fetchNextPage = () => {
|
|
742
|
-
if (this.def.type === "stream" /* QueryType.Stream */) {
|
|
743
|
-
throw new Error('Cannot fetch next page on a stream query');
|
|
744
|
-
}
|
|
745
|
-
if (this.refetchPromise) {
|
|
746
|
-
return Promise.reject(new Error('Query is refetching, cannot fetch next page'));
|
|
747
|
-
}
|
|
748
|
-
if (this.fetchMorePromise) {
|
|
749
|
-
return this.fetchMorePromise;
|
|
750
|
-
}
|
|
751
|
-
// Read nextPageParams in untracked context to avoid reactive violations
|
|
752
|
-
const nextPageParams = this.nextPageParams;
|
|
753
|
-
if (!nextPageParams) {
|
|
754
|
-
return Promise.reject(new Error('No next page params'));
|
|
755
|
-
}
|
|
756
|
-
// Set the signal before any async operations so it's immediately visible
|
|
757
|
-
// Use untrack to avoid reactive violations when called from reactive context
|
|
758
|
-
this.isFetchingMoreSignal.value = true;
|
|
759
|
-
this._version.update(v => v + 1);
|
|
760
|
-
const promise = this.runQuery(nextPageParams, false)
|
|
761
|
-
.then(result => {
|
|
762
|
-
this.relayState.value = result;
|
|
763
|
-
return result;
|
|
764
|
-
})
|
|
765
|
-
.catch((error) => {
|
|
766
|
-
this.relayState.setError(error);
|
|
767
|
-
return Promise.reject(error);
|
|
768
|
-
})
|
|
769
|
-
.finally(() => {
|
|
770
|
-
this._version.update(v => v + 1);
|
|
771
|
-
this.isFetchingMoreSignal.value = false;
|
|
772
|
-
this.fetchMorePromise = undefined;
|
|
773
|
-
});
|
|
774
|
-
this.fetchMorePromise = promise;
|
|
775
|
-
return promise;
|
|
776
|
-
};
|
|
777
|
-
// ======================================================
|
|
778
|
-
// Public properties
|
|
779
|
-
// ======================================================
|
|
780
|
-
get isRefetching() {
|
|
781
|
-
return this.isRefetchingSignal.value;
|
|
782
|
-
}
|
|
783
|
-
get isFetchingMore() {
|
|
784
|
-
return this.isFetchingMoreSignal.value;
|
|
785
|
-
}
|
|
786
|
-
get isFetching() {
|
|
787
|
-
return this.relay.isPending || this.isRefetching || this.isFetchingMore;
|
|
788
|
-
}
|
|
789
|
-
get hasNextPage() {
|
|
790
|
-
return this.nextPageParams !== null;
|
|
791
|
-
}
|
|
792
|
-
get extra() {
|
|
793
|
-
this.getAllEntityRefs();
|
|
794
|
-
return this.extraData.getExtra();
|
|
795
|
-
}
|
|
796
|
-
/**
|
|
797
|
-
* Persist the current extra data to the store
|
|
798
|
-
*/
|
|
799
|
-
persistExtraData() {
|
|
800
|
-
if (this.updatedAt === undefined) {
|
|
801
|
-
return; // Query not initialized yet
|
|
802
|
-
}
|
|
803
|
-
const extra = this._extra?.getForPersistence();
|
|
804
|
-
// Use storage key for cache operations
|
|
805
|
-
this.queryClient.saveQueryData(this.def, this.storageKey, this.relayState.value, this.updatedAt, this.refIds, extra);
|
|
806
|
-
}
|
|
807
|
-
/**
|
|
808
|
-
* Get extra data for persistence (converts Sets to arrays of entity ref IDs)
|
|
809
|
-
*/
|
|
810
|
-
getExtraForPersistence() {
|
|
811
|
-
return this._extra?.getForPersistence();
|
|
812
|
-
}
|
|
813
|
-
/**
|
|
814
|
-
* Add an optimistic insert to the query result.
|
|
815
|
-
* The insert will be automatically removed when:
|
|
816
|
-
* - The entity appears in a refetched response
|
|
817
|
-
* - The entity appears as a stream orphan
|
|
818
|
-
* - refetch() is called
|
|
819
|
-
*/
|
|
820
|
-
addOptimisticInsert(insert) {
|
|
821
|
-
// Check that the query has optimisticInserts configured
|
|
822
|
-
const def = this.def;
|
|
823
|
-
const optimisticInsertsConfig = def.optimisticInserts;
|
|
824
|
-
if (optimisticInsertsConfig === undefined) {
|
|
825
|
-
throw new Error('Query does not have optimisticInserts configured. Add optimisticInserts: { type: YourEntity } to the query definition.');
|
|
826
|
-
}
|
|
827
|
-
let proxyId = (0, proxy_js_1.getProxyId)(insert);
|
|
828
|
-
let parsedInsert = insert;
|
|
829
|
-
// If not already a proxy, parse it through the optimisticInserts shape
|
|
830
|
-
if (proxyId === undefined) {
|
|
831
|
-
parsedInsert = (0, parseEntities_js_1.parseObjectEntities)(insert, optimisticInsertsConfig.shape, this.queryClient);
|
|
832
|
-
proxyId = (0, proxy_js_1.getProxyId)(parsedInsert);
|
|
833
|
-
if (proxyId === undefined) {
|
|
834
|
-
throw new Error('Optimistic insert must be or produce an entity proxy');
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
// Check if already in main response
|
|
838
|
-
const allRefIds = this.getAllEntityRefs();
|
|
839
|
-
if (allRefIds.has(proxyId)) {
|
|
840
|
-
return; // Already in response, no-op
|
|
841
|
-
}
|
|
842
|
-
// Check if already in stream orphans
|
|
843
|
-
if (this.extraData.hasOrphanWithId(proxyId)) {
|
|
844
|
-
return; // Already in stream orphans, no-op
|
|
845
|
-
}
|
|
846
|
-
this.extraData.addOptimisticInsert(parsedInsert);
|
|
847
|
-
}
|
|
848
|
-
/**
|
|
849
|
-
* Remove an optimistic insert from the query result.
|
|
850
|
-
* This is a no-op if the insert has already been removed.
|
|
851
|
-
*/
|
|
852
|
-
removeOptimisticInsert(insert) {
|
|
853
|
-
this.extraData.removeOptimisticInsert(insert);
|
|
854
|
-
}
|
|
855
|
-
get isStale() {
|
|
856
|
-
// Streams are never stale - they're always receiving updates
|
|
857
|
-
if (this.def.type === "stream" /* QueryType.Stream */) {
|
|
858
|
-
return false;
|
|
859
|
-
}
|
|
860
|
-
if (this.updatedAt === undefined) {
|
|
861
|
-
return true; // No data yet, needs fetch
|
|
862
|
-
}
|
|
863
|
-
const staleTime = this.def.cache?.staleTime ?? 0;
|
|
864
|
-
return Date.now() - this.updatedAt >= staleTime;
|
|
865
|
-
}
|
|
866
|
-
get isPaused() {
|
|
867
|
-
// Streams handle their own connection state
|
|
868
|
-
if (this.def.type === "stream" /* QueryType.Stream */) {
|
|
869
|
-
return false;
|
|
870
|
-
}
|
|
871
|
-
const networkMode = this.def.cache?.networkMode ?? types_js_1.NetworkMode.Online;
|
|
872
|
-
const networkManager = this.queryClient.networkManager;
|
|
873
|
-
// Read the online signal to make this reactive
|
|
874
|
-
const isOnline = networkManager.getOnlineSignal().value;
|
|
875
|
-
switch (networkMode) {
|
|
876
|
-
case types_js_1.NetworkMode.Always:
|
|
877
|
-
return false;
|
|
878
|
-
case types_js_1.NetworkMode.Online:
|
|
879
|
-
return !isOnline;
|
|
880
|
-
case types_js_1.NetworkMode.OfflineFirst:
|
|
881
|
-
// Only paused if we have no cached data AND we're offline
|
|
882
|
-
return !isOnline && this.updatedAt === undefined;
|
|
883
|
-
default:
|
|
884
|
-
return false;
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
getRetryConfig() {
|
|
888
|
-
// Streams don't have retry config
|
|
889
|
-
if (this.def.type === "stream" /* QueryType.Stream */) {
|
|
890
|
-
return { retries: 0, retryDelay: () => 0 };
|
|
891
|
-
}
|
|
892
|
-
const retryOption = this.def.cache?.retry;
|
|
893
|
-
const isServer = this.queryClient.isServer;
|
|
894
|
-
// Default retry count: 3 on client, 0 on server
|
|
895
|
-
let retries;
|
|
896
|
-
let retryDelay;
|
|
897
|
-
if (retryOption === false) {
|
|
898
|
-
retries = 0;
|
|
899
|
-
}
|
|
900
|
-
else if (retryOption === undefined) {
|
|
901
|
-
retries = isServer ? 0 : 3;
|
|
902
|
-
}
|
|
903
|
-
else if (typeof retryOption === 'number') {
|
|
904
|
-
retries = retryOption;
|
|
905
|
-
}
|
|
906
|
-
else {
|
|
907
|
-
retries = retryOption.retries;
|
|
908
|
-
}
|
|
909
|
-
// Default exponential backoff: 1000ms * 2^attempt
|
|
910
|
-
if (typeof retryOption === 'object' && retryOption.retryDelay) {
|
|
911
|
-
retryDelay = retryOption.retryDelay;
|
|
912
|
-
}
|
|
913
|
-
else {
|
|
914
|
-
retryDelay = (attempt) => 1000 * Math.pow(2, attempt);
|
|
915
|
-
}
|
|
916
|
-
return { retries, retryDelay };
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
exports.QueryResultImpl = QueryResultImpl;
|
|
920
|
-
//# sourceMappingURL=QueryResult.js.map
|