@dereekb/firebase 13.0.5 → 13.0.7
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/index.cjs.js +575 -146
- package/index.cjs.js.map +1 -1
- package/index.esm.js +573 -149
- package/index.esm.js.map +1 -1
- package/package.json +5 -5
- package/src/lib/common/firestore/accessor/document.rxjs.d.ts +55 -3
- package/src/lib/common/firestore/accessor/document.utility.d.ts +439 -128
- package/src/lib/common/firestore/query/constraint.d.ts +27 -22
- package/src/lib/common/firestore/query/constraint.template.d.ts +48 -32
- package/src/lib/common/firestore/query/iterator.d.ts +58 -2
- package/src/lib/common/firestore/query/query.iterate.d.ts +300 -96
- package/test/index.cjs.js +824 -15
- package/test/index.esm.js +826 -18
- package/test/package.json +6 -6
- package/test/src/lib/common/firestore/index.d.ts +1 -0
- package/test/src/lib/common/firestore/test.driver.utility.d.ts +7 -0
package/index.cjs.js
CHANGED
|
@@ -662,31 +662,33 @@ function extendFirestoreCollectionWithSingleDocumentAccessor(x, singleItemIdenti
|
|
|
662
662
|
}
|
|
663
663
|
|
|
664
664
|
/**
|
|
665
|
-
* Creates an array of new FirestoreDocument instances without
|
|
665
|
+
* Creates an array of new {@link FirestoreDocument} instances without persisting them to Firestore.
|
|
666
666
|
*
|
|
667
|
-
*
|
|
668
|
-
*
|
|
669
|
-
*
|
|
670
|
-
*
|
|
671
|
-
* @
|
|
667
|
+
* Each document is allocated a unique auto-generated ID via {@link FirestoreDocumentAccessor.newDocument},
|
|
668
|
+
* but no data is written to the database. Useful for preparing document references in bulk before
|
|
669
|
+
* deciding what data to write.
|
|
670
|
+
*
|
|
671
|
+
* @param documentAccessor - Accessor that provides the `newDocument()` factory method
|
|
672
|
+
* @param count - Number of document instances to create
|
|
673
|
+
* @returns Array of `count` new document instances, each with a unique auto-generated ID
|
|
672
674
|
*/
|
|
673
675
|
function newDocuments(documentAccessor, count) {
|
|
674
676
|
return util.makeWithFactory(() => documentAccessor.newDocument(), count);
|
|
675
677
|
}
|
|
676
678
|
/**
|
|
677
|
-
* Creates
|
|
679
|
+
* Creates and optionally persists multiple Firestore documents in sequence.
|
|
678
680
|
*
|
|
679
|
-
* For each
|
|
680
|
-
* 1.
|
|
681
|
-
* 2.
|
|
682
|
-
* 3. If init returns data,
|
|
683
|
-
* 4.
|
|
681
|
+
* Uses {@link performMakeLoop} to iterate `count` times. For each iteration:
|
|
682
|
+
* 1. A new document instance is created (via `make.newDocument` or the default factory)
|
|
683
|
+
* 2. `make.init(i, document)` is awaited to produce initial data
|
|
684
|
+
* 3. If init returns non-nullish data, `document.accessor.create(data)` persists it
|
|
685
|
+
* 4. The document instance is collected regardless of whether it was persisted
|
|
684
686
|
*
|
|
685
|
-
*
|
|
686
|
-
*
|
|
687
|
-
* @param documentAccessor -
|
|
688
|
-
* @param make -
|
|
689
|
-
* @returns
|
|
687
|
+
* Documents are created sequentially (not in parallel) to allow index-dependent logic.
|
|
688
|
+
*
|
|
689
|
+
* @param documentAccessor - Accessor providing the document factory and collection context
|
|
690
|
+
* @param make - Configuration controlling count, factory, and initialization
|
|
691
|
+
* @returns Promise resolving to all created document instances (length === `make.count`)
|
|
690
692
|
*/
|
|
691
693
|
function makeDocuments(documentAccessor, make) {
|
|
692
694
|
const newDocumentFn = make.newDocument ?? (() => documentAccessor.newDocument());
|
|
@@ -703,65 +705,52 @@ function makeDocuments(documentAccessor, make) {
|
|
|
703
705
|
});
|
|
704
706
|
}
|
|
705
707
|
/**
|
|
706
|
-
*
|
|
708
|
+
* Fetches {@link DocumentSnapshot}s for multiple documents in parallel using {@link runAsyncTasksForValues}.
|
|
707
709
|
*
|
|
708
|
-
*
|
|
710
|
+
* Each document's `accessor.get()` is called concurrently. The returned array preserves
|
|
711
|
+
* the same ordering as the input `documents` array.
|
|
709
712
|
*
|
|
710
|
-
* @
|
|
711
|
-
* @
|
|
712
|
-
* @returns Promise that resolves to an array of DocumentSnapshots in the same order as the input documents
|
|
713
|
+
* @param documents - Documents to fetch snapshots for
|
|
714
|
+
* @returns Snapshots in the same order as the input array
|
|
713
715
|
*/
|
|
714
716
|
function getDocumentSnapshots(documents) {
|
|
715
717
|
return util.runAsyncTasksForValues(documents, (x) => x.accessor.get());
|
|
716
718
|
}
|
|
717
719
|
/**
|
|
718
|
-
*
|
|
719
|
-
*
|
|
720
|
-
* Fetches the current snapshot of the document and returns both the original
|
|
721
|
-
* document instance and the snapshot together.
|
|
720
|
+
* Fetches the current snapshot of a single document and pairs it with the document instance.
|
|
722
721
|
*
|
|
723
|
-
* @
|
|
724
|
-
* @
|
|
725
|
-
* @returns Promise that resolves to a document-snapshot pair
|
|
722
|
+
* @param document - The document to fetch
|
|
723
|
+
* @returns A pair containing the document and its snapshot
|
|
726
724
|
*/
|
|
727
725
|
function getDocumentSnapshotPair(document) {
|
|
728
726
|
return document.accessor.get().then((snapshot) => ({ document, snapshot }));
|
|
729
727
|
}
|
|
730
728
|
/**
|
|
731
|
-
*
|
|
729
|
+
* Fetches snapshots for multiple documents in parallel and pairs each with its document instance.
|
|
732
730
|
*
|
|
733
|
-
*
|
|
734
|
-
* the
|
|
735
|
-
*
|
|
736
|
-
* @template D - The FirestoreDocument implementation type
|
|
737
|
-
* @param documents - Array of document instances to get snapshots for
|
|
738
|
-
* @returns Promise that resolves to an array of document-snapshot pairs in the same order as the input documents
|
|
731
|
+
* @param documents - Documents to fetch
|
|
732
|
+
* @returns Pairs in the same order as the input array
|
|
739
733
|
*/
|
|
740
734
|
function getDocumentSnapshotPairs(documents) {
|
|
741
735
|
return util.runAsyncTasksForValues(documents, getDocumentSnapshotPair);
|
|
742
736
|
}
|
|
743
737
|
/**
|
|
744
|
-
*
|
|
745
|
-
*
|
|
746
|
-
* Fetches the current snapshot of the document, extracts its data with ID and key fields,
|
|
747
|
-
* and returns all three together in a single object.
|
|
738
|
+
* Fetches a document's snapshot, extracts its data with `id`/`key` fields, and returns all three as a triplet.
|
|
748
739
|
*
|
|
749
|
-
* @
|
|
750
|
-
* @
|
|
751
|
-
* @returns Promise that resolves to a document-snapshot-data triplet
|
|
740
|
+
* @param document - The document to fetch
|
|
741
|
+
* @returns A triplet of document, snapshot, and data (data may be `undefined` if the document doesn't exist)
|
|
752
742
|
*/
|
|
753
743
|
function getDocumentSnapshotDataPair(document) {
|
|
754
744
|
return document.accessor.get().then((snapshot) => ({ document, snapshot, data: documentDataWithIdAndKey(snapshot) }));
|
|
755
745
|
}
|
|
756
746
|
/**
|
|
757
|
-
*
|
|
747
|
+
* Fetches snapshot-data triplets for multiple documents in parallel.
|
|
758
748
|
*
|
|
759
|
-
*
|
|
760
|
-
*
|
|
749
|
+
* Processes up to 200 documents concurrently via {@link runAsyncTasksForValues}.
|
|
750
|
+
* The returned array preserves the same ordering as the input.
|
|
761
751
|
*
|
|
762
|
-
* @
|
|
763
|
-
* @
|
|
764
|
-
* @returns Promise that resolves to an array of document-snapshot-data triplets in the same order as the input documents
|
|
752
|
+
* @param documents - Documents to fetch
|
|
753
|
+
* @returns Triplets in the same order as the input array
|
|
765
754
|
*/
|
|
766
755
|
function getDocumentSnapshotDataPairs(documents) {
|
|
767
756
|
return util.runAsyncTasksForValues(documents, getDocumentSnapshotDataPair, {
|
|
@@ -769,18 +758,27 @@ function getDocumentSnapshotDataPairs(documents) {
|
|
|
769
758
|
});
|
|
770
759
|
}
|
|
771
760
|
/**
|
|
772
|
-
*
|
|
761
|
+
* Fetches snapshot-data triplets for multiple documents and filters out those that don't exist in Firestore.
|
|
773
762
|
*
|
|
774
|
-
*
|
|
775
|
-
* only
|
|
763
|
+
* Convenience wrapper around {@link getDocumentSnapshotDataPairs} that removes entries where `data` is nullish,
|
|
764
|
+
* returning only {@link FirestoreDocumentSnapshotDataPairWithData} results.
|
|
776
765
|
*
|
|
777
|
-
* @
|
|
778
|
-
* @
|
|
779
|
-
* @returns Promise that resolves to an array of document-snapshot-data triplets for existing documents only
|
|
766
|
+
* @param documents - Documents to fetch
|
|
767
|
+
* @returns Triplets for documents that exist, in their original relative order
|
|
780
768
|
*/
|
|
781
769
|
function getDocumentSnapshotDataPairsWithData(documents) {
|
|
782
770
|
return getDocumentSnapshotDataPairs(documents).then((x) => x.filter((y) => !!y.data));
|
|
783
771
|
}
|
|
772
|
+
/**
|
|
773
|
+
* Fetches raw snapshot data tuples for multiple documents in parallel.
|
|
774
|
+
*
|
|
775
|
+
* Unlike {@link getDocumentSnapshotDataPairs}, this returns a lightweight `[document, data]` tuple
|
|
776
|
+
* and does not inject `id`/`key` fields onto the data. The `data` value is the raw result of
|
|
777
|
+
* `snapshot.data()` and may be `undefined` for non-existent documents.
|
|
778
|
+
*
|
|
779
|
+
* @param documents - Documents to fetch
|
|
780
|
+
* @returns Tuples in the same order as the input array
|
|
781
|
+
*/
|
|
784
782
|
function getDocumentSnapshotDataTuples(documents) {
|
|
785
783
|
return util.runAsyncTasksForValues(documents, (document) => document.accessor.get().then((snapshot) => [document, snapshot.data()]));
|
|
786
784
|
}
|
|
@@ -794,33 +792,109 @@ function getDataFromDocumentSnapshots(snapshots, withId = true) {
|
|
|
794
792
|
const mapFn = documentDataFunction(withId);
|
|
795
793
|
return util.filterMaybeArrayValues(snapshots.map(mapFn));
|
|
796
794
|
}
|
|
795
|
+
/**
|
|
796
|
+
* Creates {@link FirestoreDocument} instances for all documents in a {@link QuerySnapshot}.
|
|
797
|
+
*
|
|
798
|
+
* Maps each document in `snapshots.docs` to a loaded document via `accessor.loadDocument(ref)`.
|
|
799
|
+
* No additional data fetching occurs; the documents are loaded from their existing references.
|
|
800
|
+
*
|
|
801
|
+
* @param accessor - Accessor to load documents with
|
|
802
|
+
* @param snapshots - Query snapshot containing the document references
|
|
803
|
+
* @returns Document instances in the same order as the query results
|
|
804
|
+
*/
|
|
797
805
|
function loadDocumentsForSnapshots(accessor, snapshots) {
|
|
798
806
|
return snapshots.docs.map((x) => accessor.loadDocument(x.ref));
|
|
799
807
|
}
|
|
808
|
+
/**
|
|
809
|
+
* Extracts {@link DocumentReference}s from arbitrary values and loads them as {@link FirestoreDocument} instances.
|
|
810
|
+
*
|
|
811
|
+
* Convenience function that maps values through `getRef` then delegates to {@link loadDocumentsForDocumentReferences}.
|
|
812
|
+
*
|
|
813
|
+
* @param accessor - Accessor to load documents with
|
|
814
|
+
* @param values - Source values to extract references from
|
|
815
|
+
* @param getRef - Extracts a document reference from each value
|
|
816
|
+
* @returns Document instances in the same order as the input values
|
|
817
|
+
*/
|
|
800
818
|
function loadDocumentsForDocumentReferencesFromValues(accessor, values, getRef) {
|
|
801
819
|
return loadDocumentsForDocumentReferences(accessor, values.map(getRef));
|
|
802
820
|
}
|
|
821
|
+
/**
|
|
822
|
+
* Alias for {@link loadDocumentsForDocumentReferencesFromValues}.
|
|
823
|
+
*/
|
|
803
824
|
const loadDocumentsForValues = loadDocumentsForDocumentReferencesFromValues;
|
|
825
|
+
/**
|
|
826
|
+
* Loads {@link FirestoreDocument} instances from an array of {@link DocumentReference}s.
|
|
827
|
+
*
|
|
828
|
+
* Each reference is passed to `accessor.loadDocument()` to create a document wrapper.
|
|
829
|
+
* No network calls are made; this only creates in-memory document instances bound to the given references.
|
|
830
|
+
*
|
|
831
|
+
* @param accessor - Accessor to load documents with
|
|
832
|
+
* @param refs - Document references to load
|
|
833
|
+
* @returns Document instances in the same order as the input references
|
|
834
|
+
*/
|
|
804
835
|
function loadDocumentsForDocumentReferences(accessor, refs) {
|
|
805
836
|
return refs.map((x) => accessor.loadDocument(x));
|
|
806
837
|
}
|
|
838
|
+
/**
|
|
839
|
+
* Extracts {@link FirestoreModelKey}s from arbitrary values and loads them as {@link FirestoreDocument} instances.
|
|
840
|
+
*
|
|
841
|
+
* Convenience function that maps values through `getKey` then delegates to {@link loadDocumentsForKeys}.
|
|
842
|
+
*
|
|
843
|
+
* @param accessor - Accessor to load documents with
|
|
844
|
+
* @param values - Source values to extract keys from
|
|
845
|
+
* @param getKey - Extracts a model key (full Firestore path) from each value
|
|
846
|
+
* @returns Document instances in the same order as the input values
|
|
847
|
+
*/
|
|
807
848
|
function loadDocumentsForKeysFromValues(accessor, values, getKey) {
|
|
808
849
|
return loadDocumentsForKeys(accessor, values.map(getKey));
|
|
809
850
|
}
|
|
851
|
+
/**
|
|
852
|
+
* Loads {@link FirestoreDocument} instances from an array of full Firestore document paths (keys).
|
|
853
|
+
*
|
|
854
|
+
* Each key is passed to `accessor.loadDocumentForKey()`. No network calls are made.
|
|
855
|
+
*
|
|
856
|
+
* @param accessor - Accessor to load documents with
|
|
857
|
+
* @param keys - Full Firestore document paths (e.g. `'users/abc123'`)
|
|
858
|
+
* @returns Document instances in the same order as the input keys
|
|
859
|
+
*/
|
|
810
860
|
function loadDocumentsForKeys(accessor, keys) {
|
|
811
861
|
return keys.map((x) => accessor.loadDocumentForKey(x));
|
|
812
862
|
}
|
|
863
|
+
/**
|
|
864
|
+
* Extracts {@link FirestoreModelId}s from arbitrary values and loads them as {@link FirestoreDocument} instances.
|
|
865
|
+
*
|
|
866
|
+
* Convenience function that maps values through `getId` then delegates to {@link loadDocumentsForIds}.
|
|
867
|
+
* Requires a full {@link FirestoreDocumentAccessor} (not limited) because loading by ID requires collection context.
|
|
868
|
+
*
|
|
869
|
+
* @param accessor - Accessor to load documents with (must have collection context for ID resolution)
|
|
870
|
+
* @param values - Source values to extract IDs from
|
|
871
|
+
* @param getId - Extracts a model ID from each value
|
|
872
|
+
* @returns Document instances in the same order as the input values
|
|
873
|
+
*/
|
|
813
874
|
function loadDocumentsForIdsFromValues(accessor, values, getId) {
|
|
814
875
|
return loadDocumentsForIds(accessor, values.map(getId));
|
|
815
876
|
}
|
|
877
|
+
/**
|
|
878
|
+
* Loads {@link FirestoreDocument} instances from an array of document IDs relative to the accessor's collection.
|
|
879
|
+
*
|
|
880
|
+
* Each ID is passed to `accessor.loadDocumentForId()`. Requires a full {@link FirestoreDocumentAccessor}
|
|
881
|
+
* because ID-based loading needs the collection reference to resolve the full path. No network calls are made.
|
|
882
|
+
*
|
|
883
|
+
* @param accessor - Accessor to load documents with (must have collection context)
|
|
884
|
+
* @param ids - Document IDs within the accessor's collection
|
|
885
|
+
* @returns Document instances in the same order as the input IDs
|
|
886
|
+
*/
|
|
816
887
|
function loadDocumentsForIds(accessor, ids) {
|
|
817
888
|
return ids.map((x) => accessor.loadDocumentForId(x));
|
|
818
889
|
}
|
|
819
890
|
/**
|
|
820
|
-
*
|
|
891
|
+
* Creates a {@link FirestoreDocumentLoader} from a {@link LimitedFirestoreDocumentAccessorContextExtension}.
|
|
821
892
|
*
|
|
822
|
-
*
|
|
823
|
-
* @
|
|
893
|
+
* The returned loader resolves the appropriate accessor based on whether a transaction is provided,
|
|
894
|
+
* then delegates to {@link loadDocumentsForDocumentReferences}.
|
|
895
|
+
*
|
|
896
|
+
* @param accessorContext - Context that provides accessors for both default and transactional use
|
|
897
|
+
* @returns A loader function that converts document references to document instances
|
|
824
898
|
*/
|
|
825
899
|
function firestoreDocumentLoader(accessorContext) {
|
|
826
900
|
return (references, transaction) => {
|
|
@@ -829,10 +903,16 @@ function firestoreDocumentLoader(accessorContext) {
|
|
|
829
903
|
};
|
|
830
904
|
}
|
|
831
905
|
/**
|
|
832
|
-
*
|
|
906
|
+
* Creates a {@link FirestoreDocumentSnapshotPairsLoader} from a {@link LimitedFirestoreDocumentAccessorContextExtension}.
|
|
833
907
|
*
|
|
834
|
-
*
|
|
835
|
-
* @
|
|
908
|
+
* The returned loader resolves the appropriate accessor based on whether a transaction is provided,
|
|
909
|
+
* then maps each snapshot to a {@link FirestoreDocumentSnapshotDataPair} using {@link firestoreDocumentSnapshotPairsLoaderInstance}.
|
|
910
|
+
*
|
|
911
|
+
* Also satisfies the {@link FirestoreQueryDocumentSnapshotPairsLoader} type since the implementation
|
|
912
|
+
* handles both {@link DocumentSnapshot} and {@link QueryDocumentSnapshot} inputs.
|
|
913
|
+
*
|
|
914
|
+
* @param accessorContext - Context that provides accessors for both default and transactional use
|
|
915
|
+
* @returns A loader function that converts snapshots to document-snapshot-data pairs
|
|
836
916
|
*/
|
|
837
917
|
function firestoreDocumentSnapshotPairsLoader(accessorContext) {
|
|
838
918
|
return (snapshots, transaction) => {
|
|
@@ -842,10 +922,15 @@ function firestoreDocumentSnapshotPairsLoader(accessorContext) {
|
|
|
842
922
|
};
|
|
843
923
|
}
|
|
844
924
|
/**
|
|
845
|
-
*
|
|
925
|
+
* Creates a {@link FirestoreDocumentSnapshotPairsLoaderInstance} bound to a specific accessor.
|
|
846
926
|
*
|
|
847
|
-
* @
|
|
848
|
-
* @
|
|
927
|
+
* The returned function converts a snapshot into a {@link FirestoreDocumentSnapshotDataPair} by:
|
|
928
|
+
* 1. Extracting data with `id`/`key` fields via {@link documentDataWithIdAndKey}
|
|
929
|
+
* 2. Loading the document from the snapshot's reference via `accessor.loadDocument()`
|
|
930
|
+
* 3. Combining all three into a single pair object
|
|
931
|
+
*
|
|
932
|
+
* @param accessor - The accessor to bind for document loading
|
|
933
|
+
* @returns A reusable function that converts snapshots to pairs using the bound accessor
|
|
849
934
|
*/
|
|
850
935
|
function firestoreDocumentSnapshotPairsLoaderInstance(accessor) {
|
|
851
936
|
const fn = ((snapshot) => {
|
|
@@ -862,10 +947,10 @@ function firestoreDocumentSnapshotPairsLoaderInstance(accessor) {
|
|
|
862
947
|
return fn;
|
|
863
948
|
}
|
|
864
949
|
/**
|
|
865
|
-
*
|
|
950
|
+
* Alias for {@link firestoreDocumentSnapshotPairsLoader}, typed specifically as a {@link FirestoreQueryDocumentSnapshotPairsLoader}.
|
|
866
951
|
*
|
|
867
|
-
*
|
|
868
|
-
*
|
|
952
|
+
* Use this when you know all input snapshots are from a query and want the stronger return type
|
|
953
|
+
* that guarantees `data` is non-nullish.
|
|
869
954
|
*/
|
|
870
955
|
const firestoreQueryDocumentSnapshotPairsLoader = firestoreDocumentSnapshotPairsLoader;
|
|
871
956
|
function documentData(snapshot, withId = false) {
|
|
@@ -887,11 +972,14 @@ function documentDataWithIdAndKey(snapshot) {
|
|
|
887
972
|
return data;
|
|
888
973
|
}
|
|
889
974
|
/**
|
|
890
|
-
*
|
|
975
|
+
* Mutates the input data object to include `id` and `key` fields from a {@link DocumentSnapshot}.
|
|
891
976
|
*
|
|
892
|
-
*
|
|
893
|
-
*
|
|
894
|
-
*
|
|
977
|
+
* Sets `data.id` to `snapshot.id` and `data.key` to `snapshot.ref.path`. The data object
|
|
978
|
+
* is modified in-place and also returned for chaining convenience.
|
|
979
|
+
*
|
|
980
|
+
* @param data - The data object to augment (mutated in-place)
|
|
981
|
+
* @param snapshot - Source of the `id` and `key` values
|
|
982
|
+
* @returns The same data object, now typed as {@link DocumentDataWithIdAndKey}
|
|
895
983
|
*/
|
|
896
984
|
function setIdAndKeyFromSnapshotOnDocumentData(data, snapshot) {
|
|
897
985
|
const target = data;
|
|
@@ -900,11 +988,15 @@ function setIdAndKeyFromSnapshotOnDocumentData(data, snapshot) {
|
|
|
900
988
|
return target;
|
|
901
989
|
}
|
|
902
990
|
/**
|
|
903
|
-
*
|
|
991
|
+
* Mutates the input data object to include `id` and `key` fields from a model reference.
|
|
904
992
|
*
|
|
905
|
-
* @
|
|
906
|
-
* @
|
|
907
|
-
*
|
|
993
|
+
* Similar to {@link setIdAndKeyFromSnapshotOnDocumentData}, but sources the values from a
|
|
994
|
+
* {@link FirestoreModelKeyRef} & {@link FirestoreModelIdRef} instead of a snapshot.
|
|
995
|
+
* The data object is modified in-place and also returned for chaining convenience.
|
|
996
|
+
*
|
|
997
|
+
* @param data - The data object to augment (mutated in-place)
|
|
998
|
+
* @param modelRef - Source of the `id` and `key` values
|
|
999
|
+
* @returns The same data object, now typed as {@link DocumentDataWithIdAndKey}
|
|
908
1000
|
*/
|
|
909
1001
|
function setIdAndKeyFromKeyIdRefOnDocumentData(data, modelRef) {
|
|
910
1002
|
const target = data;
|
|
@@ -913,47 +1005,156 @@ function setIdAndKeyFromKeyIdRefOnDocumentData(data, modelRef) {
|
|
|
913
1005
|
return target;
|
|
914
1006
|
}
|
|
915
1007
|
/**
|
|
916
|
-
*
|
|
1008
|
+
* Fetches a document's snapshot and passes it to a `use` callback, following the {@link UseAsync} pattern.
|
|
917
1009
|
*
|
|
918
|
-
*
|
|
919
|
-
*
|
|
920
|
-
*
|
|
921
|
-
* @
|
|
1010
|
+
* If `document` is nullish, the `use` callback is not invoked and `defaultValue` is returned instead.
|
|
1011
|
+
* If `document` exists but the snapshot is nullish (shouldn't happen in practice), `defaultValue` is also used.
|
|
1012
|
+
*
|
|
1013
|
+
* @param document - The document to fetch, or nullish to skip
|
|
1014
|
+
* @param use - Callback that receives the fetched snapshot and returns a result
|
|
1015
|
+
* @param defaultValue - Fallback value when `document` is nullish or the snapshot is unavailable
|
|
1016
|
+
* @returns The result of `use`, or the default value
|
|
922
1017
|
*/
|
|
923
1018
|
async function useDocumentSnapshot(document, use, defaultValue) {
|
|
924
1019
|
const snapshot = await document?.accessor.get();
|
|
925
1020
|
return util.useAsync(snapshot, use, defaultValue);
|
|
926
1021
|
}
|
|
927
1022
|
/**
|
|
928
|
-
*
|
|
1023
|
+
* Fetches a document's snapshot data (via `snapshot.data()`) and passes it to a `use` callback.
|
|
1024
|
+
*
|
|
1025
|
+
* Wraps {@link useDocumentSnapshot} with a mapping step that extracts raw data from the snapshot.
|
|
1026
|
+
* If the document doesn't exist (data is `undefined`), the `use` callback is not invoked
|
|
1027
|
+
* and `defaultValue` is returned instead.
|
|
1028
|
+
*
|
|
1029
|
+
* @param document - The document to fetch, or nullish to skip
|
|
1030
|
+
* @param use - Callback that receives the snapshot data and returns a result
|
|
1031
|
+
* @param defaultValue - Fallback value when the document is nullish or doesn't exist
|
|
1032
|
+
* @returns The result of `use`, or the default value
|
|
929
1033
|
*/
|
|
930
1034
|
const useDocumentSnapshotData = util.wrapUseAsyncFunction(useDocumentSnapshot, (x) => x.data());
|
|
931
1035
|
// MARK: Key Accessors
|
|
1036
|
+
/**
|
|
1037
|
+
* Extracts the document ID ({@link FirestoreModelId}) from a {@link FirestoreDocument}.
|
|
1038
|
+
*
|
|
1039
|
+
* Useful as a mapper function, e.g. `documents.map(firestoreModelIdFromDocument)`.
|
|
1040
|
+
*
|
|
1041
|
+
* @param document - The document to extract the ID from
|
|
1042
|
+
* @returns The document's ID (the last segment of its Firestore path)
|
|
1043
|
+
*/
|
|
932
1044
|
function firestoreModelIdFromDocument(document) {
|
|
933
1045
|
return document.id;
|
|
934
1046
|
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Extracts document IDs from an array of {@link FirestoreDocument}s.
|
|
1049
|
+
*
|
|
1050
|
+
* @param documents - Documents to extract IDs from
|
|
1051
|
+
* @returns Array of document IDs in the same order as the input
|
|
1052
|
+
*/
|
|
935
1053
|
function firestoreModelIdsFromDocuments(documents) {
|
|
936
1054
|
return documents.map(firestoreModelIdFromDocument);
|
|
937
1055
|
}
|
|
1056
|
+
/**
|
|
1057
|
+
* Extracts the full Firestore path ({@link FirestoreModelKey}) from a {@link FirestoreDocument}.
|
|
1058
|
+
*
|
|
1059
|
+
* Useful as a mapper function, e.g. `documents.map(firestoreModelKeyFromDocument)`.
|
|
1060
|
+
*
|
|
1061
|
+
* @param document - The document to extract the key from
|
|
1062
|
+
* @returns The document's full Firestore path (e.g. `'users/abc123'`)
|
|
1063
|
+
*/
|
|
938
1064
|
function firestoreModelKeyFromDocument(document) {
|
|
939
1065
|
return document.key;
|
|
940
1066
|
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Extracts full Firestore paths from an array of {@link FirestoreDocument}s.
|
|
1069
|
+
*
|
|
1070
|
+
* @param documents - Documents to extract keys from
|
|
1071
|
+
* @returns Array of full Firestore paths in the same order as the input
|
|
1072
|
+
*/
|
|
941
1073
|
function firestoreModelKeysFromDocuments(documents) {
|
|
942
1074
|
return documents.map(firestoreModelKeyFromDocument);
|
|
943
1075
|
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Extracts the {@link DocumentReference} from a {@link FirestoreDocument}.
|
|
1078
|
+
*
|
|
1079
|
+
* Useful as a mapper function, e.g. `documents.map(documentReferenceFromDocument)`.
|
|
1080
|
+
*
|
|
1081
|
+
* @param document - The document to extract the reference from
|
|
1082
|
+
* @returns The underlying Firestore document reference
|
|
1083
|
+
*/
|
|
944
1084
|
function documentReferenceFromDocument(document) {
|
|
945
1085
|
return document.documentRef;
|
|
946
1086
|
}
|
|
1087
|
+
/**
|
|
1088
|
+
* Extracts {@link DocumentReference}s from an array of {@link FirestoreDocument}s.
|
|
1089
|
+
*
|
|
1090
|
+
* @param documents - Documents to extract references from
|
|
1091
|
+
* @returns Array of document references in the same order as the input
|
|
1092
|
+
*/
|
|
947
1093
|
function documentReferencesFromDocuments(documents) {
|
|
948
1094
|
return documents.map(documentReferenceFromDocument);
|
|
949
1095
|
}
|
|
1096
|
+
/**
|
|
1097
|
+
* Creates a {@link LimitedFirestoreDocumentAccessorSnapshotCache} that wraps the given accessor
|
|
1098
|
+
* with an in-memory {@link Map} cache so that repeated loads for the same key return the cached
|
|
1099
|
+
* promise instead of re-reading from Firestore.
|
|
1100
|
+
*
|
|
1101
|
+
* The cache stores the promise itself (not the resolved value), which means concurrent requests
|
|
1102
|
+
* for the same key that arrive before the first read completes will also be deduplicated.
|
|
1103
|
+
*
|
|
1104
|
+
* The cache lives for the lifetime of the returned object and is never invalidated, so this is
|
|
1105
|
+
* best suited for short-lived scopes (e.g. a single request or batch operation) where stale reads
|
|
1106
|
+
* are acceptable.
|
|
1107
|
+
*
|
|
1108
|
+
* @param accessor - The accessor to wrap with caching behavior
|
|
1109
|
+
* @returns A {@link LimitedFirestoreDocumentAccessorSnapshotCache} backed by the given accessor
|
|
1110
|
+
*
|
|
1111
|
+
* @example
|
|
1112
|
+
* ```typescript
|
|
1113
|
+
* const cache = limitedFirestoreDocumentAccessorSnapshotCache(accessor);
|
|
1114
|
+
*
|
|
1115
|
+
* // First call reads from Firestore; second call returns cached result
|
|
1116
|
+
* const pair = await cache.getDocumentSnapshotDataPairForKey('users/abc123');
|
|
1117
|
+
* const samePair = await cache.getDocumentSnapshotDataPairForKey('users/abc123');
|
|
1118
|
+
*
|
|
1119
|
+
* // Batch fetch with automatic deduplication
|
|
1120
|
+
* const pairs = await cache.getDocumentSnapshotDataPairsWithDataForKeys(['users/abc', 'users/def']);
|
|
1121
|
+
*
|
|
1122
|
+
* // Access the underlying accessor directly
|
|
1123
|
+
* const doc = cache.accessor.loadDocumentForKey('users/xyz');
|
|
1124
|
+
* ```
|
|
1125
|
+
*/
|
|
1126
|
+
function limitedFirestoreDocumentAccessorSnapshotCache(accessor) {
|
|
1127
|
+
const cache = new Map();
|
|
1128
|
+
function getDocumentSnapshotDataPairForKey(key) {
|
|
1129
|
+
let cached = cache.get(key);
|
|
1130
|
+
if (!cached) {
|
|
1131
|
+
const document = accessor.loadDocumentForKey(key);
|
|
1132
|
+
cached = getDocumentSnapshotDataPair(document);
|
|
1133
|
+
cache.set(key, cached);
|
|
1134
|
+
}
|
|
1135
|
+
return cached;
|
|
1136
|
+
}
|
|
1137
|
+
async function getDocumentSnapshotDataPairsForKeys(keys) {
|
|
1138
|
+
return Promise.all(keys.map((key) => getDocumentSnapshotDataPairForKey(key)));
|
|
1139
|
+
}
|
|
1140
|
+
async function getDocumentSnapshotDataPairsWithDataForKeys(keys) {
|
|
1141
|
+
const pairs = await getDocumentSnapshotDataPairsForKeys(keys);
|
|
1142
|
+
return util.filterMaybeArrayValues(pairs.map((pair) => (pair.data != null ? pair : undefined)));
|
|
1143
|
+
}
|
|
1144
|
+
return {
|
|
1145
|
+
accessor,
|
|
1146
|
+
getDocumentSnapshotDataPairForKey,
|
|
1147
|
+
getDocumentSnapshotDataPairsForKeys,
|
|
1148
|
+
getDocumentSnapshotDataPairsWithDataForKeys
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
950
1151
|
|
|
951
1152
|
/**
|
|
952
1153
|
* Creates an Observable that emits arrays of document snapshots for multiple documents.
|
|
953
1154
|
*
|
|
954
1155
|
* This function streams the latest snapshots for each document in the provided array.
|
|
955
1156
|
* Each time any document in the array changes, a new array containing the latest snapshots
|
|
956
|
-
* of all documents is emitted.
|
|
1157
|
+
* of all documents is emitted.
|
|
957
1158
|
*
|
|
958
1159
|
* If the input array is empty, an Observable that emits an empty array is returned.
|
|
959
1160
|
*
|
|
@@ -962,7 +1163,25 @@ function documentReferencesFromDocuments(documents) {
|
|
|
962
1163
|
* @returns Observable that emits arrays of DocumentSnapshots whenever any document changes
|
|
963
1164
|
*/
|
|
964
1165
|
function latestSnapshotsFromDocuments(documents) {
|
|
965
|
-
return documents
|
|
1166
|
+
return mapLatestSnapshotsFromDocuments(documents, rxjs$1.map(util.MAP_IDENTITY));
|
|
1167
|
+
}
|
|
1168
|
+
/**
|
|
1169
|
+
* Creates an Observable that streams and transforms snapshots for multiple documents using `combineLatest`.
|
|
1170
|
+
*
|
|
1171
|
+
* Pipes each document's `accessor.stream()` through the provided `operator` before combining.
|
|
1172
|
+
* This ensures the transformation runs per-document when only one document changes, rather than
|
|
1173
|
+
* re-mapping all snapshots on every emission.
|
|
1174
|
+
*
|
|
1175
|
+
* {@link latestSnapshotsFromDocuments} delegates to this function with an identity operator.
|
|
1176
|
+
*
|
|
1177
|
+
* Returns `of([])` for an empty input array.
|
|
1178
|
+
*
|
|
1179
|
+
* @param documents - Documents to stream from
|
|
1180
|
+
* @param operator - RxJS operator applied to each document's snapshot stream individually
|
|
1181
|
+
* @returns Observable emitting an array of transformed values whenever any document changes
|
|
1182
|
+
*/
|
|
1183
|
+
function mapLatestSnapshotsFromDocuments(documents, operator) {
|
|
1184
|
+
return documents.length ? rxjs$1.combineLatest(documents.map((x) => x.accessor.stream().pipe(operator))) : rxjs$1.of([]);
|
|
966
1185
|
}
|
|
967
1186
|
/**
|
|
968
1187
|
* Creates an Observable that emits arrays of document data for multiple documents.
|
|
@@ -970,7 +1189,7 @@ function latestSnapshotsFromDocuments(documents) {
|
|
|
970
1189
|
* This function streams the latest data for each document in the provided array.
|
|
971
1190
|
* Each time any document in the array changes, a new array containing the latest data
|
|
972
1191
|
* of all documents is emitted. Document data includes both the document content and
|
|
973
|
-
* metadata like document ID and key.
|
|
1192
|
+
* metadata like document ID and key.
|
|
974
1193
|
*
|
|
975
1194
|
* Non-existent documents are filtered out of the results automatically.
|
|
976
1195
|
*
|
|
@@ -978,8 +1197,8 @@ function latestSnapshotsFromDocuments(documents) {
|
|
|
978
1197
|
* @param documents - Array of document instances to stream data for
|
|
979
1198
|
* @returns Observable that emits arrays of document data whenever any document changes
|
|
980
1199
|
*/
|
|
981
|
-
function
|
|
982
|
-
return latestSnapshotsFromDocuments(documents).pipe(dataFromDocumentSnapshots()
|
|
1200
|
+
function streamDocumentSnapshotsData(documents) {
|
|
1201
|
+
return latestSnapshotsFromDocuments(documents).pipe(dataFromDocumentSnapshots());
|
|
983
1202
|
}
|
|
984
1203
|
/**
|
|
985
1204
|
* Creates an RxJS operator that transforms arrays of DocumentSnapshots into arrays of document data.
|
|
@@ -994,6 +1213,53 @@ function latestDataFromDocuments(documents) {
|
|
|
994
1213
|
function dataFromDocumentSnapshots() {
|
|
995
1214
|
return rxjs$1.map((x) => getDataFromDocumentSnapshots(x));
|
|
996
1215
|
}
|
|
1216
|
+
// MARK: Streaming Document Snapshot Pairs
|
|
1217
|
+
/**
|
|
1218
|
+
* Streams {@link FirestoreDocumentSnapshotDataPair}s for multiple documents using `combineLatest`.
|
|
1219
|
+
*
|
|
1220
|
+
* Each document's `accessor.stream()` is individually piped to produce a `{ document, snapshot, data }` triplet,
|
|
1221
|
+
* then all streams are combined via `combineLatest`. This ensures the mapping only runs for the document
|
|
1222
|
+
* that actually changed. The `data` field has `id` and `key` fields injected via {@link documentDataWithIdAndKey},
|
|
1223
|
+
* and will be `undefined` for documents that don't exist in Firestore.
|
|
1224
|
+
*
|
|
1225
|
+
* Returns `of([])` for an empty input array.
|
|
1226
|
+
*
|
|
1227
|
+
* This is the streaming equivalent of {@link import('./document.utility').getDocumentSnapshotDataPairs}.
|
|
1228
|
+
*
|
|
1229
|
+
* @param documents - Documents to stream snapshot-data pairs for
|
|
1230
|
+
* @returns Observable emitting snapshot-data pairs whenever any document changes
|
|
1231
|
+
*/
|
|
1232
|
+
function streamDocumentSnapshotDataPairs(documents) {
|
|
1233
|
+
return documents.length
|
|
1234
|
+
? rxjs$1.combineLatest(documents.map((document) => document.accessor.stream().pipe(rxjs$1.map((snapshot) => ({
|
|
1235
|
+
document,
|
|
1236
|
+
snapshot,
|
|
1237
|
+
data: documentDataWithIdAndKey(snapshot)
|
|
1238
|
+
})))))
|
|
1239
|
+
: rxjs$1.of([]);
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Streams {@link FirestoreDocumentSnapshotDataPairWithData}s for multiple documents, filtering out non-existent documents.
|
|
1243
|
+
*
|
|
1244
|
+
* Builds on {@link streamDocumentSnapshotDataPairs} and filters each emission to include only pairs where
|
|
1245
|
+
* `data` is non-nullish (i.e., the document exists in Firestore). The filtered array may be shorter than
|
|
1246
|
+
* the input `documents` array and may change length over time as documents are created or deleted.
|
|
1247
|
+
*
|
|
1248
|
+
* Returns `of([])` for an empty input array.
|
|
1249
|
+
*
|
|
1250
|
+
* This is the streaming equivalent of {@link import('./document.utility').getDocumentSnapshotDataPairsWithData}.
|
|
1251
|
+
*
|
|
1252
|
+
* @param documents - Documents to stream snapshot-data pairs for
|
|
1253
|
+
* @returns Observable emitting snapshot-data pairs for existing documents only, whenever any document changes
|
|
1254
|
+
*/
|
|
1255
|
+
function streamDocumentSnapshotDataPairsWithData(documents) {
|
|
1256
|
+
return streamDocumentSnapshotDataPairs(documents).pipe(rxjs$1.map((pairs) => pairs.filter((pair) => pair.data != null)));
|
|
1257
|
+
}
|
|
1258
|
+
// MARK: Compat
|
|
1259
|
+
/**
|
|
1260
|
+
* @deprecated Use {@link streamDocumentSnapshotsData} instead.
|
|
1261
|
+
*/
|
|
1262
|
+
const latestDataFromDocuments = streamDocumentSnapshotsData;
|
|
997
1263
|
|
|
998
1264
|
// A set of copied types from @google-cloud/firestore and firebase/firestore to allow cross-compatability.
|
|
999
1265
|
/* eslint-disable */
|
|
@@ -2149,20 +2415,14 @@ function firebaseQueryItemAccumulator(iteration, mapItem) {
|
|
|
2149
2415
|
}
|
|
2150
2416
|
|
|
2151
2417
|
/**
|
|
2152
|
-
* Creates a
|
|
2418
|
+
* Creates a {@link FirestoreQueryConstraint} with the given type identifier and data.
|
|
2153
2419
|
*
|
|
2154
|
-
*
|
|
2155
|
-
* @
|
|
2156
|
-
* @param data - The constraint data
|
|
2157
|
-
* @returns A Firestore query constraint object
|
|
2158
|
-
*/
|
|
2159
|
-
/**
|
|
2160
|
-
* Creates a Firestore query constraint.
|
|
2420
|
+
* This is the low-level factory used by all constraint builder functions (e.g., {@link where},
|
|
2421
|
+
* {@link limit}, {@link orderBy}). Most callers should use those typed builders instead.
|
|
2161
2422
|
*
|
|
2162
|
-
* @
|
|
2163
|
-
* @param
|
|
2164
|
-
* @
|
|
2165
|
-
* @returns A Firestore query constraint object
|
|
2423
|
+
* @param type - The constraint type identifier (e.g., 'where', 'limit')
|
|
2424
|
+
* @param data - The constraint-specific configuration data
|
|
2425
|
+
* @returns A typed constraint object
|
|
2166
2426
|
*/
|
|
2167
2427
|
function firestoreQueryConstraint(type, data) {
|
|
2168
2428
|
return {
|
|
@@ -2662,6 +2922,17 @@ function filterDisallowedFirestoreItemPageIteratorInputConstraints(constraints)
|
|
|
2662
2922
|
* This value is used when no itemsPerPage is explicitly specified in the configuration.
|
|
2663
2923
|
*/
|
|
2664
2924
|
const DEFAULT_FIRESTORE_ITEM_PAGE_ITERATOR_ITEMS_PER_PAGE = 50;
|
|
2925
|
+
/**
|
|
2926
|
+
* Creates a {@link FirestoreItemPageIteratorDelegate} that handles cursor-based Firestore pagination.
|
|
2927
|
+
*
|
|
2928
|
+
* The delegate implements `loadItemsForPage` by:
|
|
2929
|
+
* 1. Retrieving the cursor document from the previous page's results
|
|
2930
|
+
* 2. Building a query with the configured constraints, `startAfter` cursor, and `limit`
|
|
2931
|
+
* 3. Executing the query and wrapping the results in a {@link FirestoreItemPageQueryResult}
|
|
2932
|
+
* with `reload()` and `stream()` capabilities
|
|
2933
|
+
*
|
|
2934
|
+
* @returns A delegate instance for use with {@link ItemPageIterator}
|
|
2935
|
+
*/
|
|
2665
2936
|
function makeFirestoreItemPageIteratorDelegate() {
|
|
2666
2937
|
return {
|
|
2667
2938
|
loadItemsForPage: (request) => {
|
|
@@ -2819,7 +3090,14 @@ function _firestoreItemPageIterationWithSnapshotIteration(snapshotIteration) {
|
|
|
2819
3090
|
return result;
|
|
2820
3091
|
}
|
|
2821
3092
|
/**
|
|
2822
|
-
* Creates a
|
|
3093
|
+
* Creates a factory function for generating fixed-set Firestore pagination instances.
|
|
3094
|
+
*
|
|
3095
|
+
* The returned factory takes an array of document references and an optional filter,
|
|
3096
|
+
* producing a pagination instance that iterates over those specific documents in pages.
|
|
3097
|
+
*
|
|
3098
|
+
* @param baseConfig - Base pagination configuration (query reference, driver, page size)
|
|
3099
|
+
* @param documentAccessor - Accessor used to load document snapshots from the references
|
|
3100
|
+
* @returns A factory function that creates fixed-set pagination instances
|
|
2823
3101
|
*/
|
|
2824
3102
|
function firestoreFixedItemPageIterationFactory(baseConfig, documentAccessor) {
|
|
2825
3103
|
return (items, filter) => {
|
|
@@ -2836,7 +3114,17 @@ function firestoreFixedItemPageIterationFactory(baseConfig, documentAccessor) {
|
|
|
2836
3114
|
};
|
|
2837
3115
|
}
|
|
2838
3116
|
/**
|
|
2839
|
-
* Creates a
|
|
3117
|
+
* Creates a pagination instance that iterates over a fixed set of document references.
|
|
3118
|
+
*
|
|
3119
|
+
* Unlike {@link firestoreItemPageIteration} which queries Firestore dynamically, this function
|
|
3120
|
+
* paginates through a pre-determined list of document references. Each page loads the next
|
|
3121
|
+
* slice of references via the document accessor and produces a synthetic {@link QuerySnapshot}.
|
|
3122
|
+
*
|
|
3123
|
+
* This is useful for paginating over known document sets (e.g., from a pre-computed list
|
|
3124
|
+
* of references) without executing Firestore queries.
|
|
3125
|
+
*
|
|
3126
|
+
* @param config - Configuration including the document references, accessor, and pagination settings
|
|
3127
|
+
* @returns A pagination instance that pages through the fixed reference set
|
|
2840
3128
|
*/
|
|
2841
3129
|
function firestoreFixedItemPageIteration(config) {
|
|
2842
3130
|
const { items, documentAccessor } = config;
|
|
@@ -3053,24 +3341,47 @@ function readFirestoreModelKeyFromDocumentSnapshot(snapshot) {
|
|
|
3053
3341
|
/**
|
|
3054
3342
|
* @module Firestore Query Iteration
|
|
3055
3343
|
*
|
|
3056
|
-
*
|
|
3057
|
-
*
|
|
3058
|
-
*
|
|
3059
|
-
*
|
|
3344
|
+
* Provides a layered system for iterating through Firestore query results using
|
|
3345
|
+
* cursor-based pagination ("checkpoints"). Each layer adds convenience on top of the
|
|
3346
|
+
* one below:
|
|
3347
|
+
*
|
|
3348
|
+
* 1. **Checkpoints** ({@link iterateFirestoreDocumentSnapshotCheckpoints}) — core pagination engine
|
|
3349
|
+
* 2. **Batches** ({@link iterateFirestoreDocumentSnapshotBatches}) — subdivides checkpoints into fixed-size batches
|
|
3350
|
+
* 3. **Snapshots** ({@link iterateFirestoreDocumentSnapshots}) — processes individual snapshots
|
|
3351
|
+
* 4. **Pairs** ({@link iterateFirestoreDocumentSnapshotPairs}) — loads typed document wrappers per snapshot
|
|
3352
|
+
*
|
|
3353
|
+
* Batch variants with document pairs are also available:
|
|
3354
|
+
* - {@link iterateFirestoreDocumentSnapshotPairBatches} — batch processing with typed document access
|
|
3355
|
+
*
|
|
3356
|
+
* All functions support configurable limits (`limitPerCheckpoint`, `totalSnapshotsLimit`),
|
|
3357
|
+
* concurrency (`maxParallelCheckpoints`), rate limiting (`waitBetweenCheckpoints`),
|
|
3358
|
+
* snapshot filtering, and repeat cursor detection.
|
|
3060
3359
|
*/
|
|
3061
3360
|
/**
|
|
3062
|
-
* Iterates through
|
|
3361
|
+
* Iterates through Firestore query results, loading each snapshot as a
|
|
3362
|
+
* {@link FirestoreDocumentSnapshotDataPairWithData} before processing.
|
|
3063
3363
|
*
|
|
3064
|
-
*
|
|
3065
|
-
*
|
|
3066
|
-
*
|
|
3067
|
-
*
|
|
3364
|
+
* Built on {@link iterateFirestoreDocumentSnapshots}, this adds an automatic document
|
|
3365
|
+
* loading step: each raw snapshot is resolved through the `documentAccessor` to produce
|
|
3366
|
+
* a pair containing both the typed {@link FirestoreDocument} and its snapshot data.
|
|
3367
|
+
* This is the highest-level iteration function — use it when your callback needs
|
|
3368
|
+
* document-level operations (updates, deletes) alongside the snapshot data.
|
|
3068
3369
|
*
|
|
3069
|
-
* @
|
|
3070
|
-
* @
|
|
3071
|
-
*
|
|
3072
|
-
* @
|
|
3073
|
-
*
|
|
3370
|
+
* @param config - Iteration config including the document accessor and per-pair callback
|
|
3371
|
+
* @returns Checkpoint-level statistics (total checkpoints, snapshots visited, limit status)
|
|
3372
|
+
*
|
|
3373
|
+
* @example
|
|
3374
|
+
* ```typescript
|
|
3375
|
+
* const result = await iterateFirestoreDocumentSnapshotPairs({
|
|
3376
|
+
* queryFactory,
|
|
3377
|
+
* constraintsFactory: [where('status', '==', 'pending')],
|
|
3378
|
+
* limitPerCheckpoint: 100,
|
|
3379
|
+
* documentAccessor: collection.documentAccessor(),
|
|
3380
|
+
* iterateSnapshotPair: async (pair) => {
|
|
3381
|
+
* await pair.document.accessor.set({ ...pair.data, status: 'processed' });
|
|
3382
|
+
* }
|
|
3383
|
+
* });
|
|
3384
|
+
* ```
|
|
3074
3385
|
*/
|
|
3075
3386
|
async function iterateFirestoreDocumentSnapshotPairs(config) {
|
|
3076
3387
|
const { iterateSnapshotPair, documentAccessor } = config;
|
|
@@ -3084,16 +3395,32 @@ async function iterateFirestoreDocumentSnapshotPairs(config) {
|
|
|
3084
3395
|
});
|
|
3085
3396
|
}
|
|
3086
3397
|
/**
|
|
3087
|
-
* Iterates through
|
|
3398
|
+
* Iterates through Firestore query results, processing each document snapshot individually.
|
|
3088
3399
|
*
|
|
3089
|
-
*
|
|
3090
|
-
*
|
|
3091
|
-
*
|
|
3400
|
+
* Built on {@link iterateFirestoreDocumentSnapshotBatches} with `maxParallelCheckpoints: 1`,
|
|
3401
|
+
* this unwraps each checkpoint's snapshots and processes them one-by-one via
|
|
3402
|
+
* {@link performAsyncTasks} (sequential by default). Use `snapshotsPerformTasksConfig`
|
|
3403
|
+
* to enable parallel snapshot processing within each checkpoint.
|
|
3092
3404
|
*
|
|
3093
|
-
*
|
|
3094
|
-
* @
|
|
3095
|
-
*
|
|
3096
|
-
* @
|
|
3405
|
+
* For document-level operations (needing the typed {@link FirestoreDocument} wrapper),
|
|
3406
|
+
* use {@link iterateFirestoreDocumentSnapshotPairs} instead.
|
|
3407
|
+
*
|
|
3408
|
+
* @param config - Iteration config including the per-snapshot callback
|
|
3409
|
+
* @returns Checkpoint-level statistics (total checkpoints, snapshots visited, limit status)
|
|
3410
|
+
*
|
|
3411
|
+
* @example
|
|
3412
|
+
* ```typescript
|
|
3413
|
+
* const result = await iterateFirestoreDocumentSnapshots({
|
|
3414
|
+
* queryFactory,
|
|
3415
|
+
* constraintsFactory: [where('active', '==', true)],
|
|
3416
|
+
* limitPerCheckpoint: 200,
|
|
3417
|
+
* totalSnapshotsLimit: 1000,
|
|
3418
|
+
* iterateSnapshot: async (snapshot) => {
|
|
3419
|
+
* const data = snapshot.data();
|
|
3420
|
+
* await externalApi.sync(data);
|
|
3421
|
+
* }
|
|
3422
|
+
* });
|
|
3423
|
+
* ```
|
|
3097
3424
|
*/
|
|
3098
3425
|
async function iterateFirestoreDocumentSnapshots(config) {
|
|
3099
3426
|
const { iterateSnapshot, performTasksConfig, snapshotsPerformTasksConfig } = config;
|
|
@@ -3110,10 +3437,32 @@ async function iterateFirestoreDocumentSnapshots(config) {
|
|
|
3110
3437
|
});
|
|
3111
3438
|
}
|
|
3112
3439
|
/**
|
|
3113
|
-
* Iterates through
|
|
3440
|
+
* Iterates through Firestore query results in batches, loading each batch as
|
|
3441
|
+
* {@link FirestoreDocumentSnapshotDataPairWithData} instances before processing.
|
|
3114
3442
|
*
|
|
3115
|
-
* @
|
|
3116
|
-
*
|
|
3443
|
+
* Built on {@link iterateFirestoreDocumentSnapshotBatches} with `maxParallelCheckpoints: 1`.
|
|
3444
|
+
* Each batch of raw snapshots is resolved through the `documentAccessor` to produce
|
|
3445
|
+
* typed document-snapshot pairs. Use this when you need batch-level operations with
|
|
3446
|
+
* typed document access (e.g., bulk updates, batch writes).
|
|
3447
|
+
*
|
|
3448
|
+
* @param config - Iteration config including the document accessor and per-batch callback
|
|
3449
|
+
* @returns Checkpoint-level statistics (total checkpoints, snapshots visited, limit status)
|
|
3450
|
+
*
|
|
3451
|
+
* @example
|
|
3452
|
+
* ```typescript
|
|
3453
|
+
* const result = await iterateFirestoreDocumentSnapshotPairBatches({
|
|
3454
|
+
* queryFactory,
|
|
3455
|
+
* constraintsFactory: [where('needsMigration', '==', true)],
|
|
3456
|
+
* limitPerCheckpoint: 500,
|
|
3457
|
+
* batchSize: 50,
|
|
3458
|
+
* documentAccessor: collection.documentAccessor(),
|
|
3459
|
+
* iterateSnapshotPairsBatch: async (pairs, batchIndex) => {
|
|
3460
|
+
* const writeBatch = firestore.batch();
|
|
3461
|
+
* pairs.forEach((pair) => writeBatch.update(pair.document.documentRef, { migrated: true }));
|
|
3462
|
+
* await writeBatch.commit();
|
|
3463
|
+
* }
|
|
3464
|
+
* });
|
|
3465
|
+
* ```
|
|
3117
3466
|
*/
|
|
3118
3467
|
async function iterateFirestoreDocumentSnapshotPairBatches(config) {
|
|
3119
3468
|
const { iterateSnapshotPairsBatch, documentAccessor } = config;
|
|
@@ -3134,10 +3483,32 @@ async function iterateFirestoreDocumentSnapshotPairBatches(config) {
|
|
|
3134
3483
|
*/
|
|
3135
3484
|
const DEFAULT_ITERATE_FIRESTORE_DOCUMENT_SNAPSHOT_BATCHES_BATCH_SIZE = 25;
|
|
3136
3485
|
/**
|
|
3137
|
-
* Iterates through
|
|
3486
|
+
* Iterates through Firestore query results by subdividing each checkpoint into smaller batches.
|
|
3138
3487
|
*
|
|
3139
|
-
* @
|
|
3140
|
-
*
|
|
3488
|
+
* Built on {@link iterateFirestoreDocumentSnapshotCheckpoints}, this function takes each
|
|
3489
|
+
* checkpoint's snapshots and splits them into batches (default size: 25). Batches are
|
|
3490
|
+
* processed via {@link performAsyncTasks}, sequential by default. Use this when operations
|
|
3491
|
+
* have size limits (e.g., Firestore batch writes) or benefit from controlled chunk sizes.
|
|
3492
|
+
*
|
|
3493
|
+
* For per-snapshot processing, use {@link iterateFirestoreDocumentSnapshots}.
|
|
3494
|
+
* For batch processing with typed document pairs, use {@link iterateFirestoreDocumentSnapshotPairBatches}.
|
|
3495
|
+
*
|
|
3496
|
+
* @param config - Iteration config including batch size and per-batch callback
|
|
3497
|
+
* @returns Checkpoint-level statistics (total checkpoints, snapshots visited, limit status)
|
|
3498
|
+
*
|
|
3499
|
+
* @example
|
|
3500
|
+
* ```typescript
|
|
3501
|
+
* const result = await iterateFirestoreDocumentSnapshotBatches({
|
|
3502
|
+
* queryFactory,
|
|
3503
|
+
* constraintsFactory: [where('type', '==', 'order')],
|
|
3504
|
+
* limitPerCheckpoint: 500,
|
|
3505
|
+
* batchSize: 100,
|
|
3506
|
+
* iterateSnapshotBatch: async (snapshots, batchIndex) => {
|
|
3507
|
+
* const data = snapshots.map((s) => s.data());
|
|
3508
|
+
* await analytics.trackBatch(data);
|
|
3509
|
+
* }
|
|
3510
|
+
* });
|
|
3511
|
+
* ```
|
|
3141
3512
|
*/
|
|
3142
3513
|
async function iterateFirestoreDocumentSnapshotBatches(config) {
|
|
3143
3514
|
const { iterateSnapshotBatch, batchSizeForSnapshots: inputBatchSizeForSnapshots, performTasksConfig, batchSize: inputBatchSize } = config;
|
|
@@ -3163,29 +3534,75 @@ async function iterateFirestoreDocumentSnapshotBatches(config) {
|
|
|
3163
3534
|
});
|
|
3164
3535
|
}
|
|
3165
3536
|
/**
|
|
3166
|
-
* Creates a
|
|
3537
|
+
* Creates a checkpoint filter that deduplicates documents across checkpoints.
|
|
3167
3538
|
*
|
|
3168
|
-
* Repeat documents can
|
|
3169
|
-
*
|
|
3539
|
+
* Repeat documents can appear when a document is updated during iteration and
|
|
3540
|
+
* re-matches the query in a subsequent checkpoint. This factory returns a stateful
|
|
3541
|
+
* filter that tracks seen document keys and removes duplicates.
|
|
3170
3542
|
*
|
|
3171
|
-
*
|
|
3172
|
-
*
|
|
3543
|
+
* The filter maintains state across checkpoints — use a single instance for the
|
|
3544
|
+
* entire iteration run. Pair with `handleRepeatCursor: false` to also terminate
|
|
3545
|
+
* iteration when cursor-level repeats are detected.
|
|
3546
|
+
*
|
|
3547
|
+
* @param readKeyFunction - Extracts a unique key from each snapshot; defaults to `snapshot.id`
|
|
3548
|
+
* @returns A stateful filter function suitable for `filterCheckpointSnapshots`
|
|
3549
|
+
*
|
|
3550
|
+
* @example
|
|
3551
|
+
* ```typescript
|
|
3552
|
+
* const result = await iterateFirestoreDocumentSnapshotCheckpoints({
|
|
3553
|
+
* queryFactory,
|
|
3554
|
+
* constraintsFactory: [orderBy('updatedAt')],
|
|
3555
|
+
* limitPerCheckpoint: 100,
|
|
3556
|
+
* filterCheckpointSnapshots: filterRepeatCheckpointSnapshots(),
|
|
3557
|
+
* handleRepeatCursor: false,
|
|
3558
|
+
* iterateCheckpoint: async (snapshots) => {
|
|
3559
|
+
* return snapshots.map((s) => s.data());
|
|
3560
|
+
* }
|
|
3561
|
+
* });
|
|
3562
|
+
* ```
|
|
3173
3563
|
*/
|
|
3174
3564
|
function filterRepeatCheckpointSnapshots(readKeyFunction = (x) => x.id) {
|
|
3175
3565
|
const allowOnceFilter = util.allowValueOnceFilter(readKeyFunction);
|
|
3176
3566
|
return async (snapshots) => snapshots.filter(allowOnceFilter);
|
|
3177
3567
|
}
|
|
3178
3568
|
/**
|
|
3179
|
-
*
|
|
3569
|
+
* Core cursor-based pagination engine for iterating through Firestore query results.
|
|
3180
3570
|
*
|
|
3181
|
-
* This is the
|
|
3182
|
-
*
|
|
3183
|
-
*
|
|
3571
|
+
* This is the foundational function in the Firestore iteration hierarchy. It drives
|
|
3572
|
+
* sequential cursor-based pagination: each "checkpoint" executes a Firestore query,
|
|
3573
|
+
* uses the last document as a `startAfter` cursor for the next query, and passes
|
|
3574
|
+
* results to the `iterateCheckpoint` callback.
|
|
3184
3575
|
*
|
|
3185
|
-
*
|
|
3186
|
-
*
|
|
3187
|
-
*
|
|
3188
|
-
*
|
|
3576
|
+
* The iteration loop continues until one of these conditions is met:
|
|
3577
|
+
* - A query returns no results (no more matching documents)
|
|
3578
|
+
* - The `totalSnapshotsLimit` is reached
|
|
3579
|
+
* - A repeat cursor is detected and `handleRepeatCursor` returns `false`
|
|
3580
|
+
* - The effective `limitPerCheckpoint` calculates to 0 remaining
|
|
3581
|
+
*
|
|
3582
|
+
* Higher-level functions build on this:
|
|
3583
|
+
* - {@link iterateFirestoreDocumentSnapshotBatches} — subdivides checkpoints into smaller batches
|
|
3584
|
+
* - {@link iterateFirestoreDocumentSnapshots} — processes one snapshot at a time
|
|
3585
|
+
* - {@link iterateFirestoreDocumentSnapshotPairs} — loads typed document wrappers per snapshot
|
|
3586
|
+
*
|
|
3587
|
+
* @param config - Complete configuration for pagination, processing, and termination behavior
|
|
3588
|
+
* @returns Statistics including total checkpoints executed, snapshots visited, and whether the limit was hit
|
|
3589
|
+
*
|
|
3590
|
+
* @example
|
|
3591
|
+
* ```typescript
|
|
3592
|
+
* const result = await iterateFirestoreDocumentSnapshotCheckpoints({
|
|
3593
|
+
* queryFactory,
|
|
3594
|
+
* constraintsFactory: [where('createdAt', '<=', cutoffDate), orderBy('createdAt')],
|
|
3595
|
+
* limitPerCheckpoint: 200,
|
|
3596
|
+
* totalSnapshotsLimit: 5000,
|
|
3597
|
+
* handleRepeatCursor: false,
|
|
3598
|
+
* iterateCheckpoint: async (snapshots, querySnapshot) => {
|
|
3599
|
+
* return snapshots.map((s) => ({ id: s.id, data: s.data() }));
|
|
3600
|
+
* },
|
|
3601
|
+
* useCheckpointResult: (result) => {
|
|
3602
|
+
* console.log(`Checkpoint ${result.i}: processed ${result.docSnapshots.length} docs`);
|
|
3603
|
+
* }
|
|
3604
|
+
* });
|
|
3605
|
+
* ```
|
|
3189
3606
|
*/
|
|
3190
3607
|
async function iterateFirestoreDocumentSnapshotCheckpoints(config) {
|
|
3191
3608
|
const { iterateCheckpoint, filterCheckpointSnapshots: inputFilterCheckpointSnapshot, handleRepeatCursor: inputHandleRepeatCursor, waitBetweenCheckpoints, useCheckpointResult, constraintsFactory: inputConstraintsFactory, dynamicConstraints: inputDynamicConstraints, queryFactory, maxParallelCheckpoints = 1, limitPerCheckpoint: inputLimitPerCheckpoint, totalSnapshotsLimit: inputTotalSnapshotsLimit } = config;
|
|
@@ -3288,13 +3705,20 @@ async function iterateFirestoreDocumentSnapshotCheckpoints(config) {
|
|
|
3288
3705
|
}
|
|
3289
3706
|
// MARK: Utility
|
|
3290
3707
|
/**
|
|
3291
|
-
* Creates a filter that allows each document snapshot
|
|
3708
|
+
* Creates a stateful filter that allows each document snapshot through only once,
|
|
3709
|
+
* keyed by its full Firestore model path.
|
|
3292
3710
|
*
|
|
3293
|
-
*
|
|
3294
|
-
*
|
|
3711
|
+
* Unlike {@link filterRepeatCheckpointSnapshots} which uses document ID by default,
|
|
3712
|
+
* this filter uses the full document path ({@link readFirestoreModelKeyFromDocumentSnapshot}),
|
|
3713
|
+
* making it suitable for cross-collection iteration where document IDs alone may collide.
|
|
3295
3714
|
*
|
|
3296
|
-
* @
|
|
3297
|
-
*
|
|
3715
|
+
* @returns A reusable filter function that passes each unique document path exactly once
|
|
3716
|
+
*
|
|
3717
|
+
* @example
|
|
3718
|
+
* ```typescript
|
|
3719
|
+
* const onceFilter = allowDocumentSnapshotWithPathOnceFilter();
|
|
3720
|
+
* const uniqueSnapshots = allSnapshots.filter(onceFilter);
|
|
3721
|
+
* ```
|
|
3298
3722
|
*/
|
|
3299
3723
|
function allowDocumentSnapshotWithPathOnceFilter() {
|
|
3300
3724
|
return util.allowValueOnceFilter(readFirestoreModelKeyFromDocumentSnapshot);
|
|
@@ -9701,6 +10125,7 @@ exports.limit = limit;
|
|
|
9701
10125
|
exports.limitToLast = limitToLast;
|
|
9702
10126
|
exports.limitUploadFileTypeDeterminer = limitUploadFileTypeDeterminer;
|
|
9703
10127
|
exports.limitedFirestoreDocumentAccessorFactory = limitedFirestoreDocumentAccessorFactory;
|
|
10128
|
+
exports.limitedFirestoreDocumentAccessorSnapshotCache = limitedFirestoreDocumentAccessorSnapshotCache;
|
|
9704
10129
|
exports.loadAllFirestoreDocumentSnapshot = loadAllFirestoreDocumentSnapshot;
|
|
9705
10130
|
exports.loadAllFirestoreDocumentSnapshotPairs = loadAllFirestoreDocumentSnapshotPairs;
|
|
9706
10131
|
exports.loadDocumentsForDocumentReferences = loadDocumentsForDocumentReferences;
|
|
@@ -9723,6 +10148,7 @@ exports.makeRootSingleItemFirestoreCollection = makeRootSingleItemFirestoreColle
|
|
|
9723
10148
|
exports.makeSingleItemFirestoreCollection = makeSingleItemFirestoreCollection;
|
|
9724
10149
|
exports.mapDataFromSnapshot = mapDataFromSnapshot;
|
|
9725
10150
|
exports.mapHttpsCallable = mapHttpsCallable;
|
|
10151
|
+
exports.mapLatestSnapshotsFromDocuments = mapLatestSnapshotsFromDocuments;
|
|
9726
10152
|
exports.mergeNotificationBoxRecipientTemplateConfigRecords = mergeNotificationBoxRecipientTemplateConfigRecords;
|
|
9727
10153
|
exports.mergeNotificationBoxRecipientTemplateConfigs = mergeNotificationBoxRecipientTemplateConfigs;
|
|
9728
10154
|
exports.mergeNotificationBoxRecipients = mergeNotificationBoxRecipients;
|
|
@@ -9855,6 +10281,9 @@ exports.storageListFilesResultFactory = storageListFilesResultFactory;
|
|
|
9855
10281
|
exports.storageListFilesResultHasNoNextError = storageListFilesResultHasNoNextError;
|
|
9856
10282
|
exports.storagePathFactory = storagePathFactory;
|
|
9857
10283
|
exports.storedFileReaderFactory = storedFileReaderFactory;
|
|
10284
|
+
exports.streamDocumentSnapshotDataPairs = streamDocumentSnapshotDataPairs;
|
|
10285
|
+
exports.streamDocumentSnapshotDataPairsWithData = streamDocumentSnapshotDataPairsWithData;
|
|
10286
|
+
exports.streamDocumentSnapshotsData = streamDocumentSnapshotsData;
|
|
9858
10287
|
exports.streamFromOnSnapshot = streamFromOnSnapshot;
|
|
9859
10288
|
exports.systemStateCollectionReference = systemStateCollectionReference;
|
|
9860
10289
|
exports.systemStateConverter = systemStateConverter;
|