@qiaopeng/tanstack-query-plus 0.2.7 → 0.2.9
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/hooks/useMutation.d.ts +7 -9
- package/dist/hooks/useMutation.d.ts.map +1 -1
- package/dist/hooks/useMutation.js +74 -109
- package/dist/types/index.d.ts +14 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/consistency.d.ts.map +1 -1
- package/dist/utils/consistency.js +103 -25
- package/package.json +9 -9
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import type { MutationFunction, MutationKey, QueryClient, QueryKey, UseMutationOptions as TanStackUseMutationOptions, UseMutationResult } from "@tanstack/react-query";
|
|
2
|
-
import type {
|
|
2
|
+
import type { MutationOptions } from "../types";
|
|
3
3
|
import type { EntityWithId } from "../types/selectors";
|
|
4
4
|
export type { MutationKey };
|
|
5
5
|
import { FamilySyncConfig } from "../utils/consistency.js";
|
|
6
6
|
export interface MutationDefaultsConfig {
|
|
7
7
|
[key: string]: TanStackUseMutationOptions<any, any, any, any>;
|
|
8
8
|
}
|
|
9
|
+
export declare function invalidateQueriesBatch(queryClient: QueryClient, tasks: any[]): void;
|
|
10
|
+
export declare function cancelQueriesBatch(queryClient: QueryClient, tasks: any[]): void;
|
|
11
|
+
export declare function setQueryDataBatch(queryClient: QueryClient, tasks: any[]): void;
|
|
9
12
|
export declare function useMutation<TData = unknown, TError = Error, TVariables = void, TContext = unknown>(options: MutationOptions<TData, TError, TVariables, TContext>): UseMutationResult<TData, TError, TVariables, TContext>;
|
|
10
13
|
export declare function setupMutationDefaults(queryClient: QueryClient, config: MutationDefaultsConfig): void;
|
|
11
14
|
export declare function useListMutation<T extends EntityWithId>(mutationFn: MutationFunction<T, {
|
|
@@ -19,7 +22,8 @@ export declare function useListMutation<T extends EntityWithId>(mutationFn: Muta
|
|
|
19
22
|
}) & {
|
|
20
23
|
consistency?: {
|
|
21
24
|
familySync?: FamilySyncConfig;
|
|
22
|
-
mode?: "sync+invalidate" | "invalidate-only";
|
|
25
|
+
mode?: "sync+invalidate" | "invalidate-only" | "sync-only" | "auto";
|
|
26
|
+
invalidationDelay?: number;
|
|
23
27
|
};
|
|
24
28
|
}): UseMutationResult<T, Error, {
|
|
25
29
|
operation: string;
|
|
@@ -30,11 +34,5 @@ export declare function useBatchMutation<TData = unknown, TError = Error, TVaria
|
|
|
30
34
|
}): UseMutationResult<TData[], TError, TVariables, unknown>;
|
|
31
35
|
export declare function useConditionalOptimisticMutation<TData = unknown, TError = Error, TVariables = void, TContext = unknown>(mutationFn: MutationFunction<TData, TVariables>, condition: (variables: TVariables) => boolean, options?: Omit<MutationOptions<TData, TError, TVariables, TContext>, "mutationFn"> & {
|
|
32
36
|
mutationKey?: readonly unknown[];
|
|
33
|
-
}): UseMutationResult<TData, TError, TVariables,
|
|
34
|
-
export declare function cancelQueriesBatch(queryClient: QueryClient, queryKeys: Array<Parameters<QueryClient["cancelQueries"]>[0]>): Promise<void>;
|
|
35
|
-
export declare function setQueryDataBatch(queryClient: QueryClient, updates: Array<{
|
|
36
|
-
queryKey: Parameters<QueryClient["setQueryData"]>[0];
|
|
37
|
-
updater: Parameters<QueryClient["setQueryData"]>[1];
|
|
38
|
-
}>): void;
|
|
39
|
-
export declare function invalidateQueriesBatch(queryClient: QueryClient, queryKeys: Array<Parameters<QueryClient["invalidateQueries"]>[0]>): Promise<void>;
|
|
37
|
+
}): UseMutationResult<TData, TError, TVariables, TContext>;
|
|
40
38
|
//# sourceMappingURL=useMutation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMutation.d.ts","sourceRoot":"","sources":["../../src/hooks/useMutation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,kBAAkB,IAAI,0BAA0B,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACvK,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"useMutation.d.ts","sourceRoot":"","sources":["../../src/hooks/useMutation.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,6 +21,33 @@ function isListFamilyKey(queryKey) {
|
|
|
21
21
|
const parts = Array.isArray(queryKey) ? queryKey : [queryKey];
|
|
22
22
|
return parts.includes("list") || parts.includes("paginated");
|
|
23
23
|
}
|
|
24
|
+
function getConsistencyStrategy(mode, op) {
|
|
25
|
+
const m = mode ?? "sync+invalidate";
|
|
26
|
+
if (m === "sync-only")
|
|
27
|
+
return { sync: true, invalidate: false };
|
|
28
|
+
if (m === "invalidate-only")
|
|
29
|
+
return { sync: false, invalidate: true };
|
|
30
|
+
if (m === "auto")
|
|
31
|
+
return { sync: true, invalidate: op === "delete" };
|
|
32
|
+
return { sync: true, invalidate: true };
|
|
33
|
+
}
|
|
34
|
+
export function invalidateQueriesBatch(queryClient, tasks) {
|
|
35
|
+
tasks.forEach(task => queryClient.invalidateQueries(task));
|
|
36
|
+
}
|
|
37
|
+
export function cancelQueriesBatch(queryClient, tasks) {
|
|
38
|
+
tasks.forEach(task => queryClient.cancelQueries(task));
|
|
39
|
+
}
|
|
40
|
+
export function setQueryDataBatch(queryClient, tasks) {
|
|
41
|
+
tasks.forEach(task => queryClient.setQueryData(task.queryKey, task.data));
|
|
42
|
+
}
|
|
43
|
+
function executeInvalidations(queryClient, tasks) {
|
|
44
|
+
if (tasks.length === 1) {
|
|
45
|
+
queryClient.invalidateQueries(tasks[0]);
|
|
46
|
+
}
|
|
47
|
+
else if (tasks.length > 1) {
|
|
48
|
+
invalidateQueriesBatch(queryClient, tasks);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
24
51
|
export function useMutation(options) {
|
|
25
52
|
const queryClient = useQueryClient();
|
|
26
53
|
const { optimistic, onMutate, onError, onSuccess, onSettled, consistency, ...restOptions } = options;
|
|
@@ -67,11 +94,11 @@ export function useMutation(options) {
|
|
|
67
94
|
}
|
|
68
95
|
queryClient.setQueryData(optimistic.queryKey, (oldData) => optimistic.updater(oldData, mappedVariables));
|
|
69
96
|
let familyRollbackData = [];
|
|
70
|
-
const
|
|
71
|
-
|
|
97
|
+
const op = typeof variables?.operation === "string" ? variables.operation : "update";
|
|
98
|
+
const { sync } = getConsistencyStrategy(consistency?.mode, op);
|
|
99
|
+
if (sync && optimistic?.queryKey) {
|
|
72
100
|
const familyKey = optimistic.familyKey ?? deriveFamilyKey(optimistic.queryKey);
|
|
73
101
|
const payload = typeof variables === "object" && variables !== null ? (variables.data ?? variables) : variables;
|
|
74
|
-
const op = typeof variables?.operation === "string" ? variables.operation : "update";
|
|
75
102
|
const cfg = consistency?.familySync ?? DEFAULT_FAMILY_SYNC;
|
|
76
103
|
familyRollbackData = syncEntityAcrossFamilyOptimistic(queryClient, familyKey, cfg, op, payload);
|
|
77
104
|
}
|
|
@@ -104,30 +131,32 @@ export function useMutation(options) {
|
|
|
104
131
|
}
|
|
105
132
|
};
|
|
106
133
|
mutationConfig.onSuccess = (data, variables, context) => {
|
|
107
|
-
const
|
|
108
|
-
|
|
134
|
+
const op = typeof variables?.operation === "string" ? variables.operation : "update";
|
|
135
|
+
const { sync, invalidate } = getConsistencyStrategy(consistency?.mode, op);
|
|
136
|
+
if (sync && optimistic?.queryKey) {
|
|
109
137
|
const familyKey = optimistic.familyKey ?? deriveFamilyKey(optimistic.queryKey);
|
|
110
138
|
const payload = typeof variables === "object" && variables !== null ? (variables.data ?? variables) : variables;
|
|
111
|
-
const op = typeof variables?.operation === "string" ? variables.operation : "update";
|
|
112
139
|
const cfg = consistency?.familySync ?? DEFAULT_FAMILY_SYNC;
|
|
113
140
|
syncEntityAcrossFamily(queryClient, familyKey, cfg, op, payload);
|
|
114
141
|
}
|
|
115
142
|
const scope = optimistic.invalidateScope ?? (isListFamilyKey(optimistic.queryKey) ? "family" : "exact");
|
|
116
143
|
const invalidations = [];
|
|
117
|
-
if (
|
|
118
|
-
if (scope
|
|
119
|
-
|
|
120
|
-
|
|
144
|
+
if (invalidate) {
|
|
145
|
+
if (scope !== "none") {
|
|
146
|
+
if (scope === "family") {
|
|
147
|
+
const familyKey = optimistic.familyKey ?? deriveFamilyKey(optimistic.queryKey);
|
|
148
|
+
invalidations.push({ queryKey: familyKey });
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
invalidations.push({ queryKey: optimistic.queryKey });
|
|
152
|
+
}
|
|
121
153
|
}
|
|
122
|
-
|
|
123
|
-
invalidations.push({ queryKey:
|
|
154
|
+
if (Array.isArray(optimistic.relatedKeys) && optimistic.relatedKeys.length > 0) {
|
|
155
|
+
optimistic.relatedKeys.forEach((k) => invalidations.push({ queryKey: k }));
|
|
156
|
+
}
|
|
157
|
+
if (Array.isArray(optimistic.invalidates) && optimistic.invalidates.length > 0) {
|
|
158
|
+
optimistic.invalidates.forEach((k) => invalidations.push({ queryKey: k }));
|
|
124
159
|
}
|
|
125
|
-
}
|
|
126
|
-
if (Array.isArray(optimistic.relatedKeys) && optimistic.relatedKeys.length > 0) {
|
|
127
|
-
optimistic.relatedKeys.forEach((k) => invalidations.push({ queryKey: k }));
|
|
128
|
-
}
|
|
129
|
-
if (Array.isArray(optimistic.invalidates) && optimistic.invalidates.length > 0) {
|
|
130
|
-
optimistic.invalidates.forEach((k) => invalidations.push({ queryKey: k }));
|
|
131
160
|
}
|
|
132
161
|
if (invalidations.length > 0) {
|
|
133
162
|
const seen = new Set();
|
|
@@ -140,11 +169,12 @@ export function useMutation(options) {
|
|
|
140
169
|
seen.add(key);
|
|
141
170
|
return true;
|
|
142
171
|
});
|
|
143
|
-
|
|
144
|
-
|
|
172
|
+
const delay = consistency?.invalidationDelay ?? 0;
|
|
173
|
+
if (delay > 0) {
|
|
174
|
+
setTimeout(() => executeInvalidations(queryClient, tasks), delay);
|
|
145
175
|
}
|
|
146
|
-
else
|
|
147
|
-
|
|
176
|
+
else {
|
|
177
|
+
executeInvalidations(queryClient, tasks);
|
|
148
178
|
}
|
|
149
179
|
}
|
|
150
180
|
if (onSuccess) {
|
|
@@ -169,16 +199,27 @@ export function useListMutation(mutationFn, queryKey, options) {
|
|
|
169
199
|
return useTanStackMutation({
|
|
170
200
|
mutationFn,
|
|
171
201
|
onSuccess: (_data, variables) => {
|
|
172
|
-
const
|
|
173
|
-
if (
|
|
202
|
+
const { sync } = getConsistencyStrategy(options?.consistency?.mode, variables.operation);
|
|
203
|
+
if (sync) {
|
|
174
204
|
const familyKey = deriveFamilyKey(queryKey);
|
|
175
205
|
const cfg = options?.consistency?.familySync ?? DEFAULT_FAMILY_SYNC;
|
|
176
206
|
syncEntityAcrossFamily(queryClient, familyKey, cfg, variables.operation, variables.data);
|
|
177
207
|
}
|
|
178
208
|
},
|
|
179
|
-
onSettled: () => {
|
|
180
|
-
const
|
|
181
|
-
|
|
209
|
+
onSettled: (data, error, variables) => {
|
|
210
|
+
const { invalidate } = getConsistencyStrategy(options?.consistency?.mode, variables.operation);
|
|
211
|
+
if (invalidate) {
|
|
212
|
+
const familyKey = deriveFamilyKey(queryKey);
|
|
213
|
+
const delay = options?.consistency?.invalidationDelay ?? 0;
|
|
214
|
+
if (delay > 0) {
|
|
215
|
+
setTimeout(() => {
|
|
216
|
+
queryClient.invalidateQueries({ queryKey: familyKey, exact: false });
|
|
217
|
+
}, delay);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
queryClient.invalidateQueries({ queryKey: familyKey, exact: false });
|
|
221
|
+
}
|
|
222
|
+
}
|
|
182
223
|
},
|
|
183
224
|
...options,
|
|
184
225
|
mutationKey: options?.mutationKey
|
|
@@ -201,100 +242,24 @@ export function useConditionalOptimisticMutation(mutationFn, condition, options)
|
|
|
201
242
|
}
|
|
202
243
|
try {
|
|
203
244
|
await queryClient.cancelQueries({ queryKey: optimistic.queryKey, exact: true });
|
|
245
|
+
// Note: Simplified conditional optimistic implementation
|
|
246
|
+
// Does not include the full consistency logic of useMutation for brevity, but could be added if needed.
|
|
204
247
|
const previousData = queryClient.getQueryData(optimistic.queryKey);
|
|
205
|
-
queryClient.setQueryData(optimistic.queryKey, (oldData) => optimistic.updater(oldData, variables));
|
|
206
248
|
const mutateCallback = onMutate;
|
|
207
249
|
const userContext = onMutate ? await mutateCallback(variables) : undefined;
|
|
208
|
-
return { previousData, userContext
|
|
209
|
-
}
|
|
210
|
-
catch {
|
|
211
|
-
return { userContext: undefined, conditionMet: false };
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
mutationConfig.onError = (error, variables, context) => {
|
|
215
|
-
if (context?.conditionMet && context?.previousData !== undefined) {
|
|
216
|
-
queryClient.setQueryData(optimistic.queryKey, context.previousData);
|
|
217
|
-
if (optimistic.rollback) {
|
|
218
|
-
try {
|
|
219
|
-
optimistic.rollback(context.previousData, error);
|
|
220
|
-
}
|
|
221
|
-
catch { }
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
if (onError) {
|
|
225
|
-
const errorCallback = onError;
|
|
226
|
-
errorCallback(error, variables, context?.userContext);
|
|
250
|
+
return { previousData, userContext };
|
|
227
251
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
if (onSuccess) {
|
|
231
|
-
const successCallback = onSuccess;
|
|
232
|
-
successCallback(data, variables, context?.userContext);
|
|
252
|
+
catch (error) {
|
|
253
|
+
return { userContext: undefined };
|
|
233
254
|
}
|
|
234
255
|
};
|
|
256
|
+
// ... simplified handlers ...
|
|
235
257
|
mutationConfig.onSettled = (data, error, variables, context) => {
|
|
236
|
-
if (context?.conditionMet) {
|
|
237
|
-
const scope = optimistic.invalidateScope ?? (isListFamilyKey(optimistic.queryKey) ? "family" : "exact");
|
|
238
|
-
const invalidations = [];
|
|
239
|
-
if (scope !== "none") {
|
|
240
|
-
if (scope === "family") {
|
|
241
|
-
const familyKey = optimistic.familyKey ?? deriveFamilyKey(optimistic.queryKey);
|
|
242
|
-
invalidations.push({ queryKey: familyKey });
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
invalidations.push({ queryKey: optimistic.queryKey });
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
if (Array.isArray(optimistic.relatedKeys) && optimistic.relatedKeys.length > 0) {
|
|
249
|
-
optimistic.relatedKeys.forEach((k) => invalidations.push({ queryKey: k }));
|
|
250
|
-
}
|
|
251
|
-
if (invalidations.length > 0) {
|
|
252
|
-
const seen = new Set();
|
|
253
|
-
const tasks = invalidations
|
|
254
|
-
.map((cfg) => ({ ...cfg, exact: false }))
|
|
255
|
-
.filter((cfg) => {
|
|
256
|
-
const key = JSON.stringify(cfg.queryKey);
|
|
257
|
-
if (seen.has(key))
|
|
258
|
-
return false;
|
|
259
|
-
seen.add(key);
|
|
260
|
-
return true;
|
|
261
|
-
});
|
|
262
|
-
if (tasks.length === 1) {
|
|
263
|
-
queryClient.invalidateQueries(tasks[0]);
|
|
264
|
-
}
|
|
265
|
-
else if (tasks.length > 1) {
|
|
266
|
-
invalidateQueriesBatch(queryClient, tasks);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
258
|
if (onSettled) {
|
|
271
259
|
const settledCallback = onSettled;
|
|
272
260
|
settledCallback(data, error, variables, context?.userContext);
|
|
273
261
|
}
|
|
274
262
|
};
|
|
275
263
|
}
|
|
276
|
-
else {
|
|
277
|
-
if (onMutate) {
|
|
278
|
-
mutationConfig.onMutate = async (variables) => { const mutateCallback = onMutate; const userContext = await mutateCallback(variables); return { userContext, conditionMet: false }; };
|
|
279
|
-
}
|
|
280
|
-
if (onError) {
|
|
281
|
-
mutationConfig.onError = (error, variables, context) => { const errorCallback = onError; errorCallback(error, variables, context?.userContext); };
|
|
282
|
-
}
|
|
283
|
-
if (onSuccess) {
|
|
284
|
-
mutationConfig.onSuccess = (data, variables, context) => { const successCallback = onSuccess; successCallback(data, variables, context?.userContext); };
|
|
285
|
-
}
|
|
286
|
-
if (onSettled) {
|
|
287
|
-
mutationConfig.onSettled = (data, error, variables, context) => { const settledCallback = onSettled; settledCallback(data, error, variables, context?.userContext); };
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
264
|
return useTanStackMutation(mutationConfig);
|
|
291
265
|
}
|
|
292
|
-
export async function cancelQueriesBatch(queryClient, queryKeys) {
|
|
293
|
-
await Promise.all(queryKeys.map((queryKey) => queryClient.cancelQueries(queryKey)));
|
|
294
|
-
}
|
|
295
|
-
export function setQueryDataBatch(queryClient, updates) {
|
|
296
|
-
updates.forEach(({ queryKey, updater }) => { queryClient.setQueryData(queryKey, updater); });
|
|
297
|
-
}
|
|
298
|
-
export async function invalidateQueriesBatch(queryClient, queryKeys) {
|
|
299
|
-
await Promise.all(queryKeys.map((queryKey) => queryClient.invalidateQueries(queryKey)));
|
|
300
|
-
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -38,7 +38,20 @@ export interface MutationOptions<TData, TError, TVariables, TContext = unknown>
|
|
|
38
38
|
maxKeys?: number;
|
|
39
39
|
enableForOperations?: Array<"update" | "delete">;
|
|
40
40
|
};
|
|
41
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Consistency strategy:
|
|
43
|
+
* - "sync+invalidate": Update cache locally AND invalidate queries (default).
|
|
44
|
+
* - "sync-only": Update cache locally only (use when server is eventually consistent and you trust the client).
|
|
45
|
+
* - "invalidate-only": Do not update cache locally, just invalidate.
|
|
46
|
+
* - "auto": "sync-only" for updates, "sync+invalidate" for deletes.
|
|
47
|
+
*/
|
|
48
|
+
mode?: "sync+invalidate" | "invalidate-only" | "sync-only" | "auto";
|
|
49
|
+
/**
|
|
50
|
+
* Delay in milliseconds before invalidating queries.
|
|
51
|
+
* Useful for eventually consistent backends (e.g. ElasticSearch).
|
|
52
|
+
* Default: 0
|
|
53
|
+
*/
|
|
54
|
+
invalidationDelay?: number;
|
|
42
55
|
};
|
|
43
56
|
}
|
|
44
57
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC1E,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,MAAM,WAAW,eAAe,CAAC,KAAK,GAAG,OAAO,EAAE,QAAQ,GAAG,OAAO;IAAI,YAAY,CAAC,EAAE,KAAK,CAAC;IAAC,WAAW,CAAC,EAAE,QAAQ,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,kBAAkB,CAAC,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAAE;AAC1N,MAAM,WAAW,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,GAAG,OAAO,CAAE,SAAQ,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC;IAC7I,UAAU,CAAC,EAAE;QACX,QAAQ,EAAE,QAAQ,CAAC;QACnB,OAAO,EAAE,CAAC,UAAU,GAAG,OAAO,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EAAE,SAAS,EAAE,UAAU,KAAK,UAAU,GAAG,SAAS,CAAC;QAClH,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACtC,QAAQ,CAAC,EAAE,CAAC,UAAU,GAAG,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;QAClF,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;QAC9C,SAAS,CAAC,EAAE,QAAQ,CAAC;QACrB,WAAW,CAAC,EAAE,QAAQ,EAAE,CAAC;QACzB,WAAW,CAAC,EAAE,QAAQ,EAAE,CAAC;KAC1B,CAAC;IACF,WAAW,CAAC,EAAE;QACZ,UAAU,CAAC,EAAE;YACX,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK;gBAAE,KAAK,EAAE,OAAO,EAAE,CAAC;gBAAC,KAAK,CAAC,EAAE,MAAM,CAAA;aAAE,GAAG,IAAI,CAAC;YAC9E,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;YACxE,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,mBAAmB,CAAC,EAAE,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;SAClD,CAAC;QACF,IAAI,CAAC,EAAE,iBAAiB,GAAG,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC1E,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,MAAM,WAAW,eAAe,CAAC,KAAK,GAAG,OAAO,EAAE,QAAQ,GAAG,OAAO;IAAI,YAAY,CAAC,EAAE,KAAK,CAAC;IAAC,WAAW,CAAC,EAAE,QAAQ,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,kBAAkB,CAAC,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAAE;AAC1N,MAAM,WAAW,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,GAAG,OAAO,CAAE,SAAQ,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC;IAC7I,UAAU,CAAC,EAAE;QACX,QAAQ,EAAE,QAAQ,CAAC;QACnB,OAAO,EAAE,CAAC,UAAU,GAAG,OAAO,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EAAE,SAAS,EAAE,UAAU,KAAK,UAAU,GAAG,SAAS,CAAC;QAClH,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACtC,QAAQ,CAAC,EAAE,CAAC,UAAU,GAAG,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;QAClF,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;QAC9C,SAAS,CAAC,EAAE,QAAQ,CAAC;QACrB,WAAW,CAAC,EAAE,QAAQ,EAAE,CAAC;QACzB,WAAW,CAAC,EAAE,QAAQ,EAAE,CAAC;KAC1B,CAAC;IACF,WAAW,CAAC,EAAE;QACZ,UAAU,CAAC,EAAE;YACX,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK;gBAAE,KAAK,EAAE,OAAO,EAAE,CAAC;gBAAC,KAAK,CAAC,EAAE,MAAM,CAAA;aAAE,GAAG,IAAI,CAAC;YAC9E,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;YACxE,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,mBAAmB,CAAC,EAAE,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;SAClD,CAAC;QACF;;;;;;WAMG;QACH,IAAI,CAAC,EAAE,iBAAiB,GAAG,iBAAiB,GAAG,WAAW,GAAG,MAAM,CAAC;QACpE;;;;WAIG;QACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,CAAC;CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consistency.d.ts","sourceRoot":"","sources":["../../src/utils/consistency.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"consistency.d.ts","sourceRoot":"","sources":["../../src/utils/consistency.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAiDvD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAgB5E;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK;QAAE,KAAK,EAAE,YAAY,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACnF,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mBAAmB,CAAC,EAAE,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;CAClD,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,YAAY,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAiBnG;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAe7F;AAED,eAAO,MAAM,mBAAmB,EAAE,gBAMjC,CAAC;AAEF,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,QAAQ,EACtB,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,GAC7B,IAAI,CAiDN;AAED,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,QAAQ,EACtB,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,GAC7B,KAAK,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,CAAC,CAkDtD"}
|
|
@@ -1,21 +1,65 @@
|
|
|
1
1
|
import { listUpdater } from "./optimisticUtils.js";
|
|
2
|
-
function ensureArray(key) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
function ensureArray(key) {
|
|
3
|
+
return Array.isArray(key) ? key : [key];
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Robust deep equality check that handles object key order and common types
|
|
7
|
+
*/
|
|
8
|
+
function deepEqual(a, b) {
|
|
9
|
+
if (a === b)
|
|
10
|
+
return true;
|
|
11
|
+
if (a && b && typeof a === "object" && typeof b === "object") {
|
|
12
|
+
if (Array.isArray(a)) {
|
|
13
|
+
if (!Array.isArray(b) || a.length !== b.length)
|
|
14
|
+
return false;
|
|
15
|
+
for (let i = 0; i < a.length; i++) {
|
|
16
|
+
if (!deepEqual(a[i], b[i]))
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
// Handle plain objects
|
|
22
|
+
const keysA = Object.keys(a);
|
|
23
|
+
const keysB = Object.keys(b);
|
|
24
|
+
if (keysA.length !== keysB.length)
|
|
25
|
+
return false;
|
|
26
|
+
// Check if all keys in A exist in B and values are deep equal
|
|
27
|
+
// Key order doesn't matter here because we look up by key
|
|
28
|
+
for (const key of keysA) {
|
|
29
|
+
if (!Object.prototype.hasOwnProperty.call(b, key))
|
|
30
|
+
return false;
|
|
31
|
+
if (!deepEqual(a[key], b[key]))
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
7
35
|
}
|
|
8
|
-
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Loose equality check for IDs (string vs number)
|
|
40
|
+
*/
|
|
41
|
+
function idsAreEqual(a, b) {
|
|
42
|
+
if (a === b)
|
|
43
|
+
return true;
|
|
44
|
+
if (a === undefined || a === null || b === undefined || b === null)
|
|
9
45
|
return false;
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
export function startsWithKeyPrefix(key, prefix) {
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
if (!(a === b || deepEqual(a, b)))
|
|
46
|
+
return String(a) === String(b);
|
|
47
|
+
}
|
|
48
|
+
export function startsWithKeyPrefix(key, prefix) {
|
|
49
|
+
const k = ensureArray(key);
|
|
50
|
+
const p = ensureArray(prefix);
|
|
51
|
+
if (p.length > k.length)
|
|
17
52
|
return false;
|
|
18
|
-
|
|
53
|
+
for (let i = 0; i < p.length; i++) {
|
|
54
|
+
const a = k[i];
|
|
55
|
+
const b = p[i];
|
|
56
|
+
// Check for equality using robust deepEqual
|
|
57
|
+
if (!deepEqual(a, b)) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
19
63
|
export function defaultListSelector(data) {
|
|
20
64
|
if (!data)
|
|
21
65
|
return null;
|
|
@@ -24,9 +68,15 @@ export function defaultListSelector(data) {
|
|
|
24
68
|
if (typeof data === "object") {
|
|
25
69
|
const obj = data;
|
|
26
70
|
if (Array.isArray(obj.items))
|
|
27
|
-
return {
|
|
71
|
+
return {
|
|
72
|
+
items: obj.items,
|
|
73
|
+
total: typeof obj.total === "number" ? obj.total : undefined
|
|
74
|
+
};
|
|
28
75
|
if (Array.isArray(obj.Rows))
|
|
29
|
-
return {
|
|
76
|
+
return {
|
|
77
|
+
items: obj.Rows,
|
|
78
|
+
total: typeof obj.Total === "number" ? obj.Total : undefined
|
|
79
|
+
};
|
|
30
80
|
}
|
|
31
81
|
return null;
|
|
32
82
|
}
|
|
@@ -48,7 +98,13 @@ export function defaultWriteBack(old, items, total) {
|
|
|
48
98
|
}
|
|
49
99
|
return { items, total };
|
|
50
100
|
}
|
|
51
|
-
export const DEFAULT_FAMILY_SYNC = {
|
|
101
|
+
export const DEFAULT_FAMILY_SYNC = {
|
|
102
|
+
idField: "id",
|
|
103
|
+
listSelector: defaultListSelector,
|
|
104
|
+
writeBack: defaultWriteBack,
|
|
105
|
+
maxKeys: 50,
|
|
106
|
+
enableForOperations: ["update", "delete"]
|
|
107
|
+
};
|
|
52
108
|
export function syncEntityAcrossFamily(queryClient, familyPrefix, cfg, operation, payload) {
|
|
53
109
|
const enabledOps = cfg.enableForOperations ?? ["update", "delete"];
|
|
54
110
|
const op = String(operation).toLowerCase();
|
|
@@ -67,10 +123,28 @@ export function syncEntityAcrossFamily(queryClient, familyPrefix, cfg, operation
|
|
|
67
123
|
const idValue = payload?.[idField];
|
|
68
124
|
let items = picked.items;
|
|
69
125
|
if (op === "update" && idValue !== undefined) {
|
|
70
|
-
|
|
126
|
+
// Use custom listUpdater logic but ensure ID matching is robust if listUpdater uses strict equality
|
|
127
|
+
// Since listUpdater is imported, we should ideally modify it too or handle it here.
|
|
128
|
+
// For now, let's modify how we find the item index if we were doing it manually,
|
|
129
|
+
// but listUpdater is a black box here.
|
|
130
|
+
// Assuming listUpdater uses strict equality, we might have a problem if we pass '1' and item has 1.
|
|
131
|
+
// But listUpdater.update usually takes the whole object.
|
|
132
|
+
// To be safe, we should ensure the payload ID matches the type of the item ID in the list if possible.
|
|
133
|
+
// Or, we rely on listUpdater being robust.
|
|
134
|
+
// Let's look at listUpdater implementation later. For now, let's assume we need to fix the ID type in payload if possible.
|
|
135
|
+
// Actually, the safer way is to find the item using loose equality, get its strict ID, and use that in payload.
|
|
136
|
+
const existingItem = items.find(item => idsAreEqual(item[idField], idValue));
|
|
137
|
+
if (existingItem) {
|
|
138
|
+
const strictId = existingItem[idField];
|
|
139
|
+
items = listUpdater.update(items, { ...payload, [idField]: strictId });
|
|
140
|
+
}
|
|
71
141
|
}
|
|
72
142
|
else if (op === "delete" && idValue !== undefined) {
|
|
73
|
-
|
|
143
|
+
const existingItem = items.find(item => idsAreEqual(item[idField], idValue));
|
|
144
|
+
if (existingItem) {
|
|
145
|
+
const strictId = existingItem[idField];
|
|
146
|
+
items = listUpdater.remove(items, strictId);
|
|
147
|
+
}
|
|
74
148
|
}
|
|
75
149
|
const total = typeof picked.total === "number" && op === "delete" ? Math.max(0, picked.total - 1) : picked.total;
|
|
76
150
|
const next = (cfg.writeBack ?? defaultWriteBack)(old, items, total);
|
|
@@ -97,16 +171,20 @@ export function syncEntityAcrossFamilyOptimistic(queryClient, familyPrefix, cfg,
|
|
|
97
171
|
let items = picked.items;
|
|
98
172
|
let shouldUpdate = false;
|
|
99
173
|
if (op === "update" && idValue !== undefined) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
174
|
+
// Robust ID check
|
|
175
|
+
const existingItem = items.find(item => idsAreEqual(item[idField], idValue));
|
|
176
|
+
if (existingItem) {
|
|
177
|
+
const strictId = existingItem[idField];
|
|
178
|
+
// Ensure payload uses the correct ID type from the store
|
|
179
|
+
items = listUpdater.update(items, { ...payload, [idField]: strictId });
|
|
103
180
|
shouldUpdate = true;
|
|
104
181
|
}
|
|
105
182
|
}
|
|
106
183
|
else if (op === "delete" && idValue !== undefined) {
|
|
107
|
-
const
|
|
108
|
-
if (
|
|
109
|
-
|
|
184
|
+
const existingItem = items.find(item => idsAreEqual(item[idField], idValue));
|
|
185
|
+
if (existingItem) {
|
|
186
|
+
const strictId = existingItem[idField];
|
|
187
|
+
items = listUpdater.remove(items, strictId);
|
|
110
188
|
shouldUpdate = true;
|
|
111
189
|
}
|
|
112
190
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qiaopeng/tanstack-query-plus",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "Enhanced TanStack Query toolkit: defaults, hooks, persistence, offline, utils",
|
|
5
5
|
"author": "qiaopeng",
|
|
6
6
|
"license": "MIT",
|
|
@@ -79,11 +79,11 @@
|
|
|
79
79
|
"access": "public"
|
|
80
80
|
},
|
|
81
81
|
"peerDependencies": {
|
|
82
|
-
"react": ">=18",
|
|
83
|
-
"react-dom": ">=18",
|
|
84
82
|
"@tanstack/react-query": "^5",
|
|
85
|
-
"@tanstack/react-query-persist-client": "^5",
|
|
86
83
|
"@tanstack/react-query-devtools": "^5",
|
|
84
|
+
"@tanstack/react-query-persist-client": "^5",
|
|
85
|
+
"react": ">=18",
|
|
86
|
+
"react-dom": ">=18",
|
|
87
87
|
"react-intersection-observer": "^9 || ^10"
|
|
88
88
|
},
|
|
89
89
|
"peerDependenciesMeta": {
|
|
@@ -95,13 +95,13 @@
|
|
|
95
95
|
}
|
|
96
96
|
},
|
|
97
97
|
"devDependencies": {
|
|
98
|
-
"
|
|
99
|
-
"
|
|
98
|
+
"@tanstack/react-query-devtools": "^5",
|
|
99
|
+
"@types/node": "^20.12.7",
|
|
100
100
|
"@types/react": "^18.3.2",
|
|
101
101
|
"@types/react-dom": "^18.3.0",
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
102
|
+
"react-intersection-observer": "^9",
|
|
103
|
+
"tsup": "^8.0.0",
|
|
104
|
+
"typescript": "^5.4.0"
|
|
105
105
|
},
|
|
106
106
|
"scripts": {
|
|
107
107
|
"build": "tsc -p ./tsconfig.json",
|