@tatsuokaniwa/swr-firestore 1.0.0 → 1.1.0
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 +57 -20
- package/dist/hooks/useCollection.d.ts +1 -1
- package/dist/hooks/useCollectionCount.d.ts +2 -2
- package/dist/hooks/useCollectionGroupCount.d.ts +2 -2
- package/dist/hooks/useDoc.d.ts +2 -2
- package/dist/hooks/useGetDoc.d.ts +1 -1
- package/dist/hooks/useGetDocs.d.ts +1 -1
- package/dist/index.js +83 -38
- package/dist/index.umd.cjs +83 -38
- package/dist/util/type.d.ts +11 -4
- package/dist/util/typeGuard.d.ts +5 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/js/@tatsuokaniwa%2Fswr-firestore)
|
|
4
4
|
[](https://github.com/t-k/swr-firestore/actions/workflows/test.yaml)
|
|
5
|
+
[](https://codecov.io/gh/t-k/swr-firestore)
|
|
5
6
|
|
|
6
7
|
React Hooks library for Firestore, built using the Firebase v9 modular SDK. It utilizes the [`useSWRSubscription`](https://swr.vercel.app/ja/docs/subscription) function from SWR library to enable subscription-based data fetching and caching.
|
|
7
8
|
|
|
@@ -39,7 +40,7 @@ export default function App() {
|
|
|
39
40
|
const { data } = useCollection<Post>(
|
|
40
41
|
isLogin
|
|
41
42
|
? {
|
|
42
|
-
path: "
|
|
43
|
+
path: "posts",
|
|
43
44
|
where: [["status", "==", "published"]],
|
|
44
45
|
orderBy: [["createdAt", "desc"]],
|
|
45
46
|
parseDates: ["createdAt"],
|
|
@@ -47,7 +48,7 @@ export default function App() {
|
|
|
47
48
|
: null
|
|
48
49
|
);
|
|
49
50
|
const { data: postCount } = useCollectionCount<Post>({
|
|
50
|
-
path: "
|
|
51
|
+
path: "posts",
|
|
51
52
|
where: [["status", "==", "published"]],
|
|
52
53
|
});
|
|
53
54
|
return (
|
|
@@ -64,6 +65,29 @@ export default function App() {
|
|
|
64
65
|
}
|
|
65
66
|
```
|
|
66
67
|
|
|
68
|
+
### For more complex queries
|
|
69
|
+
To perform complex queries like using `OR` queries or raw `QueryConstraint`, use the `queryConstraints` parameter.
|
|
70
|
+
However, this method does not provide input completion for field names from type definitions.
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import {
|
|
74
|
+
or,
|
|
75
|
+
orderBy,
|
|
76
|
+
where,
|
|
77
|
+
} from "firebase/firestore";
|
|
78
|
+
|
|
79
|
+
useCollection<City>({
|
|
80
|
+
path: "cities",
|
|
81
|
+
queryConstraints: [
|
|
82
|
+
or(
|
|
83
|
+
where('capital', '==', true),
|
|
84
|
+
where('population', '>=', 1000000)
|
|
85
|
+
),
|
|
86
|
+
orderBy("createdAt", "desc"),
|
|
87
|
+
],
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
67
91
|
## API
|
|
68
92
|
|
|
69
93
|
```ts
|
|
@@ -74,7 +98,7 @@ import {
|
|
|
74
98
|
useCollectionGroupCount, // Wrapper for getCountFromServer for collectionGroup
|
|
75
99
|
useDoc, // Subscription for document
|
|
76
100
|
useGetDocs, // Fetch documents with firestore's getDocs
|
|
77
|
-
useGetDoc, // Fetch
|
|
101
|
+
useGetDoc, // Fetch document with firestore's getDoc
|
|
78
102
|
} from "@tatsuokaniwa/swr-firestore";
|
|
79
103
|
```
|
|
80
104
|
|
|
@@ -83,16 +107,29 @@ import {
|
|
|
83
107
|
```ts
|
|
84
108
|
import type { orderBy, where } from "firebase/firestore";
|
|
85
109
|
// First argument of hook, specifies options to firestore, and is also used as a key for SWR.
|
|
86
|
-
type KeyParams<T> =
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
110
|
+
type KeyParams<T> =
|
|
111
|
+
| {
|
|
112
|
+
// The path to the collection or document of Firestore.
|
|
113
|
+
path: string
|
|
114
|
+
// `Paths` means object's property path, including nested object
|
|
115
|
+
where?: [Paths<T>, Parameters<typeof where>[1], ValueOf<T> | unknown][]
|
|
116
|
+
orderBy?: [Paths<T>, Parameters<typeof orderBy>[1]][]
|
|
117
|
+
limit?: number
|
|
118
|
+
// Array of field names that should be parsed as dates.
|
|
119
|
+
parseDates?: Paths<T>[]
|
|
120
|
+
}
|
|
121
|
+
// OR for more complex query
|
|
122
|
+
| {
|
|
123
|
+
// The path to the collection or document of Firestore.
|
|
124
|
+
path: string
|
|
125
|
+
// raw query constraints from `firebase/firestore`
|
|
126
|
+
queryConstraints?:
|
|
127
|
+
| [QueryCompositeFilterConstraint, ...Array<QueryNonFilterConstraint>]
|
|
128
|
+
| QueryConstraint[]
|
|
129
|
+
// Array of field names that should be parsed as dates.
|
|
130
|
+
parseDates?: Paths<T>[]
|
|
131
|
+
}
|
|
132
|
+
|
|
96
133
|
```
|
|
97
134
|
|
|
98
135
|
### Type definitions for return data
|
|
@@ -114,7 +151,7 @@ Subscription for collection
|
|
|
114
151
|
#### Return values
|
|
115
152
|
|
|
116
153
|
- `data`: data for given path's collection
|
|
117
|
-
- `error`: FirestoreError
|
|
154
|
+
- `error`: FirestoreError
|
|
118
155
|
|
|
119
156
|
```ts
|
|
120
157
|
import { useCollection } from "@tatsuokaniwa/swr-firestore";
|
|
@@ -138,7 +175,7 @@ Wrapper for getCountFromServer for collection
|
|
|
138
175
|
Returns [`SWRResponse`](https://swr.vercel.app/docs/api#return-values)
|
|
139
176
|
|
|
140
177
|
- `data`: number for given path's collection count result
|
|
141
|
-
- `error`: FirestoreError
|
|
178
|
+
- `error`: FirestoreError
|
|
142
179
|
- `isLoading`: if there's an ongoing request and no "loaded data". Fallback data and previous data are not considered "loaded data"
|
|
143
180
|
- `isValidating`: if there's a request or revalidation loading
|
|
144
181
|
- `mutate(data?, options?)`: function to mutate the cached data (details)
|
|
@@ -166,7 +203,7 @@ Subscription for collectionGroup
|
|
|
166
203
|
#### Return values
|
|
167
204
|
|
|
168
205
|
- `data`: data for given path's collectionGroup
|
|
169
|
-
- `error`: FirestoreError
|
|
206
|
+
- `error`: FirestoreError
|
|
170
207
|
|
|
171
208
|
### `useCollectionGroupCount(params, swrOptions)`
|
|
172
209
|
|
|
@@ -182,7 +219,7 @@ Wrapper for getCountFromServer for collectionGroup
|
|
|
182
219
|
Returns [`SWRResponse`](https://swr.vercel.app/docs/api#return-values)
|
|
183
220
|
|
|
184
221
|
- `data`: number for given path's collectionGroup count result
|
|
185
|
-
- `error`: FirestoreError
|
|
222
|
+
- `error`: FirestoreError
|
|
186
223
|
- `isLoading`: if there's an ongoing request and no "loaded data". Fallback data and previous data are not considered "loaded data"
|
|
187
224
|
- `isValidating`: if there's a request or revalidation loading
|
|
188
225
|
- `mutate(data?, options?)`: function to mutate the cached data (details)
|
|
@@ -198,7 +235,7 @@ Subscription for document
|
|
|
198
235
|
#### Return values
|
|
199
236
|
|
|
200
237
|
- `data`: data for given path's document
|
|
201
|
-
- `error`: FirestoreError
|
|
238
|
+
- `error`: FirestoreError
|
|
202
239
|
|
|
203
240
|
```ts
|
|
204
241
|
import { useDoc } from "@tatsuokaniwa/swr-firestore";
|
|
@@ -222,7 +259,7 @@ Fetch documents with firestore's [getDocs](https://firebase.google.com/docs/refe
|
|
|
222
259
|
Returns [`SWRResponse`](https://swr.vercel.app/docs/api#return-values)
|
|
223
260
|
|
|
224
261
|
- `data`: data for given path's collection
|
|
225
|
-
- `error`: FirestoreError
|
|
262
|
+
- `error`: FirestoreError
|
|
226
263
|
- `isLoading`: if there's an ongoing request and no "loaded data". Fallback data and previous data are not considered "loaded data"
|
|
227
264
|
- `isValidating`: if there's a request or revalidation loading
|
|
228
265
|
- `mutate(data?, options?)`: function to mutate the cached data (details)
|
|
@@ -249,7 +286,7 @@ Fetch the document with firestore's [getDoc](https://firebase.google.com/docs/re
|
|
|
249
286
|
Returns [`SWRResponse`](https://swr.vercel.app/docs/api#return-values)
|
|
250
287
|
|
|
251
288
|
- `data`: data for given path's document
|
|
252
|
-
- `error`: FirestoreError
|
|
289
|
+
- `error`: FirestoreError
|
|
253
290
|
- `isLoading`: if there's an ongoing request and no "loaded data". Fallback data and previous data are not considered "loaded data"
|
|
254
291
|
- `isValidating`: if there's a request or revalidation loading
|
|
255
292
|
- `mutate(data?, options?)`: function to mutate the cached data (details)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SWRSubscriptionResponse } from "swr/subscription";
|
|
2
2
|
import type { FirestoreError } from "firebase/firestore";
|
|
3
3
|
import type { DocumentData, KeyParams } from "../util/type";
|
|
4
|
-
declare const useCollection: <T>(params: KeyParams<T> | null) => SWRSubscriptionResponse<DocumentData<T>[], FirestoreError
|
|
4
|
+
declare const useCollection: <T>(params: KeyParams<T> | null) => SWRSubscriptionResponse<DocumentData<T>[], FirestoreError>;
|
|
5
5
|
export default useCollection;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { SWRHook } from "swr";
|
|
2
|
-
import type {
|
|
3
|
-
declare const useCollectionCount: <T>(params:
|
|
2
|
+
import type { KeyParamsForCount } from "../util/type";
|
|
3
|
+
declare const useCollectionCount: <T>(params: KeyParamsForCount<T> | null, swrOptions?: Omit<Parameters<SWRHook>[2], "fetcher">) => import("swr/_internal").SWRResponse<number | undefined, any, Omit<Partial<import("swr/_internal").PublicConfiguration<unknown, unknown, import("swr/_internal").BareFetcher<unknown>>> | undefined, "fetcher"> | undefined>;
|
|
4
4
|
export default useCollectionCount;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { SWRHook } from "swr";
|
|
2
|
-
import type {
|
|
3
|
-
declare const useCollectionGroupCount: <T>(params:
|
|
2
|
+
import type { KeyParamsForCount } from "../util/type";
|
|
3
|
+
declare const useCollectionGroupCount: <T>(params: KeyParamsForCount<T> | null, swrOptions?: Omit<Parameters<SWRHook>[2], "fetcher">) => import("swr/_internal").SWRResponse<number | undefined, any, Omit<Partial<import("swr/_internal").PublicConfiguration<unknown, unknown, import("swr/_internal").BareFetcher<unknown>>> | undefined, "fetcher"> | undefined>;
|
|
4
4
|
export default useCollectionGroupCount;
|
package/dist/hooks/useDoc.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { FirestoreError } from "firebase/firestore";
|
|
1
|
+
import type { FirestoreError } from "firebase/firestore";
|
|
2
2
|
import type { SWRSubscriptionResponse } from "swr/subscription";
|
|
3
3
|
import type { DocumentData, KeyParams } from "../util/type";
|
|
4
|
-
declare const useDoc: <T>(params: Omit<KeyParams<T>, "
|
|
4
|
+
declare const useDoc: <T>(params: Omit<KeyParams<T>, "orderBy" | "where" | "limit"> | null) => SWRSubscriptionResponse<DocumentData<T>, FirestoreError>;
|
|
5
5
|
export default useDoc;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { SWRHook } from "swr";
|
|
2
2
|
import type { DocumentData, GetDocKeyParams } from "../util/type";
|
|
3
|
-
declare const useGetDoc: <T>(params: Omit<GetDocKeyParams<T>, "
|
|
3
|
+
declare const useGetDoc: <T>(params: Omit<GetDocKeyParams<T>, "orderBy" | "where" | "limit"> | null, swrOptions?: Omit<Parameters<SWRHook>[2], "fetcher">) => import("swr/_internal").SWRResponse<DocumentData<T> | undefined, any, Omit<Partial<import("swr/_internal").PublicConfiguration<unknown, unknown, import("swr/_internal").BareFetcher<unknown>>> | undefined, "fetcher"> | undefined>;
|
|
4
4
|
export default useGetDoc;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { SWRHook } from "swr";
|
|
2
2
|
import type { DocumentData, GetDocKeyParams } from "../util/type";
|
|
3
|
-
declare const useGetDocs: <T>(params: GetDocKeyParams<T> | null, swrOptions?: Omit<Parameters<SWRHook>[2], "fetcher">) => import("swr/_internal").SWRResponse<DocumentData<T>[] | undefined, any,
|
|
3
|
+
declare const useGetDocs: <T>(params: GetDocKeyParams<T> | null, swrOptions?: Omit<Parameters<SWRHook>[2], "fetcher">) => import("swr/_internal").SWRResponse<DocumentData<T>[] | undefined, any, Omit<Partial<import("swr/_internal").PublicConfiguration<unknown, unknown, import("swr/_internal").BareFetcher<unknown>>> | undefined, "fetcher"> | undefined>;
|
|
4
4
|
export default useGetDocs;
|
package/dist/index.js
CHANGED
|
@@ -24,21 +24,30 @@ const getFirestoreConverter = (parseDates) => ({
|
|
|
24
24
|
return model;
|
|
25
25
|
}
|
|
26
26
|
});
|
|
27
|
+
const isQueryConstraintParams = (params) => {
|
|
28
|
+
return params.queryConstraints != null;
|
|
29
|
+
};
|
|
27
30
|
const useCollection = (params) => {
|
|
28
|
-
|
|
31
|
+
let swrKey = params;
|
|
32
|
+
if (params != null && isQueryConstraintParams(params)) {
|
|
33
|
+
swrKey = JSON.parse(JSON.stringify(params));
|
|
34
|
+
}
|
|
35
|
+
return useSWRSubscription(swrKey, (_, { next }) => {
|
|
29
36
|
if (params == null) {
|
|
30
37
|
return () => {
|
|
31
38
|
};
|
|
32
39
|
}
|
|
33
|
-
const { path,
|
|
34
|
-
const converter = getFirestoreConverter(
|
|
40
|
+
const { path, parseDates } = params;
|
|
41
|
+
const converter = getFirestoreConverter(parseDates);
|
|
35
42
|
const ref = collection(getFirestore(), path);
|
|
36
43
|
let q;
|
|
37
|
-
if (
|
|
38
|
-
|
|
44
|
+
if (isQueryConstraintParams(params)) {
|
|
45
|
+
q = query(ref, ...params.queryConstraints);
|
|
46
|
+
} else {
|
|
47
|
+
const { where: w, orderBy: o, limit: l } = params;
|
|
39
48
|
q = query(ref, ...(w ? w : []).map((q2) => where(...q2)), ...(o ? o : []).map((q2) => orderBy(...q2)), ...l ? [limit(l)] : []);
|
|
40
49
|
}
|
|
41
|
-
const unsub = onSnapshot(
|
|
50
|
+
const unsub = onSnapshot(q.withConverter(converter), (qs) => {
|
|
42
51
|
next(null, qs.docs.map((x) => x.data()));
|
|
43
52
|
}, (error) => {
|
|
44
53
|
next(error);
|
|
@@ -47,34 +56,49 @@ const useCollection = (params) => {
|
|
|
47
56
|
});
|
|
48
57
|
};
|
|
49
58
|
const useCollectionCount = (params, swrOptions) => {
|
|
50
|
-
|
|
51
|
-
|
|
59
|
+
let swrKey = params;
|
|
60
|
+
if (params != null && isQueryConstraintParams(params)) {
|
|
61
|
+
swrKey = JSON.parse(JSON.stringify(params));
|
|
62
|
+
}
|
|
63
|
+
const fetcher = async () => {
|
|
64
|
+
if (params == null) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const { path } = params;
|
|
52
68
|
const ref = collection(getFirestore(), path);
|
|
53
69
|
let q;
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
70
|
+
if (isQueryConstraintParams(params)) {
|
|
71
|
+
q = query(ref, ...params.queryConstraints);
|
|
72
|
+
} else {
|
|
73
|
+
const { where: w, limit: l } = params;
|
|
74
|
+
q = query(ref, ...(w ? w : []).map((q2) => where(...q2)), ...l ? [limit(l)] : []);
|
|
57
75
|
}
|
|
58
|
-
const sn = await getCountFromServer(q
|
|
76
|
+
const sn = await getCountFromServer(q);
|
|
59
77
|
return sn.data().count;
|
|
60
78
|
};
|
|
61
|
-
return useSWR(
|
|
79
|
+
return useSWR(swrKey, fetcher, swrOptions);
|
|
62
80
|
};
|
|
63
81
|
const useCollectionGroup = (params) => {
|
|
64
|
-
|
|
82
|
+
let swrKey = params;
|
|
83
|
+
if (params != null && isQueryConstraintParams(params)) {
|
|
84
|
+
swrKey = JSON.parse(JSON.stringify(params));
|
|
85
|
+
}
|
|
86
|
+
return useSWRSubscription(swrKey, (_, { next }) => {
|
|
65
87
|
if (params == null) {
|
|
66
88
|
return () => {
|
|
67
89
|
};
|
|
68
90
|
}
|
|
69
|
-
const { path,
|
|
70
|
-
const converter = getFirestoreConverter(
|
|
91
|
+
const { path, parseDates } = params;
|
|
92
|
+
const converter = getFirestoreConverter(parseDates);
|
|
71
93
|
const ref = collectionGroup(getFirestore(), path);
|
|
72
94
|
let q;
|
|
73
|
-
if (
|
|
74
|
-
|
|
95
|
+
if (isQueryConstraintParams(params)) {
|
|
96
|
+
q = query(ref, ...params.queryConstraints);
|
|
97
|
+
} else {
|
|
98
|
+
const { where: w, orderBy: o, limit: l } = params;
|
|
75
99
|
q = query(ref, ...(w ? w : []).map((q2) => where(...q2)), ...(o ? o : []).map((q2) => orderBy(...q2)), ...l ? [limit(l)] : []);
|
|
76
100
|
}
|
|
77
|
-
const unsub = onSnapshot(
|
|
101
|
+
const unsub = onSnapshot(q.withConverter(converter), (qs) => {
|
|
78
102
|
next(null, qs.docs.map((x) => x.data()));
|
|
79
103
|
}, (error) => {
|
|
80
104
|
next(error);
|
|
@@ -83,18 +107,27 @@ const useCollectionGroup = (params) => {
|
|
|
83
107
|
});
|
|
84
108
|
};
|
|
85
109
|
const useCollectionGroupCount = (params, swrOptions) => {
|
|
86
|
-
|
|
87
|
-
|
|
110
|
+
let swrKey = params;
|
|
111
|
+
if (params != null && isQueryConstraintParams(params)) {
|
|
112
|
+
swrKey = JSON.parse(JSON.stringify(params));
|
|
113
|
+
}
|
|
114
|
+
const fetcher = async () => {
|
|
115
|
+
if (params == null) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const { path } = params;
|
|
88
119
|
const ref = collectionGroup(getFirestore(), path);
|
|
89
120
|
let q;
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
121
|
+
if (isQueryConstraintParams(params)) {
|
|
122
|
+
q = query(ref, ...params.queryConstraints);
|
|
123
|
+
} else {
|
|
124
|
+
const { where: w, limit: l } = params;
|
|
125
|
+
q = query(ref, ...(w ? w : []).map((q2) => where(...q2)), ...l ? [limit(l)] : []);
|
|
93
126
|
}
|
|
94
|
-
const sn = await getCountFromServer(q
|
|
127
|
+
const sn = await getCountFromServer(q);
|
|
95
128
|
return sn.data().count;
|
|
96
129
|
};
|
|
97
|
-
return useSWR(
|
|
130
|
+
return useSWR(swrKey, fetcher, swrOptions);
|
|
98
131
|
};
|
|
99
132
|
const useDoc = (params) => {
|
|
100
133
|
return useSWRSubscription(params, (_, { next }) => {
|
|
@@ -114,31 +147,43 @@ const useDoc = (params) => {
|
|
|
114
147
|
});
|
|
115
148
|
};
|
|
116
149
|
const useGetDoc = (params, swrOptions) => {
|
|
117
|
-
const fetcher = async (
|
|
118
|
-
|
|
119
|
-
|
|
150
|
+
const fetcher = async () => {
|
|
151
|
+
if (params == null) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const { path, parseDates, ...options } = params;
|
|
155
|
+
const converter = getFirestoreConverter(parseDates);
|
|
120
156
|
const ref = doc(getFirestore(), path);
|
|
121
|
-
const getFn =
|
|
157
|
+
const getFn = options.useOfflineCache ? getDocFromCache : getDoc;
|
|
122
158
|
const sn = await getFn(ref.withConverter(converter));
|
|
123
159
|
return sn.data();
|
|
124
160
|
};
|
|
125
161
|
return useSWR(params, fetcher, swrOptions);
|
|
126
162
|
};
|
|
127
163
|
const useGetDocs = (params, swrOptions) => {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
164
|
+
let swrKey = params;
|
|
165
|
+
if (params != null && isQueryConstraintParams(params)) {
|
|
166
|
+
swrKey = JSON.parse(JSON.stringify(params));
|
|
167
|
+
}
|
|
168
|
+
const fetcher = async () => {
|
|
169
|
+
if (params == null) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const { path, parseDates } = params;
|
|
173
|
+
const converter = getFirestoreConverter(parseDates);
|
|
131
174
|
const ref = collection(getFirestore(), path);
|
|
132
175
|
let q;
|
|
133
|
-
if (
|
|
134
|
-
|
|
176
|
+
if (isQueryConstraintParams(params)) {
|
|
177
|
+
q = query(ref, ...params.queryConstraints);
|
|
178
|
+
} else {
|
|
179
|
+
const { where: w, orderBy: o, limit: l } = params;
|
|
135
180
|
q = query(ref, ...(w ? w : []).map((q2) => where(...q2)), ...(o ? o : []).map((q2) => orderBy(...q2)), ...l ? [limit(l)] : []);
|
|
136
181
|
}
|
|
137
|
-
const getFn =
|
|
138
|
-
const sn = await getFn(
|
|
182
|
+
const getFn = params.useOfflineCache ? getDocsFromCache : getDocs;
|
|
183
|
+
const sn = await getFn(q.withConverter(converter));
|
|
139
184
|
return sn.docs.map((x) => x.data());
|
|
140
185
|
};
|
|
141
|
-
return useSWR(
|
|
186
|
+
return useSWR(swrKey, fetcher, swrOptions);
|
|
142
187
|
};
|
|
143
188
|
export {
|
|
144
189
|
useCollection,
|
package/dist/index.umd.cjs
CHANGED
|
@@ -24,21 +24,30 @@
|
|
|
24
24
|
return model;
|
|
25
25
|
}
|
|
26
26
|
});
|
|
27
|
+
const isQueryConstraintParams = (params) => {
|
|
28
|
+
return params.queryConstraints != null;
|
|
29
|
+
};
|
|
27
30
|
const useCollection = (params) => {
|
|
28
|
-
|
|
31
|
+
let swrKey = params;
|
|
32
|
+
if (params != null && isQueryConstraintParams(params)) {
|
|
33
|
+
swrKey = JSON.parse(JSON.stringify(params));
|
|
34
|
+
}
|
|
35
|
+
return useSWRSubscription(swrKey, (_, { next }) => {
|
|
29
36
|
if (params == null) {
|
|
30
37
|
return () => {
|
|
31
38
|
};
|
|
32
39
|
}
|
|
33
|
-
const { path,
|
|
34
|
-
const converter = getFirestoreConverter(
|
|
40
|
+
const { path, parseDates } = params;
|
|
41
|
+
const converter = getFirestoreConverter(parseDates);
|
|
35
42
|
const ref = firestore.collection(firestore.getFirestore(), path);
|
|
36
43
|
let q;
|
|
37
|
-
if (
|
|
38
|
-
|
|
44
|
+
if (isQueryConstraintParams(params)) {
|
|
45
|
+
q = firestore.query(ref, ...params.queryConstraints);
|
|
46
|
+
} else {
|
|
47
|
+
const { where: w, orderBy: o, limit: l } = params;
|
|
39
48
|
q = firestore.query(ref, ...(w ? w : []).map((q2) => firestore.where(...q2)), ...(o ? o : []).map((q2) => firestore.orderBy(...q2)), ...l ? [firestore.limit(l)] : []);
|
|
40
49
|
}
|
|
41
|
-
const unsub = firestore.onSnapshot(
|
|
50
|
+
const unsub = firestore.onSnapshot(q.withConverter(converter), (qs) => {
|
|
42
51
|
next(null, qs.docs.map((x) => x.data()));
|
|
43
52
|
}, (error) => {
|
|
44
53
|
next(error);
|
|
@@ -47,34 +56,49 @@
|
|
|
47
56
|
});
|
|
48
57
|
};
|
|
49
58
|
const useCollectionCount = (params, swrOptions) => {
|
|
50
|
-
|
|
51
|
-
|
|
59
|
+
let swrKey = params;
|
|
60
|
+
if (params != null && isQueryConstraintParams(params)) {
|
|
61
|
+
swrKey = JSON.parse(JSON.stringify(params));
|
|
62
|
+
}
|
|
63
|
+
const fetcher = async () => {
|
|
64
|
+
if (params == null) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const { path } = params;
|
|
52
68
|
const ref = firestore.collection(firestore.getFirestore(), path);
|
|
53
69
|
let q;
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
70
|
+
if (isQueryConstraintParams(params)) {
|
|
71
|
+
q = firestore.query(ref, ...params.queryConstraints);
|
|
72
|
+
} else {
|
|
73
|
+
const { where: w, limit: l } = params;
|
|
74
|
+
q = firestore.query(ref, ...(w ? w : []).map((q2) => firestore.where(...q2)), ...l ? [firestore.limit(l)] : []);
|
|
57
75
|
}
|
|
58
|
-
const sn = await firestore.getCountFromServer(q
|
|
76
|
+
const sn = await firestore.getCountFromServer(q);
|
|
59
77
|
return sn.data().count;
|
|
60
78
|
};
|
|
61
|
-
return useSWR(
|
|
79
|
+
return useSWR(swrKey, fetcher, swrOptions);
|
|
62
80
|
};
|
|
63
81
|
const useCollectionGroup = (params) => {
|
|
64
|
-
|
|
82
|
+
let swrKey = params;
|
|
83
|
+
if (params != null && isQueryConstraintParams(params)) {
|
|
84
|
+
swrKey = JSON.parse(JSON.stringify(params));
|
|
85
|
+
}
|
|
86
|
+
return useSWRSubscription(swrKey, (_, { next }) => {
|
|
65
87
|
if (params == null) {
|
|
66
88
|
return () => {
|
|
67
89
|
};
|
|
68
90
|
}
|
|
69
|
-
const { path,
|
|
70
|
-
const converter = getFirestoreConverter(
|
|
91
|
+
const { path, parseDates } = params;
|
|
92
|
+
const converter = getFirestoreConverter(parseDates);
|
|
71
93
|
const ref = firestore.collectionGroup(firestore.getFirestore(), path);
|
|
72
94
|
let q;
|
|
73
|
-
if (
|
|
74
|
-
|
|
95
|
+
if (isQueryConstraintParams(params)) {
|
|
96
|
+
q = firestore.query(ref, ...params.queryConstraints);
|
|
97
|
+
} else {
|
|
98
|
+
const { where: w, orderBy: o, limit: l } = params;
|
|
75
99
|
q = firestore.query(ref, ...(w ? w : []).map((q2) => firestore.where(...q2)), ...(o ? o : []).map((q2) => firestore.orderBy(...q2)), ...l ? [firestore.limit(l)] : []);
|
|
76
100
|
}
|
|
77
|
-
const unsub = firestore.onSnapshot(
|
|
101
|
+
const unsub = firestore.onSnapshot(q.withConverter(converter), (qs) => {
|
|
78
102
|
next(null, qs.docs.map((x) => x.data()));
|
|
79
103
|
}, (error) => {
|
|
80
104
|
next(error);
|
|
@@ -83,18 +107,27 @@
|
|
|
83
107
|
});
|
|
84
108
|
};
|
|
85
109
|
const useCollectionGroupCount = (params, swrOptions) => {
|
|
86
|
-
|
|
87
|
-
|
|
110
|
+
let swrKey = params;
|
|
111
|
+
if (params != null && isQueryConstraintParams(params)) {
|
|
112
|
+
swrKey = JSON.parse(JSON.stringify(params));
|
|
113
|
+
}
|
|
114
|
+
const fetcher = async () => {
|
|
115
|
+
if (params == null) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const { path } = params;
|
|
88
119
|
const ref = firestore.collectionGroup(firestore.getFirestore(), path);
|
|
89
120
|
let q;
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
121
|
+
if (isQueryConstraintParams(params)) {
|
|
122
|
+
q = firestore.query(ref, ...params.queryConstraints);
|
|
123
|
+
} else {
|
|
124
|
+
const { where: w, limit: l } = params;
|
|
125
|
+
q = firestore.query(ref, ...(w ? w : []).map((q2) => firestore.where(...q2)), ...l ? [firestore.limit(l)] : []);
|
|
93
126
|
}
|
|
94
|
-
const sn = await firestore.getCountFromServer(q
|
|
127
|
+
const sn = await firestore.getCountFromServer(q);
|
|
95
128
|
return sn.data().count;
|
|
96
129
|
};
|
|
97
|
-
return useSWR(
|
|
130
|
+
return useSWR(swrKey, fetcher, swrOptions);
|
|
98
131
|
};
|
|
99
132
|
const useDoc = (params) => {
|
|
100
133
|
return useSWRSubscription(params, (_, { next }) => {
|
|
@@ -114,31 +147,43 @@
|
|
|
114
147
|
});
|
|
115
148
|
};
|
|
116
149
|
const useGetDoc = (params, swrOptions) => {
|
|
117
|
-
const fetcher = async (
|
|
118
|
-
|
|
119
|
-
|
|
150
|
+
const fetcher = async () => {
|
|
151
|
+
if (params == null) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const { path, parseDates, ...options } = params;
|
|
155
|
+
const converter = getFirestoreConverter(parseDates);
|
|
120
156
|
const ref = firestore.doc(firestore.getFirestore(), path);
|
|
121
|
-
const getFn =
|
|
157
|
+
const getFn = options.useOfflineCache ? firestore.getDocFromCache : firestore.getDoc;
|
|
122
158
|
const sn = await getFn(ref.withConverter(converter));
|
|
123
159
|
return sn.data();
|
|
124
160
|
};
|
|
125
161
|
return useSWR(params, fetcher, swrOptions);
|
|
126
162
|
};
|
|
127
163
|
const useGetDocs = (params, swrOptions) => {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
164
|
+
let swrKey = params;
|
|
165
|
+
if (params != null && isQueryConstraintParams(params)) {
|
|
166
|
+
swrKey = JSON.parse(JSON.stringify(params));
|
|
167
|
+
}
|
|
168
|
+
const fetcher = async () => {
|
|
169
|
+
if (params == null) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const { path, parseDates } = params;
|
|
173
|
+
const converter = getFirestoreConverter(parseDates);
|
|
131
174
|
const ref = firestore.collection(firestore.getFirestore(), path);
|
|
132
175
|
let q;
|
|
133
|
-
if (
|
|
134
|
-
|
|
176
|
+
if (isQueryConstraintParams(params)) {
|
|
177
|
+
q = firestore.query(ref, ...params.queryConstraints);
|
|
178
|
+
} else {
|
|
179
|
+
const { where: w, orderBy: o, limit: l } = params;
|
|
135
180
|
q = firestore.query(ref, ...(w ? w : []).map((q2) => firestore.where(...q2)), ...(o ? o : []).map((q2) => firestore.orderBy(...q2)), ...l ? [firestore.limit(l)] : []);
|
|
136
181
|
}
|
|
137
|
-
const getFn =
|
|
138
|
-
const sn = await getFn(
|
|
182
|
+
const getFn = params.useOfflineCache ? firestore.getDocsFromCache : firestore.getDocs;
|
|
183
|
+
const sn = await getFn(q.withConverter(converter));
|
|
139
184
|
return sn.docs.map((x) => x.data());
|
|
140
185
|
};
|
|
141
|
-
return useSWR(
|
|
186
|
+
return useSWR(swrKey, fetcher, swrOptions);
|
|
142
187
|
};
|
|
143
188
|
exports2.useCollection = useCollection;
|
|
144
189
|
exports2.useCollectionCount = useCollectionCount;
|
package/dist/util/type.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { orderBy, where } from "firebase/firestore";
|
|
1
|
+
import type { orderBy, QueryCompositeFilterConstraint, QueryConstraint, QueryNonFilterConstraint, where } from "firebase/firestore";
|
|
2
2
|
import type { QueryDocumentSnapshot } from "firebase/firestore";
|
|
3
3
|
type Join<K, P> = K extends string | number ? P extends string | number ? `${K}${"" extends P ? "" : "."}${P}` : never : never;
|
|
4
4
|
type Prev = [
|
|
@@ -30,13 +30,20 @@ export type Paths<T, D extends number = 3> = [D] extends [never] ? never : T ext
|
|
|
30
30
|
[K in keyof T]-?: K extends string | number ? `${K}` | Join<K, Paths<T[K], Prev[D]>> : never;
|
|
31
31
|
}[keyof T] : "";
|
|
32
32
|
export type ValueOf<T> = T[keyof T];
|
|
33
|
-
export type
|
|
34
|
-
|
|
35
|
-
where?: [Paths<T>, Parameters<typeof where>[1], ValueOf<T>][];
|
|
33
|
+
export type QueryParams<T> = {
|
|
34
|
+
where?: [Paths<T>, Parameters<typeof where>[1], ValueOf<T> | unknown][];
|
|
36
35
|
orderBy?: [Paths<T>, Parameters<typeof orderBy>[1]][];
|
|
37
36
|
limit?: number;
|
|
37
|
+
};
|
|
38
|
+
export type QueryConstraintParams = {
|
|
39
|
+
queryConstraints?: [QueryCompositeFilterConstraint, ...Array<QueryNonFilterConstraint>] | QueryConstraint[];
|
|
40
|
+
};
|
|
41
|
+
type BaseParams<T> = {
|
|
42
|
+
path: string;
|
|
38
43
|
parseDates?: Paths<T>[];
|
|
39
44
|
};
|
|
45
|
+
export type KeyParams<T> = BaseParams<T> & (QueryParams<T> | QueryConstraintParams);
|
|
46
|
+
export type KeyParamsForCount<T> = BaseParams<T> & (Omit<QueryParams<T>, "orderBy" | "parseDates"> | QueryConstraintParams);
|
|
40
47
|
export type GetDocKeyParams<T> = KeyParams<T> & {
|
|
41
48
|
useOfflineCache?: boolean;
|
|
42
49
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { KeyParams, QueryConstraintParams } from "./type";
|
|
2
|
+
export declare const isQueryConstraintParams: <T>(params: KeyParams<T>) => params is {
|
|
3
|
+
path: string;
|
|
4
|
+
parseDates?: (T extends object ? (T extends infer T_1 extends object ? { [K in keyof T_1]-?: K extends string | number ? `${K}` | (K extends infer T_2 ? T_2 extends K ? T_2 extends string | number ? (T[K] extends infer T_3 ? T_3 extends T[K] ? T_3 extends object ? (T_3 extends infer T_4 extends object ? { [K_1 in keyof T_4]-?: K_1 extends string | number ? `${K_1}` | (K_1 extends infer T_5 ? T_5 extends K_1 ? T_5 extends string | number ? (T_3[K_1] extends infer T_6 ? T_6 extends T_3[K_1] ? T_6 extends object ? (T_6 extends infer T_7 extends object ? { [K_2 in keyof T_7]-?: K_2 extends string | number ? `${K_2}` | (K_2 extends infer T_8 ? T_8 extends K_2 ? T_8 extends string | number ? (T_6[K_2] extends infer T_9 ? T_9 extends T_6[K_2] ? T_9 extends object ? (T_9 extends infer T_10 extends object ? { [K_3 in keyof T_10]-?: K_3 extends string | number ? `${K_3}` | (K_3 extends infer T_11 ? T_11 extends K_3 ? T_11 extends string | number ? never : never : never : never) : never; } : never)[keyof T_9] : "" : never : never) extends infer T_12 ? T_12 extends (T_6[K_2] extends infer T_9 ? T_9 extends T_6[K_2] ? T_9 extends object ? (T_9 extends infer T_10 extends object ? { [K_3 in keyof T_10]-?: K_3 extends string | number ? `${K_3}` | (K_3 extends infer T_11 ? T_11 extends K_3 ? T_11 extends string | number ? never : never : never : never) : never; } : never)[keyof T_9] : "" : never : never) ? T_12 extends string | number ? `${T_8}${"" extends T_12 ? T_12 & "" : "."}${T_12}` : never : never : never : never : never : never) : never; } : never)[keyof T_6] : "" : never : never) extends infer T_13 ? T_13 extends (T_3[K_1] extends infer T_6 ? T_6 extends T_3[K_1] ? T_6 extends object ? (T_6 extends infer T_7 extends object ? { [K_2 in keyof T_7]-?: K_2 extends string | number ? `${K_2}` | (K_2 extends infer T_8 ? T_8 extends K_2 ? T_8 extends string | number ? (T_6[K_2] extends infer T_9 ? T_9 extends T_6[K_2] ? T_9 extends object ? (T_9 extends infer T_10 extends object ? { [K_3 in keyof T_10]-?: K_3 extends string | number ? `${K_3}` | (K_3 extends infer T_11 ? T_11 extends K_3 ? T_11 extends string | number ? never : never : never : never) : never; } : never)[keyof T_9] : "" : never : never) extends infer T_12 ? T_12 extends (T_6[K_2] extends infer T_9 ? T_9 extends T_6[K_2] ? T_9 extends object ? (T_9 extends infer T_10 extends object ? { [K_3 in keyof T_10]-?: K_3 extends string | number ? `${K_3}` | (K_3 extends infer T_11 ? T_11 extends K_3 ? T_11 extends string | number ? never : never : never : never) : never; } : never)[keyof T_9] : "" : never : never) ? T_12 extends string | number ? `${T_8}${"" extends T_12 ? T_12 & "" : "."}${T_12}` : never : never : never : never : never : never) : never; } : never)[keyof T_6] : "" : never : never) ? T_13 extends string | number ? `${T_5}${"" extends T_13 ? T_13 & "" : "."}${T_13}` : never : never : never : never : never : never) : never; } : never)[keyof T_3] : "" : never : never) extends infer T_14 ? T_14 extends (T[K] extends infer T_3 ? T_3 extends T[K] ? T_3 extends object ? (T_3 extends infer T_4 extends object ? { [K_1 in keyof T_4]-?: K_1 extends string | number ? `${K_1}` | (K_1 extends infer T_5 ? T_5 extends K_1 ? T_5 extends string | number ? (T_3[K_1] extends infer T_6 ? T_6 extends T_3[K_1] ? T_6 extends object ? (T_6 extends infer T_7 extends object ? { [K_2 in keyof T_7]-?: K_2 extends string | number ? `${K_2}` | (K_2 extends infer T_8 ? T_8 extends K_2 ? T_8 extends string | number ? (T_6[K_2] extends infer T_9 ? T_9 extends T_6[K_2] ? T_9 extends object ? (T_9 extends infer T_10 extends object ? { [K_3 in keyof T_10]-?: K_3 extends string | number ? `${K_3}` | (K_3 extends infer T_11 ? T_11 extends K_3 ? T_11 extends string | number ? never : never : never : never) : never; } : never)[keyof T_9] : "" : never : never) extends infer T_12 ? T_12 extends (T_6[K_2] extends infer T_9 ? T_9 extends T_6[K_2] ? T_9 extends object ? (T_9 extends infer T_10 extends object ? { [K_3 in keyof T_10]-?: K_3 extends string | number ? `${K_3}` | (K_3 extends infer T_11 ? T_11 extends K_3 ? T_11 extends string | number ? never : never : never : never) : never; } : never)[keyof T_9] : "" : never : never) ? T_12 extends string | number ? `${T_8}${"" extends T_12 ? T_12 & "" : "."}${T_12}` : never : never : never : never : never : never) : never; } : never)[keyof T_6] : "" : never : never) extends infer T_13 ? T_13 extends (T_3[K_1] extends infer T_6 ? T_6 extends T_3[K_1] ? T_6 extends object ? (T_6 extends infer T_7 extends object ? { [K_2 in keyof T_7]-?: K_2 extends string | number ? `${K_2}` | (K_2 extends infer T_8 ? T_8 extends K_2 ? T_8 extends string | number ? (T_6[K_2] extends infer T_9 ? T_9 extends T_6[K_2] ? T_9 extends object ? (T_9 extends infer T_10 extends object ? { [K_3 in keyof T_10]-?: K_3 extends string | number ? `${K_3}` | (K_3 extends infer T_11 ? T_11 extends K_3 ? T_11 extends string | number ? never : never : never : never) : never; } : never)[keyof T_9] : "" : never : never) extends infer T_12 ? T_12 extends (T_6[K_2] extends infer T_9 ? T_9 extends T_6[K_2] ? T_9 extends object ? (T_9 extends infer T_10 extends object ? { [K_3 in keyof T_10]-?: K_3 extends string | number ? `${K_3}` | (K_3 extends infer T_11 ? T_11 extends K_3 ? T_11 extends string | number ? never : never : never : never) : never; } : never)[keyof T_9] : "" : never : never) ? T_12 extends string | number ? `${T_8}${"" extends T_12 ? T_12 & "" : "."}${T_12}` : never : never : never : never : never : never) : never; } : never)[keyof T_6] : "" : never : never) ? T_13 extends string | number ? `${T_5}${"" extends T_13 ? T_13 & "" : "."}${T_13}` : never : never : never : never : never : never) : never; } : never)[keyof T_3] : "" : never : never) ? T_14 extends string | number ? `${T_2}${"" extends T_14 ? T_14 & "" : "."}${T_14}` : never : never : never : never : never : never) : never; } : never)[keyof T] : "")[] | undefined;
|
|
5
|
+
} & QueryConstraintParams;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tatsuokaniwa/swr-firestore",
|
|
3
3
|
"description": "React Hooks library for Firestore using SWR's subscription feature.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/t-k/swr-firestore.git"
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"build": "tsc --noEmit && vite build",
|
|
35
35
|
"emulator": "firebase emulators:start --project swr-firestore-project --only firestore",
|
|
36
36
|
"test": "vitest",
|
|
37
|
-
"test:ci": "firebase emulators:exec --only auth,firestore,storage 'vitest run'",
|
|
37
|
+
"test:ci": "firebase emulators:exec --only auth,firestore,storage 'vitest run --coverage'",
|
|
38
38
|
"coverage": "vitest run --coverage",
|
|
39
39
|
"eslint": "eslint --fix --ext .ts,.tsx .",
|
|
40
40
|
"prettier": "prettier --check --write .",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"eslint": "^8.36.0",
|
|
61
61
|
"eslint-plugin-react": "^7.32.2",
|
|
62
62
|
"firebase": "^9.11.0 < 10.0.0",
|
|
63
|
+
"firebase-admin": "^11.5.0",
|
|
63
64
|
"jsdom": "^21.1.1",
|
|
64
65
|
"prettier": "^2.8.5",
|
|
65
66
|
"react": "^18.2.0",
|