@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 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 { orderBy, where } from "firebase/firestore";
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: "Posts",
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: "Posts",
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: `Posts/${postId}`,
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: `Posts`,
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: `Posts/${postId}`,
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> | null, swrOptions?: Omit<SWRConfiguration, "fetcher">) => import("swr/_internal").SWRResponse<DocumentData<T>[] | undefined, any, {
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
- return useSWR(params, fetcher, {
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
- return useSWR(params, fetcher, {
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
  });