@tatsuokaniwa/swr-firestore 2.0.6 → 2.0.8

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.
Files changed (44) hide show
  1. package/README.md +488 -9
  2. package/dist/.vite/manifest.json +14 -0
  3. package/dist/fetcher/fetchAggregate.d.ts +37 -0
  4. package/dist/fetcher/fetchCollection.d.ts +24 -0
  5. package/dist/fetcher/fetchCollectionCount.d.ts +19 -0
  6. package/dist/fetcher/fetchCollectionGroup.d.ts +24 -0
  7. package/dist/fetcher/fetchCollectionGroupAggregate.d.ts +30 -0
  8. package/dist/fetcher/fetchCollectionGroupCount.d.ts +20 -0
  9. package/dist/fetcher/fetchDoc.d.ts +22 -0
  10. package/dist/fetcher/fetchDocInTx.d.ts +26 -0
  11. package/dist/fetcher/index.d.ts +9 -0
  12. package/dist/hooks/useAggregate.d.ts +5 -0
  13. package/dist/hooks/useCollection.d.ts +2 -2
  14. package/dist/hooks/useCollectionCount.d.ts +18 -14
  15. package/dist/hooks/useCollectionGroup.d.ts +2 -2
  16. package/dist/hooks/useCollectionGroupAggregate.d.ts +5 -0
  17. package/dist/hooks/useCollectionGroupCount.d.ts +18 -14
  18. package/dist/hooks/useDoc.d.ts +2 -2
  19. package/dist/hooks/useGetDoc.d.ts +18 -14
  20. package/dist/hooks/useGetDocs.d.ts +19 -15
  21. package/dist/index.d.ts +6 -3
  22. package/dist/index.js +166 -24
  23. package/dist/index.umd.cjs +165 -23
  24. package/dist/server/fetcher/getAggregate.d.ts +14 -0
  25. package/dist/server/fetcher/getCollectionCountInTx.d.ts +18 -0
  26. package/dist/server/fetcher/getCollectionGroupAggregate.d.ts +14 -0
  27. package/dist/server/fetcher/getCollectionGroupCountInTx.d.ts +18 -0
  28. package/dist/server/fetcher/getCollectionGroupInTx.d.ts +24 -0
  29. package/dist/server/fetcher/getCollectionInTx.d.ts +25 -0
  30. package/dist/server/fetcher/getDocInTx.d.ts +23 -0
  31. package/dist/server/index.d.ts +10 -2
  32. package/dist/server/index.js +274 -2
  33. package/dist/server/index.umd.cjs +272 -0
  34. package/dist/server/util/buildAggregateSpec.d.ts +11 -0
  35. package/dist/server/util/buildQuery.d.ts +12 -0
  36. package/dist/server/util/createKey.d.ts +3 -6
  37. package/dist/server/util/getConverter.d.ts +1 -1
  38. package/dist/util/buildAggregateSpec.d.ts +6 -0
  39. package/dist/util/buildQuery.d.ts +12 -0
  40. package/dist/util/getConverter.d.ts +1 -1
  41. package/dist/util/type.d.ts +69 -0
  42. package/dist/util/typeGuard.d.ts +2 -2
  43. package/package.json +19 -24
  44. package/dist/manifest.json +0 -12
package/README.md CHANGED
@@ -19,6 +19,13 @@ yarn add @tatsuokaniwa/swr-firestore
19
19
  pnpm i @tatsuokaniwa/swr-firestore
20
20
  ```
21
21
 
22
+ ### Requirements for Aggregation Queries
23
+
24
+ To use aggregation features (`useAggregate`, `useCollectionGroupAggregate`, `fetchAggregate`, `fetchCollectionGroupAggregate`):
25
+
26
+ - Client-side: `firebase >= 9.17.0`
27
+ - Server-side: `firebase-admin >= 11.5.0` (recommended)
28
+
22
29
  ## Usage
23
30
 
24
31
  ```tsx
