@tatsuokaniwa/swr-firestore 1.2.0 → 2.0.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 +234 -28
- package/dist/hooks/useGetDocs.d.ts +3 -1
- package/dist/index.js +30 -6
- package/dist/index.umd.cjs +209 -185
- package/dist/manifest.json +5 -0
- package/dist/server/fetcher/getCollection.d.ts +6 -0
- package/dist/server/fetcher/getCollectionCount.d.ts +6 -0
- package/dist/server/fetcher/getCollectionGroup.d.ts +6 -0
- package/dist/server/fetcher/getCollectionGroupCount.d.ts +6 -0
- package/dist/server/fetcher/getDoc.d.ts +6 -0
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.js +196 -0
- package/dist/server/index.umd.cjs +196 -0
- package/dist/server/util/createKey.d.ts +9 -0
- package/dist/server/util/getConverter.d.ts +3 -0
- package/dist/server/util/type.d.ts +20 -0
- package/package.json +15 -1
package/README.md
CHANGED
|
@@ -66,26 +66,65 @@ export default function App() {
|
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
### For more complex queries
|
|
69
|
+
|
|
69
70
|
To perform complex queries like using `OR` queries or raw `QueryConstraint`, use the `queryConstraints` parameter.
|
|
70
71
|
However, this method does not provide input completion for field names from type definitions.
|
|
71
72
|
|
|
72
73
|
```tsx
|
|
73
|
-
import {
|
|
74
|
-
or,
|
|
75
|
-
orderBy,
|
|
76
|
-
where,
|
|
77
|
-
} from "firebase/firestore";
|
|
74
|
+
import { or, orderBy, where } from "firebase/firestore";
|
|
78
75
|
|
|
79
76
|
useCollection<City>({
|
|
80
77
|
path: "cities",
|
|
81
78
|
queryConstraints: [
|
|
82
|
-
or(
|
|
83
|
-
where('capital', '==', true),
|
|
84
|
-
where('population', '>=', 1000000)
|
|
85
|
-
),
|
|
79
|
+
or(where("capital", "==", true), where("population", ">=", 1000000)),
|
|
86
80
|
orderBy("createdAt", "desc"),
|
|
87
81
|
],
|
|
88
|
-
})
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### SSG and SSR
|
|
86
|
+
|
|
87
|
+
You can use the server module to get the SWR key and data.
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
import { useCollection, useGetDocs } from "@tatsuokaniwa/swr-firestore"
|
|
91
|
+
import { getCollection } from "@tatsuokaniwa/swr-firestore/server"
|
|
92
|
+
|
|
93
|
+
export async function getStaticProps() {
|
|
94
|
+
const params = {
|
|
95
|
+
path: "posts",
|
|
96
|
+
where: [["status", "==", "published"]],
|
|
97
|
+
}
|
|
98
|
+
const { key, data } = await getCollection<Post>({
|
|
99
|
+
...params,
|
|
100
|
+
isSubscription: true, // Add the prefix `$sub$` to the SWR key
|
|
101
|
+
})
|
|
102
|
+
const { key: useGetDocsKey, data: useGetDocsData } = await getCollection<Post>(params)
|
|
103
|
+
return {
|
|
104
|
+
props: {
|
|
105
|
+
fallback: {
|
|
106
|
+
[key]: data,
|
|
107
|
+
[useGetDocsKey]: useGetDocsData,
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export default function Page({ fallback }) {
|
|
114
|
+
const { data } = useCollection<Post>({
|
|
115
|
+
path: "posts",
|
|
116
|
+
where: [["status", "==", "published"]],
|
|
117
|
+
})
|
|
118
|
+
const { data: useGetDocsData } = useGetDocs<Post>({
|
|
119
|
+
path: "posts",
|
|
120
|
+
where: [["status", "==", "published"]],
|
|
121
|
+
})
|
|
122
|
+
return (
|
|
123
|
+
<SWRConfig value={{ fallback }}>
|
|
124
|
+
{data?.map((x, i) => <div key={i}>{x.content}}</div>)}
|
|
125
|
+
</SWRConfig>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
89
128
|
```
|
|
90
129
|
|
|
91
130
|
## API
|
|
@@ -100,40 +139,55 @@ import {
|
|
|
100
139
|
useGetDocs, // Fetch documents with firestore's getDocs
|
|
101
140
|
useGetDoc, // Fetch document with firestore's getDoc
|
|
102
141
|
} from "@tatsuokaniwa/swr-firestore";
|
|
142
|
+
|
|
143
|
+
import {
|
|
144
|
+
getCollection, // Get the SWR key and data for useCollection, useGetDocs
|
|
145
|
+
getCollectionCount, // for useCollectionCount
|
|
146
|
+
getCollectionGroup, // for useCollectionGroup, useGetDocs
|
|
147
|
+
getCollectionGroupCount, // for useCollectionGroupCount
|
|
148
|
+
getDoc, // for useDoc, useGetDoc
|
|
149
|
+
} from "@tatsuokaniwa/swr-firestore/server";
|
|
103
150
|
```
|
|
104
151
|
|
|
105
152
|
### Type definitions for parameters
|
|
106
153
|
|
|
107
154
|
```ts
|
|
108
|
-
import type {
|
|
155
|
+
import type {
|
|
156
|
+
endAt,
|
|
157
|
+
endBefore,
|
|
158
|
+
limit,
|
|
159
|
+
orderBy,
|
|
160
|
+
startAfter,
|
|
161
|
+
startAt,
|
|
162
|
+
where,
|
|
163
|
+
} from "firebase/firestore";
|
|
109
164
|
// First argument of hook, specifies options to firestore, and is also used as a key for SWR.
|
|
110
165
|
type KeyParams<T> =
|
|
111
166
|
| {
|
|
112
167
|
// The path to the collection or document of Firestore.
|
|
113
|
-
path: string
|
|
168
|
+
path: string;
|
|
114
169
|
// `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]][]
|
|
170
|
+
where?: [Paths<T>, Parameters<typeof where>[1], ValueOf<T> | unknown][];
|
|
171
|
+
orderBy?: [Paths<T>, Parameters<typeof orderBy>[1]][];
|
|
117
172
|
startAt?: Parameters<typeof startAt>;
|
|
118
173
|
startAfter?: Parameters<typeof startAfter>;
|
|
119
174
|
endAt?: Parameters<typeof endAt>;
|
|
120
175
|
endBefore?: Parameters<typeof endBefore>;
|
|
121
|
-
limit?: number
|
|
176
|
+
limit?: number;
|
|
122
177
|
// Array of field names that should be parsed as dates.
|
|
123
|
-
parseDates?: Paths<T>[]
|
|
178
|
+
parseDates?: Paths<T>[];
|
|
124
179
|
}
|
|
125
180
|
// OR for more complex query
|
|
126
181
|
| {
|
|
127
182
|
// The path to the collection or document of Firestore.
|
|
128
|
-
path: string
|
|
183
|
+
path: string;
|
|
129
184
|
// raw query constraints from `firebase/firestore`
|
|
130
185
|
queryConstraints?:
|
|
131
186
|
| [QueryCompositeFilterConstraint, ...Array<QueryNonFilterConstraint>]
|
|
132
|
-
| QueryConstraint[]
|
|
187
|
+
| QueryConstraint[];
|
|
133
188
|
// Array of field names that should be parsed as dates.
|
|
134
|
-
parseDates?: Paths<T>[]
|
|
135
|
-
}
|
|
136
|
-
|
|
189
|
+
parseDates?: Paths<T>[];
|
|
190
|
+
};
|
|
137
191
|
```
|
|
138
192
|
|
|
139
193
|
### Type definitions for return data
|
|
@@ -162,7 +216,7 @@ Subscription for collection
|
|
|
162
216
|
import { useCollection } from "@tatsuokaniwa/swr-firestore";
|
|
163
217
|
|
|
164
218
|
const { data, error } = useCollection<Post>({
|
|
165
|
-
path: "
|
|
219
|
+
path: "posts",
|
|
166
220
|
});
|
|
167
221
|
```
|
|
168
222
|
|
|
@@ -193,7 +247,7 @@ const {
|
|
|
193
247
|
error,
|
|
194
248
|
isLoading,
|
|
195
249
|
} = useCollectionCount<Post>({
|
|
196
|
-
path: "
|
|
250
|
+
path: "posts",
|
|
197
251
|
});
|
|
198
252
|
```
|
|
199
253
|
|
|
@@ -248,7 +302,7 @@ Subscription for document
|
|
|
248
302
|
import { useDoc } from "@tatsuokaniwa/swr-firestore";
|
|
249
303
|
|
|
250
304
|
const { data, error } = useDoc<Post>({
|
|
251
|
-
path: `
|
|
305
|
+
path: `posts/${postId}`,
|
|
252
306
|
});
|
|
253
307
|
```
|
|
254
308
|
|
|
@@ -258,7 +312,10 @@ Fetch documents with firestore's [getDocs](https://firebase.google.com/docs/refe
|
|
|
258
312
|
|
|
259
313
|
#### Parameters
|
|
260
314
|
|
|
261
|
-
- `params`: KeyParams | null
|
|
315
|
+
- `params`: KeyParams & { useOfflineCache?: boolean; isCollectionGroup?: boolean } | null
|
|
316
|
+
|
|
317
|
+
set `isCollectionGroup: true` to get data from collectionGroup
|
|
318
|
+
|
|
262
319
|
- `swrOptions`: [Options for SWR hook](https://swr.vercel.app/docs/api#options) except `fetcher`
|
|
263
320
|
|
|
264
321
|
#### Return values
|
|
@@ -275,7 +332,12 @@ Returns [`SWRResponse`](https://swr.vercel.app/docs/api#return-values)
|
|
|
275
332
|
import { useGetDocs } from "@tatsuokaniwa/swr-firestore";
|
|
276
333
|
|
|
277
334
|
const { data, error } = useGetDocs<Post>({
|
|
278
|
-
path: `
|
|
335
|
+
path: `posts`,
|
|
336
|
+
});
|
|
337
|
+
// for collectionGroup
|
|
338
|
+
const { data, error } = useGetDocs<Comment>({
|
|
339
|
+
path: `comments`,
|
|
340
|
+
isCollectionGroup: true,
|
|
279
341
|
});
|
|
280
342
|
```
|
|
281
343
|
|
|
@@ -285,7 +347,7 @@ Fetch the document with firestore's [getDoc](https://firebase.google.com/docs/re
|
|
|
285
347
|
|
|
286
348
|
#### Parameters
|
|
287
349
|
|
|
288
|
-
- `params`: KeyParams except `where`, `orderBy`, `limit` | null
|
|
350
|
+
- `params`: (KeyParams & { useOfflineCache?: boolean }) except `where`, `orderBy`, `limit` | null
|
|
289
351
|
- `swrOptions`: [Options for SWR hook](https://swr.vercel.app/docs/api#options) except `fetcher`
|
|
290
352
|
|
|
291
353
|
#### Return values
|
|
@@ -302,8 +364,152 @@ Returns [`SWRResponse`](https://swr.vercel.app/docs/api#return-values)
|
|
|
302
364
|
import { useGetDoc } from "@tatsuokaniwa/swr-firestore";
|
|
303
365
|
|
|
304
366
|
const { data, error } = useGetDoc<Post>({
|
|
305
|
-
path: `
|
|
367
|
+
path: `posts/${postId}`,
|
|
368
|
+
});
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## Server module
|
|
372
|
+
|
|
373
|
+
### `getCollection(params)`
|
|
374
|
+
|
|
375
|
+
Fetch documents using the Firebase Admin SDK and return the SWR key and data
|
|
376
|
+
|
|
377
|
+
#### Parameters
|
|
378
|
+
|
|
379
|
+
- `params`: KeyParams
|
|
380
|
+
|
|
381
|
+
#### Return values
|
|
382
|
+
|
|
383
|
+
Returns `Promise<{
|
|
384
|
+
key: string;
|
|
385
|
+
data: DocumentData<T>[];
|
|
386
|
+
}>`
|
|
387
|
+
|
|
388
|
+
- `key`: SWR Key
|
|
389
|
+
- `data`: documents in the collection for the given path
|
|
390
|
+
|
|
391
|
+
```ts
|
|
392
|
+
import { getCollection } from "@tatsuokaniwa/swr-firestore/server";
|
|
393
|
+
|
|
394
|
+
// For useCollection
|
|
395
|
+
const { key, data } = await getCollection<Post>({
|
|
396
|
+
path: "posts",
|
|
397
|
+
isSubscription: true, // Add the prefix `$sub$` to the SWR key
|
|
398
|
+
});
|
|
399
|
+
// For useGetDocs
|
|
400
|
+
const { key, data } = await getCollection<Post>({ path: "posts" });
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### `getCollectionCount(params)`
|
|
404
|
+
|
|
405
|
+
Fetch document's count using the Firebase Admin SDK and return the SWR key and data
|
|
406
|
+
|
|
407
|
+
#### Parameters
|
|
408
|
+
|
|
409
|
+
- `params`: KeyParams except `parseDates`
|
|
410
|
+
|
|
411
|
+
#### Return values
|
|
412
|
+
|
|
413
|
+
Returns `Promise<{
|
|
414
|
+
key: string;
|
|
415
|
+
data: number;
|
|
416
|
+
}>`
|
|
417
|
+
|
|
418
|
+
- `key`: SWR Key
|
|
419
|
+
- `data`: number of documents in the collection for the given path.
|
|
420
|
+
|
|
421
|
+
```ts
|
|
422
|
+
import { getCollection } from "@tatsuokaniwa/swr-firestore/server";
|
|
423
|
+
|
|
424
|
+
// For useCollectionCount
|
|
425
|
+
const { key, data } = await getCollectionCount<Post>({ path: "posts" });
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### `getCollectionGroup(params)`
|
|
429
|
+
|
|
430
|
+
Fetch documents using the Firebase Admin SDK and return the SWR key and data
|
|
431
|
+
|
|
432
|
+
#### Parameters
|
|
433
|
+
|
|
434
|
+
- `params`: KeyParams
|
|
435
|
+
|
|
436
|
+
#### Return values
|
|
437
|
+
|
|
438
|
+
Returns `Promise<{
|
|
439
|
+
key: string;
|
|
440
|
+
data: DocumentData<T>[];
|
|
441
|
+
}>`
|
|
442
|
+
|
|
443
|
+
- `key`: SWR Key
|
|
444
|
+
- `data`: documents in the collectionGroup for the given path
|
|
445
|
+
|
|
446
|
+
```ts
|
|
447
|
+
import { getCollectionGroup } from "@tatsuokaniwa/swr-firestore/server";
|
|
448
|
+
|
|
449
|
+
// For useCollectionGroup
|
|
450
|
+
const { key, data } = await getCollectionGroup<Comment>({
|
|
451
|
+
path: "comments",
|
|
452
|
+
isSubscription: true, // Add the prefix `$sub$` to the SWR key
|
|
453
|
+
});
|
|
454
|
+
// For useGetDocs with isCollectionGroup
|
|
455
|
+
const { key, data } = await getCollectionGroup<Comment>({ path: "comments" });
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### `getCollectionGroupCount(params)`
|
|
459
|
+
|
|
460
|
+
Fetch document's count using the Firebase Admin SDK and return the SWR key and data
|
|
461
|
+
|
|
462
|
+
#### Parameters
|
|
463
|
+
|
|
464
|
+
- `params`: KeyParams except `parseDates`
|
|
465
|
+
|
|
466
|
+
#### Return values
|
|
467
|
+
|
|
468
|
+
Returns `Promise<{
|
|
469
|
+
key: string;
|
|
470
|
+
data: number;
|
|
471
|
+
}>`
|
|
472
|
+
|
|
473
|
+
- `key`: SWR Key
|
|
474
|
+
- `data`: number of documents in the collection group for the given path
|
|
475
|
+
|
|
476
|
+
```ts
|
|
477
|
+
import { getCollectionGroupCount } from "@tatsuokaniwa/swr-firestore/server";
|
|
478
|
+
|
|
479
|
+
// For useCollectionGroupCount
|
|
480
|
+
const { key, data } = await getCollectionGroupCount<Comment>({
|
|
481
|
+
path: "comments",
|
|
482
|
+
});
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### `getDoc(params)`
|
|
486
|
+
|
|
487
|
+
Fetch the document using the Firebase Admin SDK and return the SWR key and data
|
|
488
|
+
|
|
489
|
+
#### Parameters
|
|
490
|
+
|
|
491
|
+
- `params`: KeyParams
|
|
492
|
+
|
|
493
|
+
#### Return values
|
|
494
|
+
|
|
495
|
+
Returns `Promise<{
|
|
496
|
+
key: string;
|
|
497
|
+
data: DocumentData<T>;
|
|
498
|
+
}>`
|
|
499
|
+
|
|
500
|
+
- `key`: SWR Key
|
|
501
|
+
- `data`: data for given path's document
|
|
502
|
+
|
|
503
|
+
```ts
|
|
504
|
+
import { getDoc } from "@tatsuokaniwa/swr-firestore/server";
|
|
505
|
+
|
|
506
|
+
// For useDoc
|
|
507
|
+
const { key, data } = await getDoc<Post>({
|
|
508
|
+
path: `posts/${postId}`,
|
|
509
|
+
isSubscription: true, // Add the prefix `$sub$` to the SWR key
|
|
306
510
|
});
|
|
511
|
+
// For useGetDoc
|
|
512
|
+
const { key, data } = await getDoc<Post>({ path: `posts/${postId}` });
|
|
307
513
|
```
|
|
308
514
|
|
|
309
515
|
## Testing
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { SWRConfiguration } from "swr";
|
|
2
2
|
import type { DocumentData, GetDocKeyParams } from "../util/type";
|
|
3
|
-
declare const useGetDocs: <T>(params: GetDocKeyParams<T>
|
|
3
|
+
declare const useGetDocs: <T>(params: (GetDocKeyParams<T> & {
|
|
4
|
+
isCollectionGroup?: boolean | undefined;
|
|
5
|
+
}) | null, swrOptions?: Omit<SWRConfiguration, "fetcher">) => import("swr/_internal").SWRResponse<DocumentData<T>[] | undefined, any, {
|
|
4
6
|
use: import("swr/_internal").Middleware[];
|
|
5
7
|
errorRetryInterval?: number | undefined;
|
|
6
8
|
errorRetryCount?: number | undefined;
|
package/dist/index.js
CHANGED
|
@@ -76,7 +76,7 @@ const useCollectionCount = (params, swrOptions) => {
|
|
|
76
76
|
const sn = await getCountFromServer(q);
|
|
77
77
|
return sn.data().count;
|
|
78
78
|
};
|
|
79
|
-
return useSWR(params, fetcher, {
|
|
79
|
+
return useSWR({ ...params, count: true }, fetcher, {
|
|
80
80
|
...swrOptions,
|
|
81
81
|
use: [serializeMiddleware, ...(swrOptions == null ? void 0 : swrOptions.use) ?? []]
|
|
82
82
|
});
|
|
@@ -121,7 +121,7 @@ const useCollectionGroupCount = (params, swrOptions) => {
|
|
|
121
121
|
const sn = await getCountFromServer(q);
|
|
122
122
|
return sn.data().count;
|
|
123
123
|
};
|
|
124
|
-
return useSWR(params, fetcher, {
|
|
124
|
+
return useSWR({ ...params, count: true }, fetcher, {
|
|
125
125
|
...swrOptions,
|
|
126
126
|
use: [serializeMiddleware, ...(swrOptions == null ? void 0 : swrOptions.use) ?? []]
|
|
127
127
|
});
|
|
@@ -155,7 +155,18 @@ const useGetDoc = (params, swrOptions) => {
|
|
|
155
155
|
const sn = await getFn(ref.withConverter(converter));
|
|
156
156
|
return sn.data();
|
|
157
157
|
};
|
|
158
|
-
|
|
158
|
+
const scrubKey = (params2) => {
|
|
159
|
+
if (params2 == null) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
const {
|
|
163
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
164
|
+
useOfflineCache: _useOfflineCache,
|
|
165
|
+
...rest
|
|
166
|
+
} = params2;
|
|
167
|
+
return rest;
|
|
168
|
+
};
|
|
169
|
+
return useSWR(scrubKey(params), fetcher, {
|
|
159
170
|
...swrOptions,
|
|
160
171
|
use: [serializeMiddleware, ...(swrOptions == null ? void 0 : swrOptions.use) ?? []]
|
|
161
172
|
});
|
|
@@ -165,9 +176,9 @@ const useGetDocs = (params, swrOptions) => {
|
|
|
165
176
|
if (params == null) {
|
|
166
177
|
return;
|
|
167
178
|
}
|
|
168
|
-
const { path, parseDates } = params;
|
|
179
|
+
const { path, parseDates, isCollectionGroup } = params;
|
|
169
180
|
const converter = getFirestoreConverter(parseDates);
|
|
170
|
-
const ref = collection(getFirestore(), path);
|
|
181
|
+
const ref = isCollectionGroup ? collectionGroup(getFirestore(), path) : collection(getFirestore(), path);
|
|
171
182
|
let q;
|
|
172
183
|
if (isQueryConstraintParams(params)) {
|
|
173
184
|
q = query(ref, ...params.queryConstraints);
|
|
@@ -179,7 +190,20 @@ const useGetDocs = (params, swrOptions) => {
|
|
|
179
190
|
const sn = await getFn(q.withConverter(converter));
|
|
180
191
|
return sn.docs.map((x) => x.data());
|
|
181
192
|
};
|
|
182
|
-
|
|
193
|
+
const scrubKey = (params2) => {
|
|
194
|
+
if (params2 == null) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
const {
|
|
198
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
199
|
+
isCollectionGroup: _isCollectionGroup,
|
|
200
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
201
|
+
useOfflineCache: _useOfflineCache,
|
|
202
|
+
...rest
|
|
203
|
+
} = params2;
|
|
204
|
+
return rest;
|
|
205
|
+
};
|
|
206
|
+
return useSWR(scrubKey(params), fetcher, {
|
|
183
207
|
...swrOptions,
|
|
184
208
|
use: [serializeMiddleware, ...(swrOptions == null ? void 0 : swrOptions.use) ?? []]
|
|
185
209
|
});
|