@pol-studios/db 1.0.8 → 1.0.10
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/auth/context.js +21 -12786
- package/dist/auth/context.js.map +1 -1
- package/dist/auth/guards.js +12 -7640
- package/dist/auth/guards.js.map +1 -1
- package/dist/auth/hooks.js +25 -10591
- package/dist/auth/hooks.js.map +1 -1
- package/dist/auth/index.js +43 -13008
- package/dist/auth/index.js.map +1 -1
- package/dist/canvas-75Y7XMF3.js +1541 -0
- package/dist/canvas-75Y7XMF3.js.map +1 -0
- package/dist/chunk-2IFGILT3.js +532 -0
- package/dist/chunk-2IFGILT3.js.map +1 -0
- package/dist/chunk-3M2U6TXH.js +928 -0
- package/dist/chunk-3M2U6TXH.js.map +1 -0
- package/dist/chunk-3PJTNH2L.js +2778 -0
- package/dist/chunk-3PJTNH2L.js.map +1 -0
- package/dist/chunk-5ZYAEGCJ.js +416 -0
- package/dist/chunk-5ZYAEGCJ.js.map +1 -0
- package/dist/chunk-7HG6G25H.js +710 -0
- package/dist/chunk-7HG6G25H.js.map +1 -0
- package/dist/chunk-7XT7K4QT.js +2687 -0
- package/dist/chunk-7XT7K4QT.js.map +1 -0
- package/dist/chunk-AWFMICFV.js +158 -0
- package/dist/chunk-AWFMICFV.js.map +1 -0
- package/dist/chunk-BRTW7CO5.js +1467 -0
- package/dist/chunk-BRTW7CO5.js.map +1 -0
- package/dist/chunk-EL45Z26M.js +4194 -0
- package/dist/chunk-EL45Z26M.js.map +1 -0
- package/dist/chunk-ERGF2FCE.js +903 -0
- package/dist/chunk-ERGF2FCE.js.map +1 -0
- package/dist/chunk-GK7B66LY.js +135 -0
- package/dist/chunk-GK7B66LY.js.map +1 -0
- package/dist/chunk-GQI6WJGI.js +172 -0
- package/dist/chunk-GQI6WJGI.js.map +1 -0
- package/dist/chunk-H6365JPC.js +1858 -0
- package/dist/chunk-H6365JPC.js.map +1 -0
- package/dist/chunk-J4ZVCXZ4.js +1 -0
- package/dist/chunk-J4ZVCXZ4.js.map +1 -0
- package/dist/chunk-JUVE3DWY.js +433 -0
- package/dist/chunk-JUVE3DWY.js.map +1 -0
- package/dist/chunk-O3K7R32P.js +7555 -0
- package/dist/chunk-O3K7R32P.js.map +1 -0
- package/dist/chunk-P4UZ7IXC.js +42 -0
- package/dist/chunk-P4UZ7IXC.js.map +1 -0
- package/dist/chunk-SEY5UO2T.js +89 -0
- package/dist/chunk-SEY5UO2T.js.map +1 -0
- package/dist/chunk-USJYMRUO.js +86 -0
- package/dist/chunk-USJYMRUO.js.map +1 -0
- package/dist/chunk-XX3IWSPM.js +189 -0
- package/dist/chunk-XX3IWSPM.js.map +1 -0
- package/dist/chunk-Y3INY2CS.js +14 -0
- package/dist/chunk-Y3INY2CS.js.map +1 -0
- package/dist/chunk-ZTSBF536.js +1927 -0
- package/dist/chunk-ZTSBF536.js.map +1 -0
- package/dist/client/index.js +13 -141
- package/dist/client/index.js.map +1 -1
- package/dist/dist-NDNRSNOG.js +521 -0
- package/dist/dist-NDNRSNOG.js.map +1 -0
- package/dist/gen/index.js +186 -1280
- package/dist/gen/index.js.map +1 -1
- package/dist/hooks/index.js +21 -8694
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.js +403 -47848
- package/dist/index.js.map +1 -1
- package/dist/index.native.js +400 -25048
- package/dist/index.native.js.map +1 -1
- package/dist/index.web.js +576 -43769
- package/dist/index.web.js.map +1 -1
- package/dist/mutation/index.js +44 -4675
- package/dist/mutation/index.js.map +1 -1
- package/dist/parser/index.js +45 -3697
- package/dist/parser/index.js.map +1 -1
- package/dist/pdf-3TIGQRLA.js +20336 -0
- package/dist/pdf-3TIGQRLA.js.map +1 -0
- package/dist/query/index.js +31 -13175
- package/dist/query/index.js.map +1 -1
- package/dist/realtime/index.js +45 -12431
- package/dist/realtime/index.js.map +1 -1
- package/dist/types/index.js +9 -0
- package/package.json +3 -3
|
@@ -0,0 +1,928 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getSupabaseUrl
|
|
3
|
+
} from "./chunk-Y3INY2CS.js";
|
|
4
|
+
import {
|
|
5
|
+
omit
|
|
6
|
+
} from "./chunk-O3K7R32P.js";
|
|
7
|
+
import {
|
|
8
|
+
useSupabase
|
|
9
|
+
} from "./chunk-AWFMICFV.js";
|
|
10
|
+
|
|
11
|
+
// src/providers/DataLayerContext.ts
|
|
12
|
+
import { createContext } from "react";
|
|
13
|
+
var DataLayerContext = createContext(null);
|
|
14
|
+
DataLayerContext.displayName = "DataLayerContext";
|
|
15
|
+
|
|
16
|
+
// src/hooks/useDataLayer.ts
|
|
17
|
+
import { useContext } from "react";
|
|
18
|
+
function useDataLayer() {
|
|
19
|
+
const context = useContext(DataLayerContext);
|
|
20
|
+
if (!context) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
"useDataLayer must be used within a DataLayerProvider. Make sure you have wrapped your app with <DataLayerProvider>."
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
return context;
|
|
26
|
+
}
|
|
27
|
+
function useDataLayerOptional() {
|
|
28
|
+
return useContext(DataLayerContext);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/hooks/useDbQuery.ts
|
|
32
|
+
import { useMemo, useEffect, useCallback } from "react";
|
|
33
|
+
import { useQuery } from "@tanstack/react-query";
|
|
34
|
+
function buildQueryKey(table, options, isInitialized, backend) {
|
|
35
|
+
return [
|
|
36
|
+
"v3",
|
|
37
|
+
"query",
|
|
38
|
+
table,
|
|
39
|
+
isInitialized,
|
|
40
|
+
backend,
|
|
41
|
+
options.select ?? "*",
|
|
42
|
+
JSON.stringify(options.where ?? {}),
|
|
43
|
+
JSON.stringify(options.orderBy ?? []),
|
|
44
|
+
options.limit,
|
|
45
|
+
options.offset
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
function serializeQueryOptions(options) {
|
|
49
|
+
return JSON.stringify({
|
|
50
|
+
select: options.select,
|
|
51
|
+
where: options.where,
|
|
52
|
+
orderBy: options.orderBy,
|
|
53
|
+
limit: options.limit,
|
|
54
|
+
offset: options.offset
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function resolveTableName(table) {
|
|
58
|
+
if (typeof table === "string") {
|
|
59
|
+
return table;
|
|
60
|
+
}
|
|
61
|
+
return `${table.schema}.${table.table}`;
|
|
62
|
+
}
|
|
63
|
+
function useDbQuery(table, options = {}) {
|
|
64
|
+
const tableName = typeof table === "string" ? table : resolveTableName(table);
|
|
65
|
+
const { registry, status, queryClient } = useDataLayer();
|
|
66
|
+
const isPowerSync = status.currentBackend === "powersync";
|
|
67
|
+
const {
|
|
68
|
+
enabled = true,
|
|
69
|
+
staleTime = isPowerSync ? 0 : 3e4,
|
|
70
|
+
gcTime = 3e5,
|
|
71
|
+
// 5 minutes - keep in memory for instant display while refetching
|
|
72
|
+
refetchOnWindowFocus = true,
|
|
73
|
+
refetchOnMount = isPowerSync ? "always" : true,
|
|
74
|
+
realtime = isPowerSync,
|
|
75
|
+
// Enable real-time subscriptions by default for PowerSync
|
|
76
|
+
...queryOptions
|
|
77
|
+
} = options;
|
|
78
|
+
const adapter = useMemo(() => {
|
|
79
|
+
if (!status.isInitialized) return null;
|
|
80
|
+
try {
|
|
81
|
+
return registry.getAdapter(tableName);
|
|
82
|
+
} catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}, [registry, tableName, status.isInitialized, status.currentBackend]);
|
|
86
|
+
const queryKey = useMemo(
|
|
87
|
+
() => buildQueryKey(tableName, options, status.isInitialized, status.currentBackend),
|
|
88
|
+
[tableName, serializeQueryOptions(options), status.isInitialized, status.currentBackend]
|
|
89
|
+
);
|
|
90
|
+
const memoizedQueryOptions = useMemo(
|
|
91
|
+
() => ({
|
|
92
|
+
select: queryOptions.select,
|
|
93
|
+
where: queryOptions.where,
|
|
94
|
+
orderBy: queryOptions.orderBy,
|
|
95
|
+
limit: queryOptions.limit,
|
|
96
|
+
offset: queryOptions.offset
|
|
97
|
+
}),
|
|
98
|
+
[serializeQueryOptions(queryOptions)]
|
|
99
|
+
);
|
|
100
|
+
const queryFn = useCallback(async () => {
|
|
101
|
+
if (!adapter) {
|
|
102
|
+
throw new Error(`Adapter not available for table: ${tableName}`);
|
|
103
|
+
}
|
|
104
|
+
const result = await adapter.query(tableName, memoizedQueryOptions);
|
|
105
|
+
return result;
|
|
106
|
+
}, [adapter, tableName, memoizedQueryOptions]);
|
|
107
|
+
const query = useQuery({
|
|
108
|
+
queryKey,
|
|
109
|
+
queryFn,
|
|
110
|
+
enabled: enabled && status.isInitialized && adapter !== null,
|
|
111
|
+
staleTime,
|
|
112
|
+
gcTime,
|
|
113
|
+
refetchOnWindowFocus,
|
|
114
|
+
refetchOnMount
|
|
115
|
+
});
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
if (!realtime || !adapter?.subscribe || !status.isInitialized) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const unsubscribe = adapter.subscribe(
|
|
121
|
+
tableName,
|
|
122
|
+
memoizedQueryOptions,
|
|
123
|
+
(data) => {
|
|
124
|
+
queryClient.setQueryData(queryKey, { data, count: data.length });
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
return () => {
|
|
128
|
+
unsubscribe();
|
|
129
|
+
};
|
|
130
|
+
}, [
|
|
131
|
+
realtime,
|
|
132
|
+
adapter,
|
|
133
|
+
tableName,
|
|
134
|
+
memoizedQueryOptions,
|
|
135
|
+
queryClient,
|
|
136
|
+
queryKey,
|
|
137
|
+
status.isInitialized
|
|
138
|
+
]);
|
|
139
|
+
const refetch = useCallback(async () => {
|
|
140
|
+
await query.refetch();
|
|
141
|
+
}, [query]);
|
|
142
|
+
return {
|
|
143
|
+
data: query.data?.data,
|
|
144
|
+
isLoading: query.isLoading,
|
|
145
|
+
isPending: query.isPending,
|
|
146
|
+
isFetching: query.isFetching,
|
|
147
|
+
isRefetching: query.isFetching,
|
|
148
|
+
// Alias for V2 compatibility
|
|
149
|
+
isSuccess: query.isSuccess,
|
|
150
|
+
isError: query.isError,
|
|
151
|
+
error: query.error,
|
|
152
|
+
refetch,
|
|
153
|
+
count: query.data?.count,
|
|
154
|
+
isStale: query.isStale,
|
|
155
|
+
dataUpdatedAt: query.dataUpdatedAt ?? null
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/hooks/useDbQueryById.ts
|
|
160
|
+
import { useMemo as useMemo2, useCallback as useCallback2 } from "react";
|
|
161
|
+
import { useQuery as useQuery2 } from "@tanstack/react-query";
|
|
162
|
+
function buildQueryKey2(table, id, select) {
|
|
163
|
+
return ["v3", "queryById", table, id, select ?? "*"];
|
|
164
|
+
}
|
|
165
|
+
function useDbQueryById(table, id, options = {}) {
|
|
166
|
+
const { registry, status } = useDataLayer();
|
|
167
|
+
const { select, enabled = id != null, staleTime = 3e4 } = options;
|
|
168
|
+
const adapter = useMemo2(() => {
|
|
169
|
+
if (!status.isInitialized) return null;
|
|
170
|
+
try {
|
|
171
|
+
return registry.getAdapter(table);
|
|
172
|
+
} catch {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
}, [registry, table, status.isInitialized, status.currentBackend]);
|
|
176
|
+
const queryKey = useMemo2(
|
|
177
|
+
() => buildQueryKey2(table, id, select),
|
|
178
|
+
[table, id, select]
|
|
179
|
+
);
|
|
180
|
+
const queryFn = useCallback2(async () => {
|
|
181
|
+
if (!adapter) {
|
|
182
|
+
throw new Error(`Adapter not available for table: ${table}`);
|
|
183
|
+
}
|
|
184
|
+
if (id == null) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
if (adapter.queryById) {
|
|
188
|
+
return adapter.queryById(table, String(id), { select });
|
|
189
|
+
}
|
|
190
|
+
const result = await adapter.query(table, {
|
|
191
|
+
select,
|
|
192
|
+
where: { id },
|
|
193
|
+
limit: 1
|
|
194
|
+
});
|
|
195
|
+
return result.data[0] ?? null;
|
|
196
|
+
}, [adapter, table, id, select]);
|
|
197
|
+
const query = useQuery2({
|
|
198
|
+
queryKey,
|
|
199
|
+
queryFn,
|
|
200
|
+
enabled: enabled && status.isInitialized && adapter !== null && id != null,
|
|
201
|
+
staleTime
|
|
202
|
+
});
|
|
203
|
+
const refetch = useCallback2(async () => {
|
|
204
|
+
await query.refetch();
|
|
205
|
+
}, [query]);
|
|
206
|
+
return {
|
|
207
|
+
data: query.data,
|
|
208
|
+
isLoading: query.isLoading,
|
|
209
|
+
isPending: query.isPending,
|
|
210
|
+
isFetching: query.isFetching,
|
|
211
|
+
error: query.error,
|
|
212
|
+
refetch
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/hooks/useAdvanceQuery.ts
|
|
217
|
+
import {
|
|
218
|
+
useCallback as useCallback3,
|
|
219
|
+
useMemo as useMemo3,
|
|
220
|
+
useState,
|
|
221
|
+
useEffect as useEffect2
|
|
222
|
+
} from "react";
|
|
223
|
+
import { useQuery as useQuery3 } from "@tanstack/react-query";
|
|
224
|
+
import { useSessionStorageState } from "@pol-studios/hooks/storage";
|
|
225
|
+
var createDefaultFilterState = () => ({
|
|
226
|
+
id: "root",
|
|
227
|
+
op: "AND",
|
|
228
|
+
filters: [],
|
|
229
|
+
pagination: void 0,
|
|
230
|
+
sort: [],
|
|
231
|
+
isReady: true
|
|
232
|
+
});
|
|
233
|
+
function useAdvanceQuery(table, options) {
|
|
234
|
+
const tableName = typeof table === "string" ? table : `${table.schema}.${table.table}`;
|
|
235
|
+
const { registry, status, queryClient } = useDataLayer();
|
|
236
|
+
const supabase = useSupabase();
|
|
237
|
+
const {
|
|
238
|
+
filterKey,
|
|
239
|
+
initialFilters,
|
|
240
|
+
enabled = true,
|
|
241
|
+
timeout = 15e3,
|
|
242
|
+
count = "exact",
|
|
243
|
+
realtime,
|
|
244
|
+
select,
|
|
245
|
+
where,
|
|
246
|
+
orderBy,
|
|
247
|
+
limit,
|
|
248
|
+
offset,
|
|
249
|
+
...restOptions
|
|
250
|
+
} = options;
|
|
251
|
+
const isPowerSync = status.currentBackend === "powersync";
|
|
252
|
+
const realtimeEnabled = realtime ?? isPowerSync;
|
|
253
|
+
const defaultFilterState = useMemo3(
|
|
254
|
+
() => initialFilters ?? createDefaultFilterState(),
|
|
255
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
256
|
+
[]
|
|
257
|
+
// Only compute once
|
|
258
|
+
);
|
|
259
|
+
const [filtersRaw, setFiltersRaw] = useSessionStorageState(
|
|
260
|
+
filterKey,
|
|
261
|
+
defaultFilterState
|
|
262
|
+
);
|
|
263
|
+
const filters = filtersRaw ?? defaultFilterState;
|
|
264
|
+
const setFilters = useCallback3(
|
|
265
|
+
(action) => {
|
|
266
|
+
if (typeof action === "function") {
|
|
267
|
+
setFiltersRaw((prev) => action(prev ?? defaultFilterState));
|
|
268
|
+
} else {
|
|
269
|
+
setFiltersRaw(action);
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
[setFiltersRaw, defaultFilterState]
|
|
273
|
+
);
|
|
274
|
+
const hasAdvancedFilters = useMemo3(
|
|
275
|
+
() => (filters?.filters?.length ?? 0) > 0 || !!filters?.naturalLanguageQuery,
|
|
276
|
+
[filters?.filters?.length, filters?.naturalLanguageQuery]
|
|
277
|
+
);
|
|
278
|
+
const usePowerSyncPath = !hasAdvancedFilters && isPowerSync;
|
|
279
|
+
const powerSyncOrderBy = useMemo3(() => {
|
|
280
|
+
if (filters?.sort && filters.sort.length > 0) {
|
|
281
|
+
return filters.sort.map((s) => ({
|
|
282
|
+
field: s.field,
|
|
283
|
+
direction: s.direction
|
|
284
|
+
}));
|
|
285
|
+
}
|
|
286
|
+
return orderBy;
|
|
287
|
+
}, [filters?.sort, orderBy]);
|
|
288
|
+
const powerSyncResult = useDbQuery(table, {
|
|
289
|
+
select,
|
|
290
|
+
where,
|
|
291
|
+
orderBy: powerSyncOrderBy,
|
|
292
|
+
limit: filters?.pagination?.limit ?? limit,
|
|
293
|
+
offset: filters?.pagination?.offset ?? offset,
|
|
294
|
+
enabled: enabled && usePowerSyncPath && filters?.isReady !== false,
|
|
295
|
+
realtime: realtimeEnabled
|
|
296
|
+
// Enable watch() subscriptions for reactive updates
|
|
297
|
+
});
|
|
298
|
+
const [extraData, setExtraData] = useState({});
|
|
299
|
+
const edgeFunctionQueryKey = useMemo3(
|
|
300
|
+
() => [
|
|
301
|
+
"v3",
|
|
302
|
+
"advance-query",
|
|
303
|
+
tableName,
|
|
304
|
+
select,
|
|
305
|
+
JSON.stringify(where),
|
|
306
|
+
JSON.stringify(filters),
|
|
307
|
+
status.currentBackend
|
|
308
|
+
],
|
|
309
|
+
[tableName, select, where, filters, status.currentBackend]
|
|
310
|
+
);
|
|
311
|
+
const edgeFunctionResult = useQuery3({
|
|
312
|
+
queryKey: edgeFunctionQueryKey,
|
|
313
|
+
queryFn: async ({ signal }) => {
|
|
314
|
+
const { data: { session } } = await supabase.auth.getSession();
|
|
315
|
+
if (!session?.access_token) {
|
|
316
|
+
throw new Error("No active session");
|
|
317
|
+
}
|
|
318
|
+
const controller = new AbortController();
|
|
319
|
+
signal.addEventListener("abort", () => controller.abort());
|
|
320
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
321
|
+
try {
|
|
322
|
+
const filterBody = {
|
|
323
|
+
id: filters.id || "root",
|
|
324
|
+
op: filters.op || "AND",
|
|
325
|
+
not: filters.not,
|
|
326
|
+
filters: filters.filters || []
|
|
327
|
+
};
|
|
328
|
+
const baseFilters = [];
|
|
329
|
+
if (where) {
|
|
330
|
+
Object.entries(where).forEach(([field, value]) => {
|
|
331
|
+
if (value !== void 0 && value !== null) {
|
|
332
|
+
if (typeof value === "object" && "in" in value) {
|
|
333
|
+
baseFilters.push({
|
|
334
|
+
id: `base-${field}`,
|
|
335
|
+
field,
|
|
336
|
+
op: "in",
|
|
337
|
+
value: value.in
|
|
338
|
+
});
|
|
339
|
+
} else {
|
|
340
|
+
baseFilters.push({
|
|
341
|
+
id: `base-${field}`,
|
|
342
|
+
field,
|
|
343
|
+
op: "=",
|
|
344
|
+
value
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
const combinedFilters = [...baseFilters, ...filterBody.filters];
|
|
351
|
+
const currentKey = `${tableName}${select}${JSON.stringify(omit(filters, ["pagination", "isReady"]))}`;
|
|
352
|
+
const res = await fetch(
|
|
353
|
+
`${getSupabaseUrl()}/functions/v1/query?forceDenoVersion=2`,
|
|
354
|
+
{
|
|
355
|
+
method: "POST",
|
|
356
|
+
headers: {
|
|
357
|
+
"Content-Type": "application/json",
|
|
358
|
+
Authorization: `Bearer ${session.access_token}`
|
|
359
|
+
},
|
|
360
|
+
body: JSON.stringify({
|
|
361
|
+
table: tableName,
|
|
362
|
+
schema: "public",
|
|
363
|
+
select: select ?? "*",
|
|
364
|
+
filters: {
|
|
365
|
+
id: filterBody.id,
|
|
366
|
+
op: filterBody.op,
|
|
367
|
+
not: filterBody.not,
|
|
368
|
+
filters: combinedFilters
|
|
369
|
+
},
|
|
370
|
+
pagination: filters.pagination,
|
|
371
|
+
sort: filters.sort || orderBy?.map((o) => ({
|
|
372
|
+
field: o.field,
|
|
373
|
+
direction: o.direction
|
|
374
|
+
})),
|
|
375
|
+
distinctOn: filters.distinctOn,
|
|
376
|
+
naturalLanguageQuery: filters.naturalLanguageQuery,
|
|
377
|
+
count: currentKey === extraData.key ? "" : count
|
|
378
|
+
}),
|
|
379
|
+
signal: controller.signal
|
|
380
|
+
}
|
|
381
|
+
);
|
|
382
|
+
if (!res.ok) {
|
|
383
|
+
const errorData = await res.json();
|
|
384
|
+
const errorMessage = typeof errorData?.error === "string" ? errorData.error : errorData?.error?.message || errorData?.message || "Query failed";
|
|
385
|
+
throw new Error(errorMessage);
|
|
386
|
+
}
|
|
387
|
+
const result2 = await res.json();
|
|
388
|
+
if (result2.clarification) {
|
|
389
|
+
return {
|
|
390
|
+
data: [],
|
|
391
|
+
count: 0,
|
|
392
|
+
clarification: result2.clarification
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
setExtraData((prev) => ({
|
|
396
|
+
count: prev.key === currentKey ? prev.count : result2.count,
|
|
397
|
+
key: currentKey
|
|
398
|
+
}));
|
|
399
|
+
return {
|
|
400
|
+
data: result2.data,
|
|
401
|
+
count: result2.count
|
|
402
|
+
};
|
|
403
|
+
} finally {
|
|
404
|
+
clearTimeout(timeoutId);
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
enabled: enabled && !usePowerSyncPath && filters?.isReady !== false,
|
|
408
|
+
staleTime: 3e4,
|
|
409
|
+
gcTime: 3e5,
|
|
410
|
+
refetchOnMount: true,
|
|
411
|
+
refetchOnWindowFocus: false
|
|
412
|
+
});
|
|
413
|
+
useEffect2(() => {
|
|
414
|
+
if (!realtimeEnabled || usePowerSyncPath || !enabled) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const channel = supabase.channel(`advance-query-${tableName}-${filterKey}`).on(
|
|
418
|
+
"postgres_changes",
|
|
419
|
+
{
|
|
420
|
+
event: "*",
|
|
421
|
+
// Listen to INSERT, UPDATE, DELETE
|
|
422
|
+
schema: "public",
|
|
423
|
+
table: tableName
|
|
424
|
+
// Note: We can't easily filter by complex where clauses,
|
|
425
|
+
// so we invalidate on any change to the table
|
|
426
|
+
},
|
|
427
|
+
() => {
|
|
428
|
+
queryClient.invalidateQueries({ queryKey: edgeFunctionQueryKey });
|
|
429
|
+
}
|
|
430
|
+
).subscribe();
|
|
431
|
+
return () => {
|
|
432
|
+
supabase.removeChannel(channel);
|
|
433
|
+
};
|
|
434
|
+
}, [
|
|
435
|
+
realtimeEnabled,
|
|
436
|
+
usePowerSyncPath,
|
|
437
|
+
enabled,
|
|
438
|
+
supabase,
|
|
439
|
+
tableName,
|
|
440
|
+
filterKey,
|
|
441
|
+
queryClient,
|
|
442
|
+
edgeFunctionQueryKey
|
|
443
|
+
]);
|
|
444
|
+
const result = useMemo3(() => {
|
|
445
|
+
if (usePowerSyncPath) {
|
|
446
|
+
return {
|
|
447
|
+
data: powerSyncResult.data,
|
|
448
|
+
isLoading: powerSyncResult.isLoading,
|
|
449
|
+
isPending: powerSyncResult.isPending,
|
|
450
|
+
isFetching: powerSyncResult.isFetching,
|
|
451
|
+
isRefetching: powerSyncResult.isRefetching,
|
|
452
|
+
isSuccess: powerSyncResult.isSuccess,
|
|
453
|
+
isError: powerSyncResult.isError,
|
|
454
|
+
error: powerSyncResult.error,
|
|
455
|
+
refetch: powerSyncResult.refetch,
|
|
456
|
+
count: powerSyncResult.count ?? powerSyncResult.data?.length
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
return {
|
|
460
|
+
data: edgeFunctionResult.data?.data,
|
|
461
|
+
isLoading: edgeFunctionResult.isLoading,
|
|
462
|
+
isPending: edgeFunctionResult.isPending,
|
|
463
|
+
isFetching: edgeFunctionResult.isFetching,
|
|
464
|
+
isRefetching: edgeFunctionResult.isFetching,
|
|
465
|
+
isSuccess: edgeFunctionResult.isSuccess,
|
|
466
|
+
isError: edgeFunctionResult.isError,
|
|
467
|
+
error: edgeFunctionResult.error,
|
|
468
|
+
refetch: async () => {
|
|
469
|
+
await edgeFunctionResult.refetch();
|
|
470
|
+
},
|
|
471
|
+
count: edgeFunctionResult.data?.count ?? extraData.count,
|
|
472
|
+
clarification: edgeFunctionResult.data?.clarification
|
|
473
|
+
};
|
|
474
|
+
}, [
|
|
475
|
+
usePowerSyncPath,
|
|
476
|
+
powerSyncResult,
|
|
477
|
+
edgeFunctionResult,
|
|
478
|
+
extraData.count
|
|
479
|
+
]);
|
|
480
|
+
return [result, filters, setFilters];
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/hooks/useDbInsert.ts
|
|
484
|
+
import { useCallback as useCallback4, useMemo as useMemo4 } from "react";
|
|
485
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
486
|
+
function useDbInsert(table, options = {}) {
|
|
487
|
+
const { registry, status } = useDataLayer();
|
|
488
|
+
const queryClient = useQueryClient();
|
|
489
|
+
const { onSuccess, onError, invalidateTables = [table] } = options;
|
|
490
|
+
const adapter = useMemo4(() => {
|
|
491
|
+
if (!status.isInitialized) return null;
|
|
492
|
+
try {
|
|
493
|
+
return registry.getAdapter(table);
|
|
494
|
+
} catch {
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
}, [registry, table, status.isInitialized, status.currentBackend]);
|
|
498
|
+
const mutationFn = useCallback4(
|
|
499
|
+
async (data) => {
|
|
500
|
+
if (!adapter) {
|
|
501
|
+
throw new Error(`Adapter not available for table: ${table}`);
|
|
502
|
+
}
|
|
503
|
+
return adapter.insert(table, data);
|
|
504
|
+
},
|
|
505
|
+
[adapter, table]
|
|
506
|
+
);
|
|
507
|
+
const mutation = useMutation({
|
|
508
|
+
mutationFn,
|
|
509
|
+
onSuccess: (data) => {
|
|
510
|
+
invalidateTables.forEach((t) => {
|
|
511
|
+
queryClient.invalidateQueries({
|
|
512
|
+
predicate: (query) => query.queryKey[0] === "v3" && query.queryKey[2] === t
|
|
513
|
+
});
|
|
514
|
+
});
|
|
515
|
+
onSuccess?.(data);
|
|
516
|
+
},
|
|
517
|
+
onError: (error) => {
|
|
518
|
+
onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
return {
|
|
522
|
+
mutate: mutation.mutate,
|
|
523
|
+
mutateAsync: mutation.mutateAsync,
|
|
524
|
+
isPending: mutation.isPending,
|
|
525
|
+
error: mutation.error,
|
|
526
|
+
reset: mutation.reset,
|
|
527
|
+
data: mutation.data
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// src/hooks/useDbUpdate.ts
|
|
532
|
+
import { useCallback as useCallback5, useMemo as useMemo5 } from "react";
|
|
533
|
+
import { useMutation as useMutation2, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
|
|
534
|
+
function useDbUpdate(table, options = {}) {
|
|
535
|
+
const { registry, status } = useDataLayer();
|
|
536
|
+
const queryClient = useQueryClient2();
|
|
537
|
+
const {
|
|
538
|
+
onSuccess,
|
|
539
|
+
onError,
|
|
540
|
+
invalidateTables = [table],
|
|
541
|
+
optimistic = false
|
|
542
|
+
} = options;
|
|
543
|
+
const adapter = useMemo5(() => {
|
|
544
|
+
if (!status.isInitialized) return null;
|
|
545
|
+
try {
|
|
546
|
+
return registry.getAdapter(table);
|
|
547
|
+
} catch {
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
550
|
+
}, [registry, table, status.isInitialized, status.currentBackend]);
|
|
551
|
+
const mutationFn = useCallback5(
|
|
552
|
+
async (params) => {
|
|
553
|
+
if (!adapter) {
|
|
554
|
+
throw new Error(`Adapter not available for table: ${table}`);
|
|
555
|
+
}
|
|
556
|
+
return adapter.update(table, params.id, params.data);
|
|
557
|
+
},
|
|
558
|
+
[adapter, table]
|
|
559
|
+
);
|
|
560
|
+
const mutation = useMutation2({
|
|
561
|
+
mutationFn,
|
|
562
|
+
onMutate: optimistic ? async () => {
|
|
563
|
+
await queryClient.cancelQueries({
|
|
564
|
+
predicate: (query) => query.queryKey[0] === "v3" && query.queryKey[2] === table
|
|
565
|
+
});
|
|
566
|
+
const previousData = queryClient.getQueriesData({
|
|
567
|
+
predicate: (query) => query.queryKey[0] === "v3" && query.queryKey[2] === table
|
|
568
|
+
});
|
|
569
|
+
return { previousData };
|
|
570
|
+
} : void 0,
|
|
571
|
+
onSuccess: (data) => {
|
|
572
|
+
invalidateTables.forEach((t) => {
|
|
573
|
+
queryClient.invalidateQueries({
|
|
574
|
+
predicate: (query) => query.queryKey[0] === "v3" && query.queryKey[2] === t
|
|
575
|
+
});
|
|
576
|
+
});
|
|
577
|
+
onSuccess?.(data);
|
|
578
|
+
},
|
|
579
|
+
onError: (error, _variables, context) => {
|
|
580
|
+
if (optimistic && context?.previousData) {
|
|
581
|
+
context.previousData.forEach(([queryKey, data]) => {
|
|
582
|
+
queryClient.setQueryData(queryKey, data);
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
return {
|
|
589
|
+
mutate: mutation.mutate,
|
|
590
|
+
mutateAsync: mutation.mutateAsync,
|
|
591
|
+
isPending: mutation.isPending,
|
|
592
|
+
error: mutation.error,
|
|
593
|
+
reset: mutation.reset,
|
|
594
|
+
data: mutation.data
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// src/hooks/useDbUpsert.ts
|
|
599
|
+
import { useCallback as useCallback6, useMemo as useMemo6 } from "react";
|
|
600
|
+
import { useMutation as useMutation3, useQueryClient as useQueryClient3 } from "@tanstack/react-query";
|
|
601
|
+
function useDbUpsert(table, options = {}) {
|
|
602
|
+
const { registry, status } = useDataLayer();
|
|
603
|
+
const queryClient = useQueryClient3();
|
|
604
|
+
const { onSuccess, onError, invalidateTables = [table] } = options;
|
|
605
|
+
const adapter = useMemo6(() => {
|
|
606
|
+
if (!status.isInitialized) return null;
|
|
607
|
+
try {
|
|
608
|
+
return registry.getAdapter(table);
|
|
609
|
+
} catch {
|
|
610
|
+
return null;
|
|
611
|
+
}
|
|
612
|
+
}, [registry, table, status.isInitialized, status.currentBackend]);
|
|
613
|
+
const mutationFn = useCallback6(
|
|
614
|
+
async (data) => {
|
|
615
|
+
if (!adapter) {
|
|
616
|
+
throw new Error(`Adapter not available for table: ${table}`);
|
|
617
|
+
}
|
|
618
|
+
return adapter.upsert(table, data);
|
|
619
|
+
},
|
|
620
|
+
[adapter, table]
|
|
621
|
+
);
|
|
622
|
+
const mutation = useMutation3({
|
|
623
|
+
mutationFn,
|
|
624
|
+
onSuccess: (data) => {
|
|
625
|
+
invalidateTables.forEach((t) => {
|
|
626
|
+
queryClient.invalidateQueries({
|
|
627
|
+
predicate: (query) => query.queryKey[0] === "v3" && query.queryKey[2] === t
|
|
628
|
+
});
|
|
629
|
+
});
|
|
630
|
+
onSuccess?.(data);
|
|
631
|
+
},
|
|
632
|
+
onError: (error) => {
|
|
633
|
+
onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
return {
|
|
637
|
+
mutate: mutation.mutate,
|
|
638
|
+
mutateAsync: mutation.mutateAsync,
|
|
639
|
+
isPending: mutation.isPending,
|
|
640
|
+
error: mutation.error,
|
|
641
|
+
reset: mutation.reset,
|
|
642
|
+
data: mutation.data
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// src/hooks/useDbDelete.ts
|
|
647
|
+
import { useCallback as useCallback7, useMemo as useMemo7 } from "react";
|
|
648
|
+
import { useMutation as useMutation4, useQueryClient as useQueryClient4 } from "@tanstack/react-query";
|
|
649
|
+
function useDbDelete(table, options = {}) {
|
|
650
|
+
const { registry, status } = useDataLayer();
|
|
651
|
+
const queryClient = useQueryClient4();
|
|
652
|
+
const {
|
|
653
|
+
onSuccess,
|
|
654
|
+
onError,
|
|
655
|
+
invalidateTables = [table],
|
|
656
|
+
optimistic = false
|
|
657
|
+
} = options;
|
|
658
|
+
const adapter = useMemo7(() => {
|
|
659
|
+
if (!status.isInitialized) return null;
|
|
660
|
+
try {
|
|
661
|
+
return registry.getAdapter(table);
|
|
662
|
+
} catch {
|
|
663
|
+
return null;
|
|
664
|
+
}
|
|
665
|
+
}, [registry, table, status.isInitialized, status.currentBackend]);
|
|
666
|
+
const mutationFn = useCallback7(
|
|
667
|
+
async (id) => {
|
|
668
|
+
if (!adapter) {
|
|
669
|
+
throw new Error(`Adapter not available for table: ${table}`);
|
|
670
|
+
}
|
|
671
|
+
await adapter.delete(table, id);
|
|
672
|
+
},
|
|
673
|
+
[adapter, table]
|
|
674
|
+
);
|
|
675
|
+
const mutation = useMutation4({
|
|
676
|
+
mutationFn,
|
|
677
|
+
onMutate: optimistic ? async (id) => {
|
|
678
|
+
await queryClient.cancelQueries({
|
|
679
|
+
predicate: (query) => query.queryKey[0] === "v3" && query.queryKey[2] === table
|
|
680
|
+
});
|
|
681
|
+
const previousData = queryClient.getQueriesData({
|
|
682
|
+
predicate: (query) => query.queryKey[0] === "v3" && query.queryKey[2] === table
|
|
683
|
+
});
|
|
684
|
+
queryClient.setQueriesData(
|
|
685
|
+
{
|
|
686
|
+
predicate: (query) => query.queryKey[0] === "v3" && query.queryKey[2] === table
|
|
687
|
+
},
|
|
688
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
689
|
+
(old) => {
|
|
690
|
+
if (!old?.data) return old;
|
|
691
|
+
return {
|
|
692
|
+
...old,
|
|
693
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
694
|
+
data: old.data.filter((item) => item.id !== id)
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
);
|
|
698
|
+
return { previousData };
|
|
699
|
+
} : void 0,
|
|
700
|
+
onSuccess: () => {
|
|
701
|
+
invalidateTables.forEach((t) => {
|
|
702
|
+
queryClient.invalidateQueries({
|
|
703
|
+
predicate: (query) => query.queryKey[0] === "v3" && query.queryKey[2] === t
|
|
704
|
+
});
|
|
705
|
+
});
|
|
706
|
+
onSuccess?.();
|
|
707
|
+
},
|
|
708
|
+
onError: (error, _id, context) => {
|
|
709
|
+
if (optimistic && context?.previousData) {
|
|
710
|
+
context.previousData.forEach(([queryKey, data]) => {
|
|
711
|
+
queryClient.setQueryData(queryKey, data);
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
return {
|
|
718
|
+
mutate: mutation.mutate,
|
|
719
|
+
mutateAsync: mutation.mutateAsync,
|
|
720
|
+
isPending: mutation.isPending,
|
|
721
|
+
error: mutation.error,
|
|
722
|
+
reset: mutation.reset
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// src/hooks/useDbInfiniteQuery.ts
|
|
727
|
+
import { useMemo as useMemo8, useCallback as useCallback8 } from "react";
|
|
728
|
+
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
729
|
+
function buildInfiniteQueryKey(table, options) {
|
|
730
|
+
return [
|
|
731
|
+
"v3",
|
|
732
|
+
"infinite-query",
|
|
733
|
+
table,
|
|
734
|
+
options.select ?? "*",
|
|
735
|
+
JSON.stringify(options.where ?? {}),
|
|
736
|
+
JSON.stringify(options.orderBy ?? []),
|
|
737
|
+
options.pageSize ?? 50,
|
|
738
|
+
options.searchText ?? "",
|
|
739
|
+
JSON.stringify(options.searchFields ?? [])
|
|
740
|
+
];
|
|
741
|
+
}
|
|
742
|
+
function serializeInfiniteQueryOptions(options) {
|
|
743
|
+
return JSON.stringify({
|
|
744
|
+
select: options.select,
|
|
745
|
+
where: options.where,
|
|
746
|
+
orderBy: options.orderBy,
|
|
747
|
+
pageSize: options.pageSize,
|
|
748
|
+
searchText: options.searchText,
|
|
749
|
+
searchFields: options.searchFields
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
function resolveTableName2(table) {
|
|
753
|
+
if (typeof table === "string") {
|
|
754
|
+
return table;
|
|
755
|
+
}
|
|
756
|
+
return `${table.schema}.${table.table}`;
|
|
757
|
+
}
|
|
758
|
+
function buildSearchWhereClause(searchText, searchFields, existingWhere) {
|
|
759
|
+
const searchWhere = {};
|
|
760
|
+
if (searchFields.length === 1) {
|
|
761
|
+
searchWhere[searchFields[0]] = { like: `%${searchText}%` };
|
|
762
|
+
} else if (searchFields.length > 1) {
|
|
763
|
+
searchWhere[searchFields[0]] = { like: `%${searchText}%` };
|
|
764
|
+
}
|
|
765
|
+
return {
|
|
766
|
+
...existingWhere,
|
|
767
|
+
...searchWhere
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
function useDbInfiniteQuery(table, options = {}) {
|
|
771
|
+
const tableName = resolveTableName2(table);
|
|
772
|
+
const { registry, status } = useDataLayer();
|
|
773
|
+
const {
|
|
774
|
+
enabled = true,
|
|
775
|
+
staleTime = 3e4,
|
|
776
|
+
refetchOnWindowFocus = true,
|
|
777
|
+
pageSize = 50,
|
|
778
|
+
searchText,
|
|
779
|
+
searchFields,
|
|
780
|
+
...queryOptions
|
|
781
|
+
} = options;
|
|
782
|
+
const adapter = useMemo8(() => {
|
|
783
|
+
if (!status.isInitialized) return null;
|
|
784
|
+
try {
|
|
785
|
+
return registry.getAdapter(tableName);
|
|
786
|
+
} catch {
|
|
787
|
+
return null;
|
|
788
|
+
}
|
|
789
|
+
}, [registry, tableName, status.isInitialized, status.currentBackend]);
|
|
790
|
+
const queryKey = useMemo8(
|
|
791
|
+
() => buildInfiniteQueryKey(tableName, options),
|
|
792
|
+
[tableName, serializeInfiniteQueryOptions(options)]
|
|
793
|
+
);
|
|
794
|
+
const effectiveWhere = useMemo8(() => {
|
|
795
|
+
if (searchText && searchFields && searchFields.length > 0) {
|
|
796
|
+
return buildSearchWhereClause(searchText, searchFields, queryOptions.where);
|
|
797
|
+
}
|
|
798
|
+
return queryOptions.where;
|
|
799
|
+
}, [searchText, searchFields, queryOptions.where]);
|
|
800
|
+
const memoizedQueryOptions = useMemo8(
|
|
801
|
+
() => ({
|
|
802
|
+
select: queryOptions.select,
|
|
803
|
+
where: effectiveWhere,
|
|
804
|
+
orderBy: queryOptions.orderBy
|
|
805
|
+
}),
|
|
806
|
+
[queryOptions.select, effectiveWhere, queryOptions.orderBy]
|
|
807
|
+
);
|
|
808
|
+
const infiniteQuery = useInfiniteQuery({
|
|
809
|
+
queryKey,
|
|
810
|
+
queryFn: async ({ pageParam }) => {
|
|
811
|
+
if (!adapter) {
|
|
812
|
+
throw new Error(`Adapter not available for table: ${tableName}`);
|
|
813
|
+
}
|
|
814
|
+
const offset = (pageParam - 1) * pageSize;
|
|
815
|
+
const result = await adapter.query(tableName, {
|
|
816
|
+
...memoizedQueryOptions,
|
|
817
|
+
limit: pageSize,
|
|
818
|
+
offset
|
|
819
|
+
});
|
|
820
|
+
return {
|
|
821
|
+
data: result.data ?? [],
|
|
822
|
+
count: result.count
|
|
823
|
+
};
|
|
824
|
+
},
|
|
825
|
+
initialPageParam: 1,
|
|
826
|
+
getNextPageParam: (lastPage, allPages) => {
|
|
827
|
+
const totalLoaded = allPages.reduce((sum, page) => sum + page.data.length, 0);
|
|
828
|
+
const totalCount = lastPage.count;
|
|
829
|
+
if (totalCount !== void 0 && totalLoaded >= totalCount) {
|
|
830
|
+
return void 0;
|
|
831
|
+
}
|
|
832
|
+
if (lastPage.data.length < pageSize) {
|
|
833
|
+
return void 0;
|
|
834
|
+
}
|
|
835
|
+
return allPages.length + 1;
|
|
836
|
+
},
|
|
837
|
+
enabled: enabled && status.isInitialized && adapter !== null,
|
|
838
|
+
staleTime,
|
|
839
|
+
refetchOnWindowFocus
|
|
840
|
+
});
|
|
841
|
+
const flattenedData = useMemo8(() => {
|
|
842
|
+
if (!infiniteQuery.data?.pages) return void 0;
|
|
843
|
+
return infiniteQuery.data.pages.flatMap((page) => page.data);
|
|
844
|
+
}, [infiniteQuery.data?.pages]);
|
|
845
|
+
const count = useMemo8(() => {
|
|
846
|
+
if (!infiniteQuery.data?.pages || infiniteQuery.data.pages.length === 0) {
|
|
847
|
+
return void 0;
|
|
848
|
+
}
|
|
849
|
+
return infiniteQuery.data.pages[infiniteQuery.data.pages.length - 1].count;
|
|
850
|
+
}, [infiniteQuery.data?.pages]);
|
|
851
|
+
const fetchNextPage = useCallback8(async () => {
|
|
852
|
+
await infiniteQuery.fetchNextPage();
|
|
853
|
+
}, [infiniteQuery]);
|
|
854
|
+
const refetch = useCallback8(async () => {
|
|
855
|
+
await infiniteQuery.refetch();
|
|
856
|
+
}, [infiniteQuery]);
|
|
857
|
+
return {
|
|
858
|
+
data: flattenedData,
|
|
859
|
+
isLoading: infiniteQuery.isLoading,
|
|
860
|
+
isPending: infiniteQuery.isPending,
|
|
861
|
+
isFetching: infiniteQuery.isFetching,
|
|
862
|
+
error: infiniteQuery.error,
|
|
863
|
+
fetchNextPage,
|
|
864
|
+
hasNextPage: infiniteQuery.hasNextPage ?? false,
|
|
865
|
+
isFetchingNextPage: infiniteQuery.isFetchingNextPage,
|
|
866
|
+
count,
|
|
867
|
+
refetch
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
// src/hooks/useDbCount.ts
|
|
872
|
+
import { useMemo as useMemo9, useCallback as useCallback9 } from "react";
|
|
873
|
+
import { useQuery as useQuery4 } from "@tanstack/react-query";
|
|
874
|
+
function useDbCount(table, options = {}) {
|
|
875
|
+
const { registry, status } = useDataLayer();
|
|
876
|
+
const { enabled = true, staleTime = 3e4, where } = options;
|
|
877
|
+
const adapter = useMemo9(() => {
|
|
878
|
+
if (!status.isInitialized) return null;
|
|
879
|
+
try {
|
|
880
|
+
return registry.getAdapter(table);
|
|
881
|
+
} catch {
|
|
882
|
+
return null;
|
|
883
|
+
}
|
|
884
|
+
}, [registry, table, status.isInitialized, status.currentBackend]);
|
|
885
|
+
const queryKey = useMemo9(
|
|
886
|
+
() => ["v3", "count", table, JSON.stringify(where ?? {})],
|
|
887
|
+
[table, where]
|
|
888
|
+
);
|
|
889
|
+
const queryFn = useCallback9(async () => {
|
|
890
|
+
if (!adapter) {
|
|
891
|
+
throw new Error(`Adapter not available for table: ${table}`);
|
|
892
|
+
}
|
|
893
|
+
const result = await adapter.query(table, { where, select: "id" });
|
|
894
|
+
return result.count ?? result.data.length;
|
|
895
|
+
}, [adapter, table, where]);
|
|
896
|
+
const query = useQuery4({
|
|
897
|
+
queryKey,
|
|
898
|
+
queryFn,
|
|
899
|
+
enabled: enabled && status.isInitialized && adapter !== null,
|
|
900
|
+
staleTime
|
|
901
|
+
});
|
|
902
|
+
const refetch = useCallback9(async () => {
|
|
903
|
+
await query.refetch();
|
|
904
|
+
}, [query]);
|
|
905
|
+
return {
|
|
906
|
+
count: query.data,
|
|
907
|
+
isLoading: query.isLoading,
|
|
908
|
+
isFetching: query.isFetching,
|
|
909
|
+
error: query.error,
|
|
910
|
+
refetch
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
export {
|
|
915
|
+
DataLayerContext,
|
|
916
|
+
useDataLayer,
|
|
917
|
+
useDataLayerOptional,
|
|
918
|
+
useDbQuery,
|
|
919
|
+
useDbQueryById,
|
|
920
|
+
useAdvanceQuery,
|
|
921
|
+
useDbInsert,
|
|
922
|
+
useDbUpdate,
|
|
923
|
+
useDbUpsert,
|
|
924
|
+
useDbDelete,
|
|
925
|
+
useDbInfiniteQuery,
|
|
926
|
+
useDbCount
|
|
927
|
+
};
|
|
928
|
+
//# sourceMappingURL=chunk-3M2U6TXH.js.map
|