@@ -38,14 +45,12 @@ export default function App() {
38
45
  // Conditional Fetching
39
46
  const [isLogin, setIsLogin] = useState(false);
40
47
  const { data } = useCollection<Post>(
41
- isLogin
42
- ? {
43
- path: "posts",
44
- where: [["status", "==", "published"]],
45
- orderBy: [["createdAt", "desc"]],
46
- parseDates: ["createdAt"],
47
- }
48
- : null
48
+ isLogin && {
49
+ path: "posts",
50
+ where: [["status", "==", "published"]],
51
+ orderBy: [["createdAt", "desc"]],
52
+ parseDates: ["createdAt"],
53
+ }
49
54
  );
50
55
  const { data: postCount } = useCollectionCount<Post>({
51
56
  path: "posts",
@@ -131,13 +136,26 @@ export default function Page({ fallback }) {
131
136
 
132
137
  ```ts
133
138
  import {
139
+ // SWR Hooks
134
140
  useCollection, // Subscription for collection
135
141
  useCollectionCount, // Wrapper for getCountFromServer for collection
136
142
  useCollectionGroup, // Subscription for collectionGroup
137
143
  useCollectionGroupCount, // Wrapper for getCountFromServer for collectionGroup
144
+ useAggregate, // Aggregation queries (count, sum, average) for collection
145
+ useCollectionGroupAggregate, // Aggregation queries for collectionGroup
138
146
  useDoc, // Subscription for document
139
147
  useGetDocs, // Fetch documents with firestore's getDocs
140
148
  useGetDoc, // Fetch document with firestore's getDoc
149
+ // Client-side fetchers (without SWR)
150
+ fetchDoc, // Fetch single document
151
+ fetchCollection, // Fetch collection
152
+ fetchCollectionCount, // Count documents in collection
153
+ fetchCollectionGroup, // Fetch collection group
154
+ fetchCollectionGroupCount, // Count documents in collection group
155
+ fetchAggregate, // Aggregation queries for collection
156
+ fetchCollectionGroupAggregate, // Aggregation queries for collection group
157
+ // Client-side transaction fetcher
158
+ fetchDocInTx, // Fetch document within transaction
141
159
  } from "@tatsuokaniwa/swr-firestore";
142
160
 
143
161
  import {
@@ -145,7 +163,15 @@ import {
145
163
  getCollectionCount, // for useCollectionCount
146
164
  getCollectionGroup, // for useCollectionGroup, useGetDocs
147
165
  getCollectionGroupCount, // for useCollectionGroupCount
166
+ getAggregate, // for useAggregate
167
+ getCollectionGroupAggregate, // for useCollectionGroupAggregate
148
168
  getDoc, // for useDoc, useGetDoc
169
+ // Transaction-aware fetchers (for use within db.runTransaction)
170
+ getDocInTx,
171
+ getCollectionInTx,
172
+ getCollectionCountInTx,
173
+ getCollectionGroupInTx,
174
+ getCollectionGroupCountInTx,
149
175
  } from "@tatsuokaniwa/swr-firestore/server";
150
176
  ```
151
177
 
@@ -291,6 +317,103 @@ Returns [`SWRResponse`](https://swr.vercel.app/docs/api#return-values)
291
317
  - `isValidating`: if there's a request or revalidation loading
292
318
  - `mutate(data?, options?)`: function to mutate the cached data (details)
293
319
 
320
+ ### `useAggregate(params, swrOptions)`
321
+
322
+ Wrapper for getAggregateFromServer for collection. Supports count, sum, and average aggregations in a single query.
323
+
324
+ #### Parameters
325
+
326
+ - `params`: KeyParams except `parseDates` & { aggregate: AggregateSpec } | null
327
+ - `swrOptions`: [Options for SWR hook](https://swr.vercel.app/docs/api#options) except `fetcher`
328
+
329
+ #### Return values
330
+
331
+ Returns [`SWRResponse`](https://swr.vercel.app/docs/api#return-values)
332
+
333
+ - `data`: aggregation result object with keys matching the aggregate spec
334
+ - `error`: FirestoreError
335
+ - `isLoading`: if there's an ongoing request and no "loaded data"
336
+ - `isValidating`: if there's a request or revalidation loading
337
+ - `mutate(data?, options?)`: function to mutate the cached data
338
+
339
+ ```ts
340
+ import { useAggregate } from "@tatsuokaniwa/swr-firestore";
341
+
342
+ type Product = {
343
+ name: string;
344
+ category: string;
345
+ price: number;
346
+ stock: number;
347
+ };
348
+
349
+ const { data, error, isLoading } = useAggregate<
350
+ Product,
351
+ {
352
+ totalStock: { type: "sum"; field: "stock" };
353
+ averagePrice: { type: "average"; field: "price" };
354
+ productCount: { type: "count" };
355
+ }
356
+ >({
357
+ path: "products",
358
+ where: [["category", "==", "electronics"]],
359
+ aggregate: {
360
+ totalStock: { type: "sum", field: "stock" },
361
+ averagePrice: { type: "average", field: "price" },
362
+ productCount: { type: "count" },
363
+ },
364
+ });
365
+
366
+ if (data) {
367
+ console.log(data.productCount); // number
368
+ console.log(data.totalStock); // number
369
+ console.log(data.averagePrice); // number | null (null when no documents)
370
+ }
371
+ ```
372
+
373
+ ### `useCollectionGroupAggregate(params, swrOptions)`
374
+
375
+ Wrapper for getAggregateFromServer for collectionGroup. Supports count, sum, and average aggregations across subcollections.
376
+
377
+ #### Parameters
378
+
379
+ - `params`: KeyParams except `parseDates` & { aggregate: AggregateSpec } | null
380
+ - `swrOptions`: [Options for SWR hook](https://swr.vercel.app/docs/api#options) except `fetcher`
381
+
382
+ #### Return values
383
+
384
+ Returns [`SWRResponse`](https://swr.vercel.app/docs/api#return-values)
385
+
386
+ - `data`: aggregation result object with keys matching the aggregate spec
387
+ - `error`: FirestoreError
388
+ - `isLoading`: if there's an ongoing request and no "loaded data"
389
+ - `isValidating`: if there's a request or revalidation loading
390
+ - `mutate(data?, options?)`: function to mutate the cached data
391
+
392
+ ```ts
393
+ import { useCollectionGroupAggregate } from "@tatsuokaniwa/swr-firestore";
394
+
395
+ type OrderItem = {
396
+ productId: string;
397
+ price: number;
398
+ quantity: number;
399
+ };
400
+
401
+ // Aggregate across all "items" subcollections
402
+ const { data } = useCollectionGroupAggregate<
403
+ OrderItem,
404
+ {
405
+ totalRevenue: { type: "sum"; field: "price" };
406
+ itemCount: { type: "count" };
407
+ }
408
+ >({
409
+ path: "items",
410
+ aggregate: {
411
+ totalRevenue: { type: "sum", field: "price" },
412
+ itemCount: { type: "count" },
413
+ },
414
+ });
415
+ ```
416
+
294
417
  ### `useDoc(params, swrOptions)`
295
418
 
296
419
  Subscription for document
@@ -375,6 +498,146 @@ const { data, error } = useGetDoc<Post>({
375
498
  });
376
499
  ```
377
500
 
501
+ ## Client-side fetchers
502
+
503
+ These functions fetch data directly from Firestore without SWR caching. Useful for one-off data fetching, imperative data loading, or when you don't need SWR's caching and revalidation features.
504
+
505
+ ### `fetchDoc(params)`
506
+
507
+ Fetch a single document from Firestore
508
+
509
+ ```ts
510
+ import { fetchDoc } from "@tatsuokaniwa/swr-firestore";
511
+
512
+ const city = await fetchDoc<City>({
513
+ path: "cities/tokyo",
514
+ parseDates: ["createdAt"],
515
+ });
516
+ ```
517
+
518
+ ### `fetchCollection(params)`
519
+
520
+ Fetch documents from a collection
521
+
522
+ ```ts
523
+ import { fetchCollection } from "@tatsuokaniwa/swr-firestore";
524
+
525
+ const cities = await fetchCollection<City>({
526
+ path: "cities",
527
+ where: [["population", ">", 1000000]],
528
+ orderBy: [["population", "desc"]],
529
+ limit: 10,
530
+ });
531
+ ```
532
+
533
+ ### `fetchCollectionCount(params)`
534
+
535
+ Count documents in a collection
536
+
537
+ ```ts
538
+ import { fetchCollectionCount } from "@tatsuokaniwa/swr-firestore";
539
+
540
+ const count = await fetchCollectionCount<City>({
541
+ path: "cities",
542
+ where: [["population", ">", 1000000]],
543
+ });
544
+ ```
545
+
546
+ ### `fetchCollectionGroup(params)`
547
+
548
+ Fetch documents from a collection group
549
+
550
+ ```ts
551
+ import { fetchCollectionGroup } from "@tatsuokaniwa/swr-firestore";
552
+
553
+ const comments = await fetchCollectionGroup<Comment>({
554
+ path: "comments",
555
+ where: [["authorId", "==", "user123"]],
556
+ limit: 10,
557
+ });
558
+ ```
559
+
560
+ ### `fetchCollectionGroupCount(params)`
561
+
562
+ Count documents in a collection group
563
+
564
+ ```ts
565
+ import { fetchCollectionGroupCount } from "@tatsuokaniwa/swr-firestore";
566
+
567
+ const count = await fetchCollectionGroupCount<Comment>({
568
+ path: "comments",
569
+ where: [["status", "==", "approved"]],
570
+ });
571
+ ```
572
+
573
+ ### `fetchAggregate(params)`
574
+
575
+ Fetch aggregation result from a collection
576
+
577
+ ```ts
578
+ import { fetchAggregate } from "@tatsuokaniwa/swr-firestore";
579
+
580
+ const result = await fetchAggregate<
581
+ Product,
582
+ {
583
+ count: { type: "count" };
584
+ totalStock: { type: "sum"; field: "stock" };
585
+ avgPrice: { type: "average"; field: "price" };
586
+ }
587
+ >({
588
+ path: "products",
589
+ aggregate: {
590
+ count: { type: "count" },
591
+ totalStock: { type: "sum", field: "stock" },
592
+ avgPrice: { type: "average", field: "price" },
593
+ },
594
+ });
595
+ ```
596
+
597
+ ### `fetchCollectionGroupAggregate(params)`
598
+
599
+ Fetch aggregation result from a collection group
600
+
601
+ ```ts
602
+ import { fetchCollectionGroupAggregate } from "@tatsuokaniwa/swr-firestore";
603
+
604
+ const result = await fetchCollectionGroupAggregate<
605
+ OrderItem,
606
+ { totalRevenue: { type: "sum"; field: "price" } }
607
+ >({
608
+ path: "items",
609
+ aggregate: {
610
+ totalRevenue: { type: "sum", field: "price" },
611
+ },
612
+ });
613
+ ```
614
+
615
+ ### `fetchDocInTx(transaction, params)`
616
+
617
+ Fetch a single document within a Firestore transaction (client-side)
618
+
619
+ Note: Due to Firebase client SDK limitations, only document fetching is supported in transactions. Collection queries within transactions are only available in the server module.
620
+
621
+ ```ts
622
+ import { getFirestore, runTransaction } from "firebase/firestore";
623
+ import { fetchDocInTx } from "@tatsuokaniwa/swr-firestore";
624
+
625
+ const db = getFirestore();
626
+
627
+ await runTransaction(db, async (t) => {
628
+ const city = await fetchDocInTx<City>(t, {
629
+ path: "cities/tokyo",
630
+ parseDates: ["createdAt"],
631
+ });
632
+
633
+ if (city) {
634
+ t.update(doc(db, "cities/tokyo"), {
635
+ population: city.population + 1,
636
+ });
637
+ }
638
+ });
639
+ ```
640
+
378
641
  ## Server module
379
642
 
380
643
  ### `getCollection(params)`
@@ -426,7 +689,7 @@ Returns `Promise<{
426
689
  - `data`: number of documents in the collection for the given path.
427
690
 
428
691
  ```ts
429
- import { getCollection } from "@tatsuokaniwa/swr-firestore/server";
692
+ import { getCollectionCount } from "@tatsuokaniwa/swr-firestore/server";
430
693
 
431
694
  // For useCollectionCount
432
695
  const { key, data } = await getCollectionCount<Post>({ path: "posts" });
@@ -489,6 +752,80 @@ const { key, data } = await getCollectionGroupCount<Comment>({
489
752
  });
490
753
  ```
491
754
 
755
+ ### `getAggregate(params)`
756
+
757
+ Fetch aggregation result using the Firebase Admin SDK and return the SWR key and data
758
+
759
+ #### Parameters
760
+
761
+ - `params`: KeyParams except `parseDates`, `queryConstraints` & { aggregate: AggregateSpec }
762
+
763
+ Note: `queryConstraints` is not supported on the server side because the Admin SDK uses a different query builder API.
764
+
765
+ #### Return values
766
+
767
+ Returns `Promise<{
768
+ key: string;
769
+ data: AggregateResult<TSpec>;
770
+ }>`
771
+
772
+ - `key`: SWR Key
773
+ - `data`: aggregation result object
774
+
775
+ ```ts
776
+ import { getAggregate } from "@tatsuokaniwa/swr-firestore/server";
777
+
778
+ // For useAggregate
779
+ const { key, data } = await getAggregate<
780
+ Product,
781
+ {
782
+ count: { type: "count" };
783
+ totalRevenue: { type: "sum"; field: "price" };
784
+ }
785
+ >({
786
+ path: "products",
787
+ aggregate: {
788
+ count: { type: "count" },
789
+ totalRevenue: { type: "sum", field: "price" },
790
+ },
791
+ });
792
+ ```
793
+
794
+ ### `getCollectionGroupAggregate(params)`
795
+
796
+ Fetch aggregation result across subcollections using the Firebase Admin SDK
797
+
798
+ #### Parameters
799
+
800
+ - `params`: KeyParams except `parseDates`, `queryConstraints` & { aggregate: AggregateSpec }
801
+
802
+ Note: `queryConstraints` is not supported on the server side because the Admin SDK uses a different query builder API.
803
+
804
+ #### Return values
805
+
806
+ Returns `Promise<{
807
+ key: string;
808
+ data: AggregateResult<TSpec>;
809
+ }>`
810
+
811
+ - `key`: SWR Key
812
+ - `data`: aggregation result object
813
+
814
+ ```ts
815
+ import { getCollectionGroupAggregate } from "@tatsuokaniwa/swr-firestore/server";
816
+
817
+ // For useCollectionGroupAggregate
818
+ const { key, data } = await getCollectionGroupAggregate<
819
+ OrderItem,
820
+ { totalItems: { type: "count" } }
821
+ >({
822
+ path: "items",
823
+ aggregate: {
824
+ totalItems: { type: "count" },
825
+ },
826
+ });
827
+ ```
828
+
492
829
  ### `getDoc(params)`
493
830
 
494
831
  Fetch the document using the Firebase Admin SDK and return the SWR key and data
@@ -519,6 +856,148 @@ const { key, data } = await getDoc<Post>({
519
856
  const { key, data } = await getDoc<Post>({ path: `posts/${postId}` });
520
857
  ```
521
858
 
859
+ ### `getDocInTx(transaction, params)`
860
+
861
+ Type-safe document fetcher for use within Firestore transactions
862
+
863
+ #### Parameters
864
+
865
+ - `transaction`: Firebase Admin SDK Transaction object
866
+ - `params`: KeyParams except `where`, `orderBy`, `limit`
867
+
868
+ #### Return values
869
+
870
+ Returns `Promise<DocumentData<T> | undefined>`
871
+
872
+ - Returns the document data, or undefined if the document does not exist
873
+
874
+ ```ts
875
+ import { getFirestore } from "firebase-admin/firestore";
876
+ import { getDocInTx } from "@tatsuokaniwa/swr-firestore/server";
877
+
878
+ const db = getFirestore();
879
+
880
+ await db.runTransaction(async (t) => {
881
+ const city = await getDocInTx<City>(t, {
882
+ path: "cities/tokyo",
883
+ parseDates: ["createdAt"],
884
+ });
885
+
886
+ if (city) {
887
+ t.update(db.doc("cities/tokyo"), {
888
+ population: city.population + 1,
889
+ });
890
+ }
891
+ });
892
+ ```
893
+
894
+ ### `getCollectionInTx(transaction, params)`
895
+
896
+ Type-safe collection fetcher for use within Firestore transactions
897
+
898
+ #### Parameters
899
+
900
+ - `transaction`: Firebase Admin SDK Transaction object
901
+ - `params`: KeyParams
902
+
903
+ #### Return values
904
+
905
+ Returns `Promise<DocumentData<T>[]>`
906
+
907
+ - Returns an array of document data
908
+
909
+ ```ts
910
+ import { getFirestore } from "firebase-admin/firestore";
911
+ import { getCollectionInTx } from "@tatsuokaniwa/swr-firestore/server";
912
+
913
+ const db = getFirestore();
914
+
915
+ await db.runTransaction(async (t) => {
916
+ const cities = await getCollectionInTx<City>(t, {
917
+ path: "cities",
918
+ where: [["population", ">", 1000000]],
919
+ orderBy: [["population", "desc"]],
920
+ limit: 10,
921
+ });
922
+
923
+ cities.forEach((city) => {
924
+ t.update(db.doc(`cities/${city.id}`), {
925
+ isLargeCity: true,
926
+ });
927
+ });
928
+ });
929
+ ```
930
+
931
+ ### `getCollectionCountInTx(transaction, params)`
932
+
933
+ Type-safe collection count fetcher for use within Firestore transactions
934
+
935
+ #### Parameters
936
+
937
+ - `transaction`: Firebase Admin SDK Transaction object
938
+ - `params`: KeyParams except `parseDates`
939
+
940
+ #### Return values
941
+
942
+ Returns `Promise<number>`
943
+
944
+ ```ts
945
+ await db.runTransaction(async (t) => {
946
+ const count = await getCollectionCountInTx<City>(t, {
947
+ path: "cities",
948
+ where: [["population", ">", 1000000]],
949
+ });
950
+ console.log(`Found ${count} large cities`);
951
+ });
952
+ ```
953
+
954
+ ### `getCollectionGroupInTx(transaction, params)`
955
+
956
+ Type-safe collection group fetcher for use within Firestore transactions
957
+
958
+ #### Parameters
959
+
960
+ - `transaction`: Firebase Admin SDK Transaction object
961
+ - `params`: KeyParams
962
+
963
+ #### Return values
964
+
965
+ Returns `Promise<DocumentData<T>[]>`
966
+
967
+ ```ts
968
+ await db.runTransaction(async (t) => {
969
+ const comments = await getCollectionGroupInTx<Comment>(t, {
970
+ path: "comments",
971
+ where: [["authorId", "==", "user123"]],
972
+ limit: 10,
973
+ });
974
+ // comments is DocumentData<Comment>[]
975
+ });
976
+ ```
977
+
978
+ ### `getCollectionGroupCountInTx(transaction, params)`
979
+
980
+ Type-safe collection group count fetcher for use within Firestore transactions
981
+
982
+ #### Parameters
983
+
984
+ - `transaction`: Firebase Admin SDK Transaction object
985
+ - `params`: KeyParams except `parseDates`
986
+
987
+ #### Return values
988
+
989
+ Returns `Promise<number>`
990
+
991
+ ```ts
992
+ await db.runTransaction(async (t) => {
993
+ const count = await getCollectionGroupCountInTx<Comment>(t, {
994
+ path: "comments",
995
+ where: [["status", "==", "approved"]],
996
+ });
997
+ console.log(`Found ${count} approved comments`);
998
+ });
999
+ ```
1000
+
522
1001
  ## Testing
523
1002
 
524
1003
  Before running the test, you need to install the [Firebase tools](https://firebase.google.com/docs/cli).
@@ -0,0 +1,14 @@
1
+ {
2
+ "src/index.ts": {
3
+ "file": "index.umd.cjs",
4
+ "name": "index",
5
+ "src": "src/index.ts",
6
+ "isEntry": true
7
+ },
8
+ "src/server/index.ts": {
9
+ "file": "server/index.umd.cjs",
10
+ "name": "server",
11
+ "src": "src/server/index.ts",
12
+ "isEntry": true
13
+ }
14
+ }
@@ -0,0 +1,37 @@
1
+ import type { KeyParamsForAggregate, SwrAggregateSpec, AggregateResult } from "../util/type";
2
+ /**
3
+ * Fetch aggregation result from a collection (client-side).
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * interface Product {
8
+ * name: string;
9
+ * category: string;
10
+ * price: number;
11
+ * stock: number;
12
+ * }
13
+ *
14
+ * const result = await fetchAggregate<
15
+ * Product,
16
+ * {
17
+ * totalStock: { type: "sum"; field: "stock" };
18
+ * averagePrice: { type: "average"; field: "price" };
19
+ * productCount: { type: "count" };
20
+ * }
21
+ * >({
22
+ * path: "products",
23
+ * where: [["category", "==", "electronics"]],
24
+ * aggregate: {
25
+ * totalStock: { type: "sum", field: "stock" },
26
+ * averagePrice: { type: "average", field: "price" },
27
+ * productCount: { type: "count" },
28
+ * },
29
+ * });
30
+ *
31
+ * console.log(result.productCount); // number
32
+ * console.log(result.totalStock); // number
33
+ * console.log(result.averagePrice); // number | null
34
+ * ```
35
+ */
36
+ declare const fetchAggregate: <T, TSpec extends SwrAggregateSpec<T>>(params: KeyParamsForAggregate<T, TSpec>) => Promise<AggregateResult<TSpec>>;
37
+ export default fetchAggregate;
@@ -0,0 +1,24 @@
1
+ import type { DocumentData, KeyParams } from "../util/type";
2
+ export type FetchCollectionParams<T> = KeyParams<T> & {
3
+ useOfflineCache?: boolean;
4
+ };
5
+ /**
6
+ * Fetch documents from a collection (client-side).
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * interface City {
11
+ * name: string;
12
+ * population: number;
13
+ * }
14
+ *
15
+ * const cities = await fetchCollection<City>({
16
+ * path: "cities",
17
+ * where: [["population", ">", 1000000]],
18
+ * orderBy: [["population", "desc"]],
19
+ * limit: 10,
20
+ * });
21
+ * ```
22
+ */
23
+ declare const fetchCollection: <T>(params: FetchCollectionParams<T>) => Promise<DocumentData<T>[]>;
24
+ export default fetchCollection;
@@ -0,0 +1,19 @@
1
+ import type { KeyParamsForCount } from "../util/type";
2
+ /**
3
+ * Fetch count of documents in a collection (client-side).
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * interface City {
8
+ * name: string;
9
+ * population: number;
10
+ * }
11
+ *
12
+ * const count = await fetchCollectionCount<City>({
13
+ * path: "cities",
14
+ * where: [["population", ">", 1000000]],
15
+ * });
16
+ * ```
17
+ */
18
+ declare const fetchCollectionCount: <T>(params: KeyParamsForCount<T>) => Promise<number>;
19
+ export default fetchCollectionCount;
@@ -0,0 +1,24 @@
1
+ import type { DocumentData, KeyParamsForCollectionGroup } from "../util/type";
2
+ export type FetchCollectionGroupParams<T> = KeyParamsForCollectionGroup<T> & {
3
+ useOfflineCache?: boolean;
4
+ };
5
+ /**
6
+ * Fetch documents from a collection group (client-side).
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * interface Comment {
11
+ * text: string;
12
+ * authorId: string;
13
+ * }
14
+ *
15
+ * // Fetch all "comments" subcollections across all documents
16
+ * const comments = await fetchCollectionGroup<Comment>({
17
+ * path: "comments",
18
+ * where: [["authorId", "==", "user123"]],
19
+ * limit: 10,
20
+ * });
21
+ * ```
22
+ */
23
+ declare const fetchCollectionGroup: <T>(params: FetchCollectionGroupParams<T>) => Promise<DocumentData<T>[]>;
24
+ export default fetchCollectionGroup;