@powersync/tanstack-react-query 0.1.9 → 0.1.11
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/README.md +32 -0
- package/lib/hooks/usePowerSyncQueries.d.ts +15 -0
- package/lib/hooks/usePowerSyncQueries.js +151 -0
- package/lib/hooks/usePowerSyncQueries.js.map +1 -0
- package/lib/hooks/useQueries.d.ts +59 -0
- package/lib/hooks/useQueries.js +70 -0
- package/lib/hooks/useQueries.js.map +1 -0
- package/lib/hooks/useQuery.d.ts +58 -0
- package/lib/hooks/useQuery.js +9 -71
- package/lib/hooks/useQuery.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/package.json +3 -3
- package/src/hooks/usePowerSyncQueries.ts +192 -0
- package/src/hooks/useQueries.ts +165 -0
- package/src/hooks/useQuery.ts +70 -84
- package/src/index.ts +2 -0
package/README.md
CHANGED
|
@@ -106,6 +106,38 @@ export const TodoListDisplaySuspense = () => {
|
|
|
106
106
|
};
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
+
### useQueries
|
|
110
|
+
|
|
111
|
+
The `useQueries` hook allows you to run multiple queries in parallel and combine the results into a single result.
|
|
112
|
+
|
|
113
|
+
```JSX
|
|
114
|
+
// TodoListDisplay.jsx
|
|
115
|
+
import { useQueries } from '@powersync/tanstack-react-query';
|
|
116
|
+
|
|
117
|
+
export const TodoListDisplay = () => {
|
|
118
|
+
const { data: todoLists } = useQueries({
|
|
119
|
+
queries: [
|
|
120
|
+
{ queryKey: ['todoLists'], query: 'SELECT * from lists' },
|
|
121
|
+
{ queryKey: ['todoLists2'], query: 'SELECT * from lists2' },
|
|
122
|
+
],
|
|
123
|
+
combine: (results) => {
|
|
124
|
+
return {
|
|
125
|
+
data: results.map((result) => result.data),
|
|
126
|
+
pending: results.some((result) => result.isPending),
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<div>
|
|
133
|
+
{todoLists.map((list) => (
|
|
134
|
+
<li key={list.id}>{list.name}</li>
|
|
135
|
+
))}
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
};
|
|
139
|
+
```
|
|
140
|
+
|
|
109
141
|
### TypeScript Support
|
|
110
142
|
|
|
111
143
|
A type can be specified for each row returned by `useQuery` and `useSuspenseQuery`.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type CompilableQuery } from '@powersync/common';
|
|
2
|
+
import * as Tanstack from '@tanstack/react-query';
|
|
3
|
+
export type UsePowerSyncQueriesInput = {
|
|
4
|
+
query?: string | CompilableQuery<unknown>;
|
|
5
|
+
parameters?: unknown[];
|
|
6
|
+
queryKey: Tanstack.QueryKey;
|
|
7
|
+
}[];
|
|
8
|
+
export type UsePowerSyncQueriesOutput = {
|
|
9
|
+
sqlStatement: string;
|
|
10
|
+
queryParameters: unknown[];
|
|
11
|
+
tables: string[];
|
|
12
|
+
error?: Error;
|
|
13
|
+
queryFn: () => Promise<unknown[]>;
|
|
14
|
+
}[];
|
|
15
|
+
export declare function usePowerSyncQueries(queries: UsePowerSyncQueriesInput, queryClient: Tanstack.QueryClient): UsePowerSyncQueriesOutput;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { parseQuery } from '@powersync/common';
|
|
2
|
+
import { usePowerSync } from '@powersync/react';
|
|
3
|
+
import { useEffect, useState, useCallback, useMemo } from 'react';
|
|
4
|
+
export function usePowerSyncQueries(queries, queryClient) {
|
|
5
|
+
const powerSync = usePowerSync();
|
|
6
|
+
const [tablesArr, setTablesArr] = useState(() => queries.map(() => []));
|
|
7
|
+
const [errorsArr, setErrorsArr] = useState(() => queries.map(() => undefined));
|
|
8
|
+
const updateTablesArr = useCallback((tables, idx) => {
|
|
9
|
+
setTablesArr((prev) => {
|
|
10
|
+
if (JSON.stringify(prev[idx]) === JSON.stringify(tables))
|
|
11
|
+
return prev;
|
|
12
|
+
const next = [...prev];
|
|
13
|
+
next[idx] = tables;
|
|
14
|
+
return next;
|
|
15
|
+
});
|
|
16
|
+
}, []);
|
|
17
|
+
const updateErrorsArr = useCallback((error, idx) => {
|
|
18
|
+
setErrorsArr((prev) => {
|
|
19
|
+
if (prev[idx]?.message === error?.message)
|
|
20
|
+
return prev;
|
|
21
|
+
const next = [...prev];
|
|
22
|
+
next[idx] = error;
|
|
23
|
+
return next;
|
|
24
|
+
});
|
|
25
|
+
}, []);
|
|
26
|
+
const parsedQueries = useMemo(() => queries.map((queryInput) => {
|
|
27
|
+
const { query, parameters = [], queryKey } = queryInput;
|
|
28
|
+
if (!query) {
|
|
29
|
+
return {
|
|
30
|
+
query,
|
|
31
|
+
parameters,
|
|
32
|
+
queryKey,
|
|
33
|
+
sqlStatement: '',
|
|
34
|
+
queryParameters: [],
|
|
35
|
+
parseError: undefined
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const parsed = parseQuery(query, parameters);
|
|
40
|
+
return {
|
|
41
|
+
query,
|
|
42
|
+
parameters,
|
|
43
|
+
queryKey,
|
|
44
|
+
sqlStatement: parsed.sqlStatement,
|
|
45
|
+
queryParameters: parsed.parameters,
|
|
46
|
+
parseError: undefined
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
return {
|
|
51
|
+
query,
|
|
52
|
+
parameters,
|
|
53
|
+
queryKey,
|
|
54
|
+
sqlStatement: '',
|
|
55
|
+
queryParameters: [],
|
|
56
|
+
parseError: e
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}), [queries]);
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
parsedQueries.forEach((pq, idx) => {
|
|
62
|
+
if (pq.parseError) {
|
|
63
|
+
updateErrorsArr(pq.parseError, idx);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}, [parsedQueries, updateErrorsArr]);
|
|
67
|
+
const stringifiedQueriesDeps = JSON.stringify(parsedQueries.map((q) => ({
|
|
68
|
+
sql: q.sqlStatement,
|
|
69
|
+
params: q.queryParameters
|
|
70
|
+
})));
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
const listeners = parsedQueries.map((pq, idx) => {
|
|
73
|
+
if (pq.parseError || !pq.query) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
(async () => {
|
|
77
|
+
try {
|
|
78
|
+
const tables = await powerSync.resolveTables(pq.sqlStatement, pq.queryParameters);
|
|
79
|
+
updateTablesArr(tables, idx);
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
updateErrorsArr(e, idx);
|
|
83
|
+
}
|
|
84
|
+
})();
|
|
85
|
+
return powerSync.registerListener({
|
|
86
|
+
schemaChanged: async () => {
|
|
87
|
+
try {
|
|
88
|
+
const tables = await powerSync.resolveTables(pq.sqlStatement, pq.queryParameters);
|
|
89
|
+
updateTablesArr(tables, idx);
|
|
90
|
+
queryClient.invalidateQueries({ queryKey: pq.queryKey });
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
updateErrorsArr(e, idx);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
return () => {
|
|
99
|
+
listeners.forEach((l) => l?.());
|
|
100
|
+
};
|
|
101
|
+
}, [powerSync, queryClient, stringifiedQueriesDeps, updateTablesArr, updateErrorsArr]);
|
|
102
|
+
const stringifiedQueryKeys = JSON.stringify(parsedQueries.map((q) => q.queryKey));
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
const aborts = parsedQueries.map((pq, idx) => {
|
|
105
|
+
if (pq.parseError || !pq.query) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const abort = new AbortController();
|
|
109
|
+
powerSync.onChangeWithCallback({
|
|
110
|
+
onChange: () => {
|
|
111
|
+
queryClient.invalidateQueries({ queryKey: pq.queryKey });
|
|
112
|
+
},
|
|
113
|
+
onError: (e) => {
|
|
114
|
+
updateErrorsArr(e, idx);
|
|
115
|
+
}
|
|
116
|
+
}, {
|
|
117
|
+
tables: tablesArr[idx],
|
|
118
|
+
signal: abort.signal
|
|
119
|
+
});
|
|
120
|
+
return abort;
|
|
121
|
+
});
|
|
122
|
+
return () => aborts.forEach((a) => a?.abort());
|
|
123
|
+
}, [powerSync, queryClient, tablesArr, updateErrorsArr, stringifiedQueryKeys]);
|
|
124
|
+
return useMemo(() => {
|
|
125
|
+
return parsedQueries.map((pq, idx) => {
|
|
126
|
+
const error = errorsArr[idx] || pq.parseError;
|
|
127
|
+
const queryFn = async () => {
|
|
128
|
+
if (error)
|
|
129
|
+
throw error;
|
|
130
|
+
if (!pq.query)
|
|
131
|
+
throw new Error('No query provided');
|
|
132
|
+
try {
|
|
133
|
+
return typeof pq.query === 'string'
|
|
134
|
+
? await powerSync.getAll(pq.sqlStatement, pq.queryParameters)
|
|
135
|
+
: await pq.query.execute();
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
throw e;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
return {
|
|
142
|
+
sqlStatement: pq.sqlStatement,
|
|
143
|
+
queryParameters: pq.queryParameters,
|
|
144
|
+
tables: tablesArr[idx],
|
|
145
|
+
error,
|
|
146
|
+
queryFn
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
}, [parsedQueries, errorsArr, tablesArr, powerSync]);
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=usePowerSyncQueries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePowerSyncQueries.js","sourceRoot":"","sources":["../../src/hooks/usePowerSyncQueries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAiBlE,MAAM,UAAU,mBAAmB,CACjC,OAAiC,EACjC,WAAiC;IAEjC,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IAEjC,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAa,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACpF,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAwB,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAEtG,MAAM,eAAe,GAAG,WAAW,CAAC,CAAC,MAAgB,EAAE,GAAW,EAAE,EAAE;QACpE,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE;YACpB,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC;YACtE,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;YACnB,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,eAAe,GAAG,WAAW,CAAC,CAAC,KAAwB,EAAE,GAAW,EAAE,EAAE;QAC5E,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE;YACpB,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,KAAK,KAAK,EAAE,OAAO;gBAAE,OAAO,IAAI,CAAC;YACvD,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YAClB,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,aAAa,GAAG,OAAO,CAC3B,GAAG,EAAE,CACH,OAAO,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE;QACzB,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,EAAE,EAAE,QAAQ,EAAE,GAAG,UAAU,CAAC;QAExD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO;gBACL,KAAK;gBACL,UAAU;gBACV,QAAQ;gBACR,YAAY,EAAE,EAAE;gBAChB,eAAe,EAAE,EAAE;gBACnB,UAAU,EAAE,SAAS;aACtB,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;YAC7C,OAAO;gBACL,KAAK;gBACL,UAAU;gBACV,QAAQ;gBACR,YAAY,EAAE,MAAM,CAAC,YAAY;gBACjC,eAAe,EAAE,MAAM,CAAC,UAAU;gBAClC,UAAU,EAAE,SAAS;aACtB,CAAC;QACJ,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO;gBACL,KAAK;gBACL,UAAU;gBACV,QAAQ;gBACR,YAAY,EAAE,EAAE;gBAChB,eAAe,EAAE,EAAE;gBACnB,UAAU,EAAE,CAAU;aACvB,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,EACJ,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE;YAChC,IAAI,EAAE,CAAC,UAAU,EAAE,CAAC;gBAClB,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YACtC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC,CAAC;IAErC,MAAM,sBAAsB,GAAG,IAAI,CAAC,SAAS,CAC3C,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACxB,GAAG,EAAE,CAAC,CAAC,YAAY;QACnB,MAAM,EAAE,CAAC,CAAC,eAAe;KAC1B,CAAC,CAAC,CACJ,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,SAAS,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE;YAC9C,IAAI,EAAE,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;gBAC/B,OAAO,IAAI,CAAC;YACd,CAAC;YAED,CAAC,KAAK,IAAI,EAAE;gBACV,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,aAAa,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC;oBAClF,eAAe,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;gBAC/B,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,eAAe,CAAC,CAAU,EAAE,GAAG,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC,CAAC,EAAE,CAAC;YAEL,OAAO,SAAS,CAAC,gBAAgB,CAAC;gBAChC,aAAa,EAAE,KAAK,IAAI,EAAE;oBACxB,IAAI,CAAC;wBACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,aAAa,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC;wBAClF,eAAe,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;wBAC7B,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;oBAC3D,CAAC;oBAAC,OAAO,CAAC,EAAE,CAAC;wBACX,eAAe,CAAC,CAAU,EAAE,GAAG,CAAC,CAAC;oBACnC,CAAC;gBACH,CAAC;aACF,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAClC,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,sBAAsB,EAAE,eAAe,EAAE,eAAe,CAAC,CAAC,CAAC;IAEvF,MAAM,oBAAoB,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IAElF,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE;YAC3C,IAAI,EAAE,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;gBAC/B,OAAO,IAAI,CAAC;YACd,CAAC;YAED,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;YAEpC,SAAS,CAAC,oBAAoB,CAC5B;gBACE,QAAQ,EAAE,GAAG,EAAE;oBACb,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC3D,CAAC;gBACD,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;oBACb,eAAe,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;gBAC1B,CAAC;aACF,EACD;gBACE,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC;gBACtB,MAAM,EAAE,KAAK,CAAC,MAAM;aACrB,CACF,CAAC;YAEF,OAAO,KAAK,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACjD,CAAC,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAE/E,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE;YACnC,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC;YAE9C,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;gBACzB,IAAI,KAAK;oBAAE,MAAM,KAAK,CAAC;gBACvB,IAAI,CAAC,EAAE,CAAC,KAAK;oBAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBAEpD,IAAI,CAAC;oBACH,OAAO,OAAO,EAAE,CAAC,KAAK,KAAK,QAAQ;wBACjC,CAAC,CAAC,MAAM,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,eAAe,CAAC;wBAC7D,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;gBAC/B,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,MAAM,CAAC,CAAC;gBACV,CAAC;YACH,CAAC,CAAC;YAEF,OAAO;gBACL,YAAY,EAAE,EAAE,CAAC,YAAY;gBAC7B,eAAe,EAAE,EAAE,CAAC,eAAe;gBACnC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC;gBACtB,KAAK;gBACL,OAAO;aACR,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type CompilableQuery } from '@powersync/common';
|
|
2
|
+
import * as Tanstack from '@tanstack/react-query';
|
|
3
|
+
export type PowerSyncQueryOptions<T> = {
|
|
4
|
+
query?: string | CompilableQuery<T>;
|
|
5
|
+
parameters?: any[];
|
|
6
|
+
};
|
|
7
|
+
export type PowerSyncQueryOption<T = unknown[]> = Tanstack.UseQueryOptions<T[]> & PowerSyncQueryOptions<T>;
|
|
8
|
+
export type InferQueryResults<TQueries extends readonly unknown[]> = {
|
|
9
|
+
[K in keyof TQueries]: TQueries[K] extends {
|
|
10
|
+
query: CompilableQuery<infer TData>;
|
|
11
|
+
} ? Tanstack.UseQueryResult<TData[]> : Tanstack.UseQueryResult<unknown[]>;
|
|
12
|
+
};
|
|
13
|
+
export type ExplicitQueryResults<T extends readonly unknown[]> = {
|
|
14
|
+
[K in keyof T]: Tanstack.UseQueryResult<T[K][]>;
|
|
15
|
+
};
|
|
16
|
+
export type EnhancedInferQueryResults<TQueries extends readonly unknown[]> = {
|
|
17
|
+
[K in keyof TQueries]: TQueries[K] extends {
|
|
18
|
+
query: CompilableQuery<infer TData>;
|
|
19
|
+
} ? Tanstack.UseQueryResult<TData[]> & {
|
|
20
|
+
queryKey: Tanstack.QueryKey;
|
|
21
|
+
} : Tanstack.UseQueryResult<unknown[]> & {
|
|
22
|
+
queryKey: Tanstack.QueryKey;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export type EnhancedExplicitQueryResults<T extends readonly unknown[]> = {
|
|
26
|
+
[K in keyof T]: Tanstack.UseQueryResult<T[K][]> & {
|
|
27
|
+
queryKey: Tanstack.QueryKey;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export type UseQueriesExplicitWithCombineOptions<T extends readonly unknown[], TCombined> = {
|
|
31
|
+
queries: readonly [...{
|
|
32
|
+
[K in keyof T]: PowerSyncQueryOption<T[K]>;
|
|
33
|
+
}];
|
|
34
|
+
combine: (results: EnhancedExplicitQueryResults<T>) => TCombined;
|
|
35
|
+
};
|
|
36
|
+
export type UseQueriesExplicitWithoutCombineOptions<T extends readonly unknown[]> = {
|
|
37
|
+
queries: readonly [...{
|
|
38
|
+
[K in keyof T]: PowerSyncQueryOption<T[K]>;
|
|
39
|
+
}];
|
|
40
|
+
combine?: undefined;
|
|
41
|
+
};
|
|
42
|
+
export type UseQueriesAutoInferenceWithCombineOptions<TQueries extends readonly PowerSyncQueryOption[], TCombined> = {
|
|
43
|
+
queries: readonly [...TQueries];
|
|
44
|
+
combine: (results: EnhancedInferQueryResults<TQueries>) => TCombined;
|
|
45
|
+
};
|
|
46
|
+
export type UseQueriesAutoInferenceWithoutCombineOptions<TQueries extends readonly PowerSyncQueryOption[]> = {
|
|
47
|
+
queries: readonly [...TQueries];
|
|
48
|
+
combine?: undefined;
|
|
49
|
+
};
|
|
50
|
+
export type UseQueriesBaseOptions = {
|
|
51
|
+
queries: readonly (Tanstack.UseQueryOptions & PowerSyncQueryOptions<unknown>)[];
|
|
52
|
+
combine?: (results: (Tanstack.UseQueryResult<unknown, unknown> & {
|
|
53
|
+
queryKey: Tanstack.QueryKey;
|
|
54
|
+
})[]) => unknown;
|
|
55
|
+
};
|
|
56
|
+
export declare function useQueries<T extends readonly unknown[], TCombined>(options: UseQueriesExplicitWithCombineOptions<T, TCombined>, queryClient?: Tanstack.QueryClient): TCombined;
|
|
57
|
+
export declare function useQueries<T extends readonly unknown[]>(options: UseQueriesExplicitWithoutCombineOptions<T>, queryClient?: Tanstack.QueryClient): ExplicitQueryResults<T>;
|
|
58
|
+
export declare function useQueries<TQueries extends readonly PowerSyncQueryOption[], TCombined>(options: UseQueriesAutoInferenceWithCombineOptions<TQueries, TCombined>, queryClient?: Tanstack.QueryClient): TCombined;
|
|
59
|
+
export declare function useQueries<TQueries extends readonly PowerSyncQueryOption[]>(options: UseQueriesAutoInferenceWithoutCombineOptions<TQueries>, queryClient?: Tanstack.QueryClient): InferQueryResults<TQueries>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { usePowerSync } from '@powersync/react';
|
|
2
|
+
import * as Tanstack from '@tanstack/react-query';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { usePowerSyncQueries } from './usePowerSyncQueries.js';
|
|
5
|
+
/**
|
|
6
|
+
* @example
|
|
7
|
+
* ```
|
|
8
|
+
* const { data, error, isLoading } = useQueries({
|
|
9
|
+
* queries: [
|
|
10
|
+
* { queryKey: ['lists'], query: 'SELECT * from lists' },
|
|
11
|
+
* { queryKey: ['todos'], query: 'SELECT * from todos' }
|
|
12
|
+
* ],
|
|
13
|
+
* })
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```
|
|
18
|
+
* const ids = [1, 2, 3];
|
|
19
|
+
* const combinedQueries = useQueries({
|
|
20
|
+
* queries: ids.map((id) => ({
|
|
21
|
+
* queryKey: ['post', id],
|
|
22
|
+
* query: 'SELECT * from lists where id = ?',
|
|
23
|
+
* parameters: [id],
|
|
24
|
+
* })),
|
|
25
|
+
* combine: (results) => {
|
|
26
|
+
* return {
|
|
27
|
+
* data: results.map((result) => result.data),
|
|
28
|
+
* pending: results.some((result) => result.isPending),
|
|
29
|
+
* }
|
|
30
|
+
* },
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export function useQueries(options, queryClient = Tanstack.useQueryClient()) {
|
|
35
|
+
const powerSync = usePowerSync();
|
|
36
|
+
if (!powerSync) {
|
|
37
|
+
throw new Error('PowerSync is not available');
|
|
38
|
+
}
|
|
39
|
+
const queriesInput = options.queries;
|
|
40
|
+
const powerSyncQueriesInput = useMemo(() => queriesInput.map((queryOptions) => ({
|
|
41
|
+
query: queryOptions.query,
|
|
42
|
+
parameters: queryOptions.parameters,
|
|
43
|
+
queryKey: queryOptions.queryKey
|
|
44
|
+
})), [queriesInput]);
|
|
45
|
+
const states = usePowerSyncQueries(powerSyncQueriesInput, queryClient);
|
|
46
|
+
const queries = useMemo(() => {
|
|
47
|
+
return queriesInput.map((queryOptions, idx) => {
|
|
48
|
+
const { query, parameters, ...rest } = queryOptions;
|
|
49
|
+
const state = states[idx];
|
|
50
|
+
return {
|
|
51
|
+
...rest,
|
|
52
|
+
queryFn: query ? state.queryFn : rest.queryFn,
|
|
53
|
+
queryKey: rest.queryKey
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
}, [queriesInput, states]);
|
|
57
|
+
return Tanstack.useQueries({
|
|
58
|
+
queries: queries,
|
|
59
|
+
combine: options.combine
|
|
60
|
+
? (results) => {
|
|
61
|
+
const enhancedResultsWithQueryKey = results.map((result, index) => ({
|
|
62
|
+
...result,
|
|
63
|
+
queryKey: queries[index].queryKey
|
|
64
|
+
}));
|
|
65
|
+
return options.combine?.(enhancedResultsWithQueryKey);
|
|
66
|
+
}
|
|
67
|
+
: undefined
|
|
68
|
+
}, queryClient);
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=useQueries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useQueries.js","sourceRoot":"","sources":["../../src/hooks/useQueries.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,QAAQ,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AA8E/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,UAAU,CACxB,OAA8B,EAC9B,cAAoC,QAAQ,CAAC,cAAc,EAAE;IAE7D,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IAEjC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;IAErC,MAAM,qBAAqB,GAAG,OAAO,CACnC,GAAG,EAAE,CACH,YAAY,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QAClC,KAAK,EAAE,YAAY,CAAC,KAAK;QACzB,UAAU,EAAE,YAAY,CAAC,UAAU;QACnC,QAAQ,EAAE,YAAY,CAAC,QAAQ;KAChC,CAAC,CAAC,EACL,CAAC,YAAY,CAAC,CACf,CAAC;IAEF,MAAM,MAAM,GAAG,mBAAmB,CAAC,qBAAqB,EAAE,WAAW,CAAC,CAAC;IAEvE,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE;QAC3B,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,GAAG,EAAE,EAAE;YAC5C,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,YAAY,CAAC;YACpD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAE1B,OAAO;gBACL,GAAG,IAAI;gBACP,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO;gBAC7C,QAAQ,EAAE,IAAI,CAAC,QAAQ;aACxB,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IAE3B,OAAO,QAAQ,CAAC,UAAU,CACxB;QACE,OAAO,EAAE,OAAuC;QAChD,OAAO,EAAE,OAAO,CAAC,OAAO;YACtB,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE;gBACV,MAAM,2BAA2B,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;oBAClE,GAAG,MAAM;oBACT,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ;iBAClC,CAAC,CAAC,CAAC;gBAEJ,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC,2BAA2B,CAAC,CAAC;YACxD,CAAC;YACH,CAAC,CAAC,SAAS;KACd,EACD,WAAW,CACZ,CAAC;AACJ,CAAC"}
|
package/lib/hooks/useQuery.d.ts
CHANGED
|
@@ -5,15 +5,73 @@ export type PowerSyncQueryOptions<T> = {
|
|
|
5
5
|
parameters?: any[];
|
|
6
6
|
};
|
|
7
7
|
export type UseBaseQueryOptions<TQueryOptions> = TQueryOptions & PowerSyncQueryOptions<any>;
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* Uses the `queryFn` to execute the query. No different from the base `useQuery` hook.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```
|
|
14
|
+
* const { data, error, isLoading } = useQuery({
|
|
15
|
+
* queryKey: ['lists'],
|
|
16
|
+
* queryFn: getTodos,
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
8
20
|
export declare function useQuery<TData = unknown, TError = Tanstack.DefaultError>(options: UseBaseQueryOptions<Tanstack.UseQueryOptions<TData, TError>> & {
|
|
9
21
|
query?: undefined;
|
|
10
22
|
}, queryClient?: Tanstack.QueryClient): Tanstack.UseQueryResult<TData, TError>;
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* Uses the `query` to execute the PowerSync query.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```
|
|
29
|
+
* const { data, error, isLoading } = useQuery({
|
|
30
|
+
* queryKey: ['lists'],
|
|
31
|
+
* query: 'SELECT * from lists where id = ?',
|
|
32
|
+
* parameters: ['id-1']
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```
|
|
38
|
+
* const { data, error, isLoading } = useQuery({
|
|
39
|
+
* queryKey: ['lists'],
|
|
40
|
+
* query: compilableQuery,
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
11
44
|
export declare function useQuery<TData = unknown, TError = Tanstack.DefaultError>(options: UseBaseQueryOptions<Tanstack.UseQueryOptions<TData[], TError>> & {
|
|
12
45
|
query: string | CompilableQuery<TData>;
|
|
13
46
|
}, queryClient?: Tanstack.QueryClient): Tanstack.UseQueryResult<TData[], TError>;
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
* Uses the `queryFn` to execute the query. No different from the base `useSuspenseQuery` hook.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```
|
|
53
|
+
* const { data } = useSuspenseQuery({
|
|
54
|
+
* queryKey: ['lists'],
|
|
55
|
+
* queryFn: getTodos,
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
14
59
|
export declare function useSuspenseQuery<TData = unknown, TError = Tanstack.DefaultError>(options: UseBaseQueryOptions<Tanstack.UseSuspenseQueryOptions<TData, TError>> & {
|
|
15
60
|
query?: undefined;
|
|
16
61
|
}, queryClient?: Tanstack.QueryClient): Tanstack.UseSuspenseQueryResult<TData, TError>;
|
|
62
|
+
/***
|
|
63
|
+
*
|
|
64
|
+
* Uses the `query` to execute the PowerSync query.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```
|
|
68
|
+
* const { data } = useSuspenseQuery({
|
|
69
|
+
* queryKey: ['lists'],
|
|
70
|
+
* query: 'SELECT * from lists where id = ?',
|
|
71
|
+
* parameters: ['id-1']
|
|
72
|
+
* });
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
17
75
|
export declare function useSuspenseQuery<TData = unknown, TError = Tanstack.DefaultError>(options: UseBaseQueryOptions<Tanstack.UseSuspenseQueryOptions<TData[], TError>> & {
|
|
18
76
|
query: string | CompilableQuery<TData>;
|
|
19
77
|
}, queryClient?: Tanstack.QueryClient): Tanstack.UseSuspenseQueryResult<TData[], TError>;
|
package/lib/hooks/useQuery.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { parseQuery } from '@powersync/common';
|
|
2
1
|
import { usePowerSync } from '@powersync/react';
|
|
3
|
-
import React from 'react';
|
|
4
2
|
import * as Tanstack from '@tanstack/react-query';
|
|
3
|
+
import { usePowerSyncQueries } from './usePowerSyncQueries.js';
|
|
5
4
|
export function useQuery(options, queryClient = Tanstack.useQueryClient()) {
|
|
6
5
|
return useQueryCore(options, queryClient, Tanstack.useQuery);
|
|
7
6
|
}
|
|
@@ -13,78 +12,17 @@ function useQueryCore(options, queryClient, useQueryFn) {
|
|
|
13
12
|
if (!powerSync) {
|
|
14
13
|
throw new Error('PowerSync is not available');
|
|
15
14
|
}
|
|
16
|
-
|
|
17
|
-
const [
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
const parsedQuery = parseQuery(query, parameters);
|
|
24
|
-
sqlStatement = parsedQuery.sqlStatement;
|
|
25
|
-
queryParameters = parsedQuery.parameters;
|
|
15
|
+
const { query, parameters, queryKey, ...resolvedOptions } = options;
|
|
16
|
+
const [{ queryFn }] = usePowerSyncQueries([
|
|
17
|
+
{
|
|
18
|
+
query,
|
|
19
|
+
parameters,
|
|
20
|
+
queryKey
|
|
26
21
|
}
|
|
27
|
-
|
|
28
|
-
error = e;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
const stringifiedParams = JSON.stringify(queryParameters);
|
|
32
|
-
const stringifiedKey = JSON.stringify(options.queryKey);
|
|
33
|
-
const fetchTables = async () => {
|
|
34
|
-
try {
|
|
35
|
-
const tables = await powerSync.resolveTables(sqlStatement, queryParameters);
|
|
36
|
-
setTables(tables);
|
|
37
|
-
}
|
|
38
|
-
catch (e) {
|
|
39
|
-
error = e;
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
React.useEffect(() => {
|
|
43
|
-
if (error || !query)
|
|
44
|
-
return () => { };
|
|
45
|
-
(async () => {
|
|
46
|
-
await fetchTables();
|
|
47
|
-
})();
|
|
48
|
-
const l = powerSync.registerListener({
|
|
49
|
-
schemaChanged: async () => {
|
|
50
|
-
await fetchTables();
|
|
51
|
-
queryClient.invalidateQueries({ queryKey: options.queryKey });
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
return () => l?.();
|
|
55
|
-
}, [powerSync, sqlStatement, stringifiedParams]);
|
|
56
|
-
const queryFn = React.useCallback(async () => {
|
|
57
|
-
if (error) {
|
|
58
|
-
return Promise.reject(error);
|
|
59
|
-
}
|
|
60
|
-
try {
|
|
61
|
-
return typeof query == 'string' ? powerSync.getAll(sqlStatement, queryParameters) : query.execute();
|
|
62
|
-
}
|
|
63
|
-
catch (e) {
|
|
64
|
-
return Promise.reject(e);
|
|
65
|
-
}
|
|
66
|
-
}, [powerSync, query, parameters, stringifiedKey]);
|
|
67
|
-
React.useEffect(() => {
|
|
68
|
-
if (error || !query)
|
|
69
|
-
return () => { };
|
|
70
|
-
const abort = new AbortController();
|
|
71
|
-
powerSync.onChangeWithCallback({
|
|
72
|
-
onChange: () => {
|
|
73
|
-
queryClient.invalidateQueries({
|
|
74
|
-
queryKey: options.queryKey
|
|
75
|
-
});
|
|
76
|
-
},
|
|
77
|
-
onError: (e) => {
|
|
78
|
-
error = e;
|
|
79
|
-
}
|
|
80
|
-
}, {
|
|
81
|
-
tables,
|
|
82
|
-
signal: abort.signal
|
|
83
|
-
});
|
|
84
|
-
return () => abort.abort();
|
|
85
|
-
}, [powerSync, queryClient, stringifiedKey, tables]);
|
|
22
|
+
], queryClient);
|
|
86
23
|
return useQueryFn({
|
|
87
24
|
...resolvedOptions,
|
|
25
|
+
queryKey,
|
|
88
26
|
queryFn: query ? queryFn : resolvedOptions.queryFn
|
|
89
27
|
}, queryClient);
|
|
90
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useQuery.js","sourceRoot":"","sources":["../../src/hooks/useQuery.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useQuery.js","sourceRoot":"","sources":["../../src/hooks/useQuery.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,QAAQ,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAoD/D,MAAM,UAAU,QAAQ,CACtB,OAAqE,EACrE,cAAoC,QAAQ,CAAC,cAAc,EAAE;IAE7D,OAAO,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC/D,CAAC;AAuCD,MAAM,UAAU,gBAAgB,CAC9B,OAA6E,EAC7E,cAAoC,QAAQ,CAAC,cAAc,EAAE;IAE7D,OAAO,YAAY,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,YAAY,CAMnB,OAA2C,EAC3C,WAAiC,EACjC,UAAwF;IAExF,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IAEjC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE,GAAG,OAAO,CAAC;IAEpE,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,mBAAmB,CACvC;QACE;YACE,KAAK;YACL,UAAU;YACV,QAAQ;SACT;KACF,EACD,WAAW,CACZ,CAAC;IAEF,OAAO,UAAU,CACf;QACE,GAAI,eAAiC;QACrC,QAAQ;QACR,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO;KAClC,EAClB,WAAW,CACZ,CAAC;AACJ,CAAC"}
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powersync/tanstack-react-query",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/",
|
|
6
6
|
"access": "public"
|
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
},
|
|
25
25
|
"homepage": "https://docs.powersync.com",
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"@powersync/common": "^1.
|
|
27
|
+
"@powersync/common": "^1.43.1",
|
|
28
28
|
"react": "*"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@tanstack/react-query": "^5.70.0",
|
|
32
|
-
"@powersync/common": "1.
|
|
32
|
+
"@powersync/common": "1.43.1",
|
|
33
33
|
"@powersync/react": "1.8.2"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { type CompilableQuery, parseQuery } from '@powersync/common';
|
|
2
|
+
import { usePowerSync } from '@powersync/react';
|
|
3
|
+
import { useEffect, useState, useCallback, useMemo } from 'react';
|
|
4
|
+
import * as Tanstack from '@tanstack/react-query';
|
|
5
|
+
|
|
6
|
+
export type UsePowerSyncQueriesInput = {
|
|
7
|
+
query?: string | CompilableQuery<unknown>;
|
|
8
|
+
parameters?: unknown[];
|
|
9
|
+
queryKey: Tanstack.QueryKey;
|
|
10
|
+
}[];
|
|
11
|
+
|
|
12
|
+
export type UsePowerSyncQueriesOutput = {
|
|
13
|
+
sqlStatement: string;
|
|
14
|
+
queryParameters: unknown[];
|
|
15
|
+
tables: string[];
|
|
16
|
+
error?: Error;
|
|
17
|
+
queryFn: () => Promise<unknown[]>;
|
|
18
|
+
}[];
|
|
19
|
+
|
|
20
|
+
export function usePowerSyncQueries(
|
|
21
|
+
queries: UsePowerSyncQueriesInput,
|
|
22
|
+
queryClient: Tanstack.QueryClient
|
|
23
|
+
): UsePowerSyncQueriesOutput {
|
|
24
|
+
const powerSync = usePowerSync();
|
|
25
|
+
|
|
26
|
+
const [tablesArr, setTablesArr] = useState<string[][]>(() => queries.map(() => []));
|
|
27
|
+
const [errorsArr, setErrorsArr] = useState<(Error | undefined)[]>(() => queries.map(() => undefined));
|
|
28
|
+
|
|
29
|
+
const updateTablesArr = useCallback((tables: string[], idx: number) => {
|
|
30
|
+
setTablesArr((prev) => {
|
|
31
|
+
if (JSON.stringify(prev[idx]) === JSON.stringify(tables)) return prev;
|
|
32
|
+
const next = [...prev];
|
|
33
|
+
next[idx] = tables;
|
|
34
|
+
return next;
|
|
35
|
+
});
|
|
36
|
+
}, []);
|
|
37
|
+
|
|
38
|
+
const updateErrorsArr = useCallback((error: Error | undefined, idx: number) => {
|
|
39
|
+
setErrorsArr((prev) => {
|
|
40
|
+
if (prev[idx]?.message === error?.message) return prev;
|
|
41
|
+
const next = [...prev];
|
|
42
|
+
next[idx] = error;
|
|
43
|
+
return next;
|
|
44
|
+
});
|
|
45
|
+
}, []);
|
|
46
|
+
|
|
47
|
+
const parsedQueries = useMemo(
|
|
48
|
+
() =>
|
|
49
|
+
queries.map((queryInput) => {
|
|
50
|
+
const { query, parameters = [], queryKey } = queryInput;
|
|
51
|
+
|
|
52
|
+
if (!query) {
|
|
53
|
+
return {
|
|
54
|
+
query,
|
|
55
|
+
parameters,
|
|
56
|
+
queryKey,
|
|
57
|
+
sqlStatement: '',
|
|
58
|
+
queryParameters: [],
|
|
59
|
+
parseError: undefined
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const parsed = parseQuery(query, parameters);
|
|
65
|
+
return {
|
|
66
|
+
query,
|
|
67
|
+
parameters,
|
|
68
|
+
queryKey,
|
|
69
|
+
sqlStatement: parsed.sqlStatement,
|
|
70
|
+
queryParameters: parsed.parameters,
|
|
71
|
+
parseError: undefined
|
|
72
|
+
};
|
|
73
|
+
} catch (e) {
|
|
74
|
+
return {
|
|
75
|
+
query,
|
|
76
|
+
parameters,
|
|
77
|
+
queryKey,
|
|
78
|
+
sqlStatement: '',
|
|
79
|
+
queryParameters: [],
|
|
80
|
+
parseError: e as Error
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}),
|
|
84
|
+
[queries]
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
parsedQueries.forEach((pq, idx) => {
|
|
89
|
+
if (pq.parseError) {
|
|
90
|
+
updateErrorsArr(pq.parseError, idx);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}, [parsedQueries, updateErrorsArr]);
|
|
94
|
+
|
|
95
|
+
const stringifiedQueriesDeps = JSON.stringify(
|
|
96
|
+
parsedQueries.map((q) => ({
|
|
97
|
+
sql: q.sqlStatement,
|
|
98
|
+
params: q.queryParameters
|
|
99
|
+
}))
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
const listeners = parsedQueries.map((pq, idx) => {
|
|
104
|
+
if (pq.parseError || !pq.query) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
(async () => {
|
|
109
|
+
try {
|
|
110
|
+
const tables = await powerSync.resolveTables(pq.sqlStatement, pq.queryParameters);
|
|
111
|
+
updateTablesArr(tables, idx);
|
|
112
|
+
} catch (e) {
|
|
113
|
+
updateErrorsArr(e as Error, idx);
|
|
114
|
+
}
|
|
115
|
+
})();
|
|
116
|
+
|
|
117
|
+
return powerSync.registerListener({
|
|
118
|
+
schemaChanged: async () => {
|
|
119
|
+
try {
|
|
120
|
+
const tables = await powerSync.resolveTables(pq.sqlStatement, pq.queryParameters);
|
|
121
|
+
updateTablesArr(tables, idx);
|
|
122
|
+
queryClient.invalidateQueries({ queryKey: pq.queryKey });
|
|
123
|
+
} catch (e) {
|
|
124
|
+
updateErrorsArr(e as Error, idx);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return () => {
|
|
131
|
+
listeners.forEach((l) => l?.());
|
|
132
|
+
};
|
|
133
|
+
}, [powerSync, queryClient, stringifiedQueriesDeps, updateTablesArr, updateErrorsArr]);
|
|
134
|
+
|
|
135
|
+
const stringifiedQueryKeys = JSON.stringify(parsedQueries.map((q) => q.queryKey));
|
|
136
|
+
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
const aborts = parsedQueries.map((pq, idx) => {
|
|
139
|
+
if (pq.parseError || !pq.query) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const abort = new AbortController();
|
|
144
|
+
|
|
145
|
+
powerSync.onChangeWithCallback(
|
|
146
|
+
{
|
|
147
|
+
onChange: () => {
|
|
148
|
+
queryClient.invalidateQueries({ queryKey: pq.queryKey });
|
|
149
|
+
},
|
|
150
|
+
onError: (e) => {
|
|
151
|
+
updateErrorsArr(e, idx);
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
tables: tablesArr[idx],
|
|
156
|
+
signal: abort.signal
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
return abort;
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
return () => aborts.forEach((a) => a?.abort());
|
|
164
|
+
}, [powerSync, queryClient, tablesArr, updateErrorsArr, stringifiedQueryKeys]);
|
|
165
|
+
|
|
166
|
+
return useMemo(() => {
|
|
167
|
+
return parsedQueries.map((pq, idx) => {
|
|
168
|
+
const error = errorsArr[idx] || pq.parseError;
|
|
169
|
+
|
|
170
|
+
const queryFn = async () => {
|
|
171
|
+
if (error) throw error;
|
|
172
|
+
if (!pq.query) throw new Error('No query provided');
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
return typeof pq.query === 'string'
|
|
176
|
+
? await powerSync.getAll(pq.sqlStatement, pq.queryParameters)
|
|
177
|
+
: await pq.query.execute();
|
|
178
|
+
} catch (e) {
|
|
179
|
+
throw e;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
sqlStatement: pq.sqlStatement,
|
|
185
|
+
queryParameters: pq.queryParameters,
|
|
186
|
+
tables: tablesArr[idx],
|
|
187
|
+
error,
|
|
188
|
+
queryFn
|
|
189
|
+
};
|
|
190
|
+
});
|
|
191
|
+
}, [parsedQueries, errorsArr, tablesArr, powerSync]);
|
|
192
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { type CompilableQuery } from '@powersync/common';
|
|
2
|
+
import { usePowerSync } from '@powersync/react';
|
|
3
|
+
import * as Tanstack from '@tanstack/react-query';
|
|
4
|
+
import { useMemo } from 'react';
|
|
5
|
+
import { usePowerSyncQueries } from './usePowerSyncQueries.js';
|
|
6
|
+
|
|
7
|
+
export type PowerSyncQueryOptions<T> = {
|
|
8
|
+
query?: string | CompilableQuery<T>;
|
|
9
|
+
parameters?: any[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type PowerSyncQueryOption<T = unknown[]> = Tanstack.UseQueryOptions<T[]> & PowerSyncQueryOptions<T>;
|
|
13
|
+
|
|
14
|
+
export type InferQueryResults<TQueries extends readonly unknown[]> = {
|
|
15
|
+
[K in keyof TQueries]: TQueries[K] extends { query: CompilableQuery<infer TData> }
|
|
16
|
+
? Tanstack.UseQueryResult<TData[]>
|
|
17
|
+
: Tanstack.UseQueryResult<unknown[]>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type ExplicitQueryResults<T extends readonly unknown[]> = {
|
|
21
|
+
[K in keyof T]: Tanstack.UseQueryResult<T[K][]>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type EnhancedInferQueryResults<TQueries extends readonly unknown[]> = {
|
|
25
|
+
[K in keyof TQueries]: TQueries[K] extends { query: CompilableQuery<infer TData> }
|
|
26
|
+
? Tanstack.UseQueryResult<TData[]> & { queryKey: Tanstack.QueryKey }
|
|
27
|
+
: Tanstack.UseQueryResult<unknown[]> & { queryKey: Tanstack.QueryKey };
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type EnhancedExplicitQueryResults<T extends readonly unknown[]> = {
|
|
31
|
+
[K in keyof T]: Tanstack.UseQueryResult<T[K][]> & { queryKey: Tanstack.QueryKey };
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type UseQueriesExplicitWithCombineOptions<T extends readonly unknown[], TCombined> = {
|
|
35
|
+
queries: readonly [...{ [K in keyof T]: PowerSyncQueryOption<T[K]> }];
|
|
36
|
+
combine: (results: EnhancedExplicitQueryResults<T>) => TCombined;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type UseQueriesExplicitWithoutCombineOptions<T extends readonly unknown[]> = {
|
|
40
|
+
queries: readonly [...{ [K in keyof T]: PowerSyncQueryOption<T[K]> }];
|
|
41
|
+
combine?: undefined;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type UseQueriesAutoInferenceWithCombineOptions<TQueries extends readonly PowerSyncQueryOption[], TCombined> = {
|
|
45
|
+
queries: readonly [...TQueries];
|
|
46
|
+
combine: (results: EnhancedInferQueryResults<TQueries>) => TCombined;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type UseQueriesAutoInferenceWithoutCombineOptions<TQueries extends readonly PowerSyncQueryOption[]> = {
|
|
50
|
+
queries: readonly [...TQueries];
|
|
51
|
+
combine?: undefined;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type UseQueriesBaseOptions = {
|
|
55
|
+
queries: readonly (Tanstack.UseQueryOptions & PowerSyncQueryOptions<unknown>)[];
|
|
56
|
+
combine?: (results: (Tanstack.UseQueryResult<unknown, unknown> & { queryKey: Tanstack.QueryKey })[]) => unknown;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// Explicit generic typing with combine
|
|
60
|
+
export function useQueries<T extends readonly unknown[], TCombined>(
|
|
61
|
+
options: UseQueriesExplicitWithCombineOptions<T, TCombined>,
|
|
62
|
+
queryClient?: Tanstack.QueryClient
|
|
63
|
+
): TCombined;
|
|
64
|
+
|
|
65
|
+
// Explicit generic typing without combine
|
|
66
|
+
export function useQueries<T extends readonly unknown[]>(
|
|
67
|
+
options: UseQueriesExplicitWithoutCombineOptions<T>,
|
|
68
|
+
queryClient?: Tanstack.QueryClient
|
|
69
|
+
): ExplicitQueryResults<T>;
|
|
70
|
+
|
|
71
|
+
// Auto inference with combine
|
|
72
|
+
export function useQueries<TQueries extends readonly PowerSyncQueryOption[], TCombined>(
|
|
73
|
+
options: UseQueriesAutoInferenceWithCombineOptions<TQueries, TCombined>,
|
|
74
|
+
queryClient?: Tanstack.QueryClient
|
|
75
|
+
): TCombined;
|
|
76
|
+
|
|
77
|
+
// Auto inference without combine
|
|
78
|
+
export function useQueries<TQueries extends readonly PowerSyncQueryOption[]>(
|
|
79
|
+
options: UseQueriesAutoInferenceWithoutCombineOptions<TQueries>,
|
|
80
|
+
queryClient?: Tanstack.QueryClient
|
|
81
|
+
): InferQueryResults<TQueries>;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @example
|
|
85
|
+
* ```
|
|
86
|
+
* const { data, error, isLoading } = useQueries({
|
|
87
|
+
* queries: [
|
|
88
|
+
* { queryKey: ['lists'], query: 'SELECT * from lists' },
|
|
89
|
+
* { queryKey: ['todos'], query: 'SELECT * from todos' }
|
|
90
|
+
* ],
|
|
91
|
+
* })
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```
|
|
96
|
+
* const ids = [1, 2, 3];
|
|
97
|
+
* const combinedQueries = useQueries({
|
|
98
|
+
* queries: ids.map((id) => ({
|
|
99
|
+
* queryKey: ['post', id],
|
|
100
|
+
* query: 'SELECT * from lists where id = ?',
|
|
101
|
+
* parameters: [id],
|
|
102
|
+
* })),
|
|
103
|
+
* combine: (results) => {
|
|
104
|
+
* return {
|
|
105
|
+
* data: results.map((result) => result.data),
|
|
106
|
+
* pending: results.some((result) => result.isPending),
|
|
107
|
+
* }
|
|
108
|
+
* },
|
|
109
|
+
* });
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export function useQueries(
|
|
113
|
+
options: UseQueriesBaseOptions,
|
|
114
|
+
queryClient: Tanstack.QueryClient = Tanstack.useQueryClient()
|
|
115
|
+
) {
|
|
116
|
+
const powerSync = usePowerSync();
|
|
117
|
+
|
|
118
|
+
if (!powerSync) {
|
|
119
|
+
throw new Error('PowerSync is not available');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const queriesInput = options.queries;
|
|
123
|
+
|
|
124
|
+
const powerSyncQueriesInput = useMemo(
|
|
125
|
+
() =>
|
|
126
|
+
queriesInput.map((queryOptions) => ({
|
|
127
|
+
query: queryOptions.query,
|
|
128
|
+
parameters: queryOptions.parameters,
|
|
129
|
+
queryKey: queryOptions.queryKey
|
|
130
|
+
})),
|
|
131
|
+
[queriesInput]
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const states = usePowerSyncQueries(powerSyncQueriesInput, queryClient);
|
|
135
|
+
|
|
136
|
+
const queries = useMemo(() => {
|
|
137
|
+
return queriesInput.map((queryOptions, idx) => {
|
|
138
|
+
const { query, parameters, ...rest } = queryOptions;
|
|
139
|
+
const state = states[idx];
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
...rest,
|
|
143
|
+
queryFn: query ? state.queryFn : rest.queryFn,
|
|
144
|
+
queryKey: rest.queryKey
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
}, [queriesInput, states]);
|
|
148
|
+
|
|
149
|
+
return Tanstack.useQueries(
|
|
150
|
+
{
|
|
151
|
+
queries: queries as Tanstack.QueriesOptions<any>,
|
|
152
|
+
combine: options.combine
|
|
153
|
+
? (results) => {
|
|
154
|
+
const enhancedResultsWithQueryKey = results.map((result, index) => ({
|
|
155
|
+
...result,
|
|
156
|
+
queryKey: queries[index].queryKey
|
|
157
|
+
}));
|
|
158
|
+
|
|
159
|
+
return options.combine?.(enhancedResultsWithQueryKey);
|
|
160
|
+
}
|
|
161
|
+
: undefined
|
|
162
|
+
},
|
|
163
|
+
queryClient
|
|
164
|
+
);
|
|
165
|
+
}
|
package/src/hooks/useQuery.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type CompilableQuery } from '@powersync/common';
|
|
2
2
|
import { usePowerSync } from '@powersync/react';
|
|
3
|
-
import React from 'react';
|
|
4
|
-
|
|
5
3
|
import * as Tanstack from '@tanstack/react-query';
|
|
4
|
+
import { usePowerSyncQueries } from './usePowerSyncQueries.js';
|
|
6
5
|
|
|
7
6
|
export type PowerSyncQueryOptions<T> = {
|
|
8
7
|
query?: string | CompilableQuery<T>;
|
|
@@ -11,12 +10,44 @@ export type PowerSyncQueryOptions<T> = {
|
|
|
11
10
|
|
|
12
11
|
export type UseBaseQueryOptions<TQueryOptions> = TQueryOptions & PowerSyncQueryOptions<any>;
|
|
13
12
|
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
* Uses the `queryFn` to execute the query. No different from the base `useQuery` hook.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```
|
|
19
|
+
* const { data, error, isLoading } = useQuery({
|
|
20
|
+
* queryKey: ['lists'],
|
|
21
|
+
* queryFn: getTodos,
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
14
25
|
export function useQuery<TData = unknown, TError = Tanstack.DefaultError>(
|
|
15
26
|
options: UseBaseQueryOptions<Tanstack.UseQueryOptions<TData, TError>> & { query?: undefined },
|
|
16
27
|
queryClient?: Tanstack.QueryClient
|
|
17
28
|
): Tanstack.UseQueryResult<TData, TError>;
|
|
18
29
|
|
|
19
|
-
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
* Uses the `query` to execute the PowerSync query.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```
|
|
36
|
+
* const { data, error, isLoading } = useQuery({
|
|
37
|
+
* queryKey: ['lists'],
|
|
38
|
+
* query: 'SELECT * from lists where id = ?',
|
|
39
|
+
* parameters: ['id-1']
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```
|
|
45
|
+
* const { data, error, isLoading } = useQuery({
|
|
46
|
+
* queryKey: ['lists'],
|
|
47
|
+
* query: compilableQuery,
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
20
51
|
export function useQuery<TData = unknown, TError = Tanstack.DefaultError>(
|
|
21
52
|
options: UseBaseQueryOptions<Tanstack.UseQueryOptions<TData[], TError>> & { query: string | CompilableQuery<TData> },
|
|
22
53
|
queryClient?: Tanstack.QueryClient
|
|
@@ -29,12 +60,36 @@ export function useQuery<TData = unknown, TError = Tanstack.DefaultError>(
|
|
|
29
60
|
return useQueryCore(options, queryClient, Tanstack.useQuery);
|
|
30
61
|
}
|
|
31
62
|
|
|
63
|
+
/**
|
|
64
|
+
*
|
|
65
|
+
* Uses the `queryFn` to execute the query. No different from the base `useSuspenseQuery` hook.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```
|
|
69
|
+
* const { data } = useSuspenseQuery({
|
|
70
|
+
* queryKey: ['lists'],
|
|
71
|
+
* queryFn: getTodos,
|
|
72
|
+
* });
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
32
75
|
export function useSuspenseQuery<TData = unknown, TError = Tanstack.DefaultError>(
|
|
33
76
|
options: UseBaseQueryOptions<Tanstack.UseSuspenseQueryOptions<TData, TError>> & { query?: undefined },
|
|
34
77
|
queryClient?: Tanstack.QueryClient
|
|
35
78
|
): Tanstack.UseSuspenseQueryResult<TData, TError>;
|
|
36
79
|
|
|
37
|
-
|
|
80
|
+
/***
|
|
81
|
+
*
|
|
82
|
+
* Uses the `query` to execute the PowerSync query.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```
|
|
86
|
+
* const { data } = useSuspenseQuery({
|
|
87
|
+
* queryKey: ['lists'],
|
|
88
|
+
* query: 'SELECT * from lists where id = ?',
|
|
89
|
+
* parameters: ['id-1']
|
|
90
|
+
* });
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
38
93
|
export function useSuspenseQuery<TData = unknown, TError = Tanstack.DefaultError>(
|
|
39
94
|
options: UseBaseQueryOptions<Tanstack.UseSuspenseQueryOptions<TData[], TError>> & {
|
|
40
95
|
query: string | CompilableQuery<TData>;
|
|
@@ -65,92 +120,23 @@ function useQueryCore<
|
|
|
65
120
|
throw new Error('PowerSync is not available');
|
|
66
121
|
}
|
|
67
122
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const [tables, setTables] = React.useState<string[]>([]);
|
|
71
|
-
const { query, parameters = [], ...resolvedOptions } = options;
|
|
72
|
-
|
|
73
|
-
let sqlStatement = '';
|
|
74
|
-
let queryParameters = [];
|
|
75
|
-
|
|
76
|
-
if (query) {
|
|
77
|
-
try {
|
|
78
|
-
const parsedQuery = parseQuery(query, parameters);
|
|
79
|
-
|
|
80
|
-
sqlStatement = parsedQuery.sqlStatement;
|
|
81
|
-
queryParameters = parsedQuery.parameters;
|
|
82
|
-
} catch (e) {
|
|
83
|
-
error = e;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const stringifiedParams = JSON.stringify(queryParameters);
|
|
88
|
-
const stringifiedKey = JSON.stringify(options.queryKey);
|
|
89
|
-
|
|
90
|
-
const fetchTables = async () => {
|
|
91
|
-
try {
|
|
92
|
-
const tables = await powerSync.resolveTables(sqlStatement, queryParameters);
|
|
93
|
-
setTables(tables);
|
|
94
|
-
} catch (e) {
|
|
95
|
-
error = e;
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
React.useEffect(() => {
|
|
100
|
-
if (error || !query) return () => {};
|
|
101
|
-
|
|
102
|
-
(async () => {
|
|
103
|
-
await fetchTables();
|
|
104
|
-
})();
|
|
123
|
+
const { query, parameters, queryKey, ...resolvedOptions } = options;
|
|
105
124
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
await fetchTables();
|
|
109
|
-
queryClient.invalidateQueries({ queryKey: options.queryKey });
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
return () => l?.();
|
|
114
|
-
}, [powerSync, sqlStatement, stringifiedParams]);
|
|
115
|
-
|
|
116
|
-
const queryFn = React.useCallback(async () => {
|
|
117
|
-
if (error) {
|
|
118
|
-
return Promise.reject(error);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
return typeof query == 'string' ? powerSync.getAll<TData>(sqlStatement, queryParameters) : query.execute();
|
|
123
|
-
} catch (e) {
|
|
124
|
-
return Promise.reject(e);
|
|
125
|
-
}
|
|
126
|
-
}, [powerSync, query, parameters, stringifiedKey]);
|
|
127
|
-
|
|
128
|
-
React.useEffect(() => {
|
|
129
|
-
if (error || !query) return () => {};
|
|
130
|
-
|
|
131
|
-
const abort = new AbortController();
|
|
132
|
-
powerSync.onChangeWithCallback(
|
|
133
|
-
{
|
|
134
|
-
onChange: () => {
|
|
135
|
-
queryClient.invalidateQueries({
|
|
136
|
-
queryKey: options.queryKey
|
|
137
|
-
});
|
|
138
|
-
},
|
|
139
|
-
onError: (e) => {
|
|
140
|
-
error = e;
|
|
141
|
-
}
|
|
142
|
-
},
|
|
125
|
+
const [{ queryFn }] = usePowerSyncQueries(
|
|
126
|
+
[
|
|
143
127
|
{
|
|
144
|
-
|
|
145
|
-
|
|
128
|
+
query,
|
|
129
|
+
parameters,
|
|
130
|
+
queryKey
|
|
146
131
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
132
|
+
],
|
|
133
|
+
queryClient
|
|
134
|
+
);
|
|
150
135
|
|
|
151
136
|
return useQueryFn(
|
|
152
137
|
{
|
|
153
138
|
...(resolvedOptions as TQueryOptions),
|
|
139
|
+
queryKey,
|
|
154
140
|
queryFn: query ? queryFn : resolvedOptions.queryFn
|
|
155
141
|
} as TQueryOptions,
|
|
156
142
|
queryClient
|
package/src/index.ts
CHANGED