@dereekb/firebase 13.0.6 → 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 +281 -61
- package/index.cjs.js.map +1 -1
- package/index.esm.js +280 -62
- package/index.esm.js.map +1 -1
- package/package.json +5 -5
- package/src/lib/common/firestore/accessor/document.rxjs.d.ts +5 -1
- package/src/lib/common/firestore/accessor/document.utility.d.ts +89 -0
- 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 +85 -4
- package/test/index.esm.js +86 -5
- package/test/package.json +6 -6
package/index.cjs.js
CHANGED
|
@@ -1093,6 +1093,61 @@ function documentReferenceFromDocument(document) {
|
|
|
1093
1093
|
function documentReferencesFromDocuments(documents) {
|
|
1094
1094
|
return documents.map(documentReferenceFromDocument);
|
|
1095
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
|
+
}
|
|
1096
1151
|
|
|
1097
1152
|
/**
|
|
1098
1153
|
* Creates an Observable that emits arrays of document snapshots for multiple documents.
|
|
@@ -1142,7 +1197,7 @@ function mapLatestSnapshotsFromDocuments(documents, operator) {
|
|
|
1142
1197
|
* @param documents - Array of document instances to stream data for
|
|
1143
1198
|
* @returns Observable that emits arrays of document data whenever any document changes
|
|
1144
1199
|
*/
|
|
1145
|
-
function
|
|
1200
|
+
function streamDocumentSnapshotsData(documents) {
|
|
1146
1201
|
return latestSnapshotsFromDocuments(documents).pipe(dataFromDocumentSnapshots());
|
|
1147
1202
|
}
|
|
1148
1203
|
/**
|
|
@@ -1200,6 +1255,11 @@ function streamDocumentSnapshotDataPairs(documents) {
|
|
|
1200
1255
|
function streamDocumentSnapshotDataPairsWithData(documents) {
|
|
1201
1256
|
return streamDocumentSnapshotDataPairs(documents).pipe(rxjs$1.map((pairs) => pairs.filter((pair) => pair.data != null)));
|
|
1202
1257
|
}
|
|
1258
|
+
// MARK: Compat
|
|
1259
|
+
/**
|
|
1260
|
+
* @deprecated Use {@link streamDocumentSnapshotsData} instead.
|
|
1261
|
+
*/
|
|
1262
|
+
const latestDataFromDocuments = streamDocumentSnapshotsData;
|
|
1203
1263
|
|
|
1204
1264
|
// A set of copied types from @google-cloud/firestore and firebase/firestore to allow cross-compatability.
|
|
1205
1265
|
/* eslint-disable */
|
|
@@ -2355,20 +2415,14 @@ function firebaseQueryItemAccumulator(iteration, mapItem) {
|
|
|
2355
2415
|
}
|
|
2356
2416
|
|
|
2357
2417
|
/**
|
|
2358
|
-
* Creates a
|
|
2418
|
+
* Creates a {@link FirestoreQueryConstraint} with the given type identifier and data.
|
|
2359
2419
|
*
|
|
2360
|
-
*
|
|
2361
|
-
* @
|
|
2362
|
-
* @param data - The constraint data
|
|
2363
|
-
* @returns A Firestore query constraint object
|
|
2364
|
-
*/
|
|
2365
|
-
/**
|
|
2366
|
-
* 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.
|
|
2367
2422
|
*
|
|
2368
|
-
* @
|
|
2369
|
-
* @param
|
|
2370
|
-
* @
|
|
2371
|
-
* @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
|
|
2372
2426
|
*/
|
|
2373
2427
|
function firestoreQueryConstraint(type, data) {
|
|
2374
2428
|
return {
|
|
@@ -2868,6 +2922,17 @@ function filterDisallowedFirestoreItemPageIteratorInputConstraints(constraints)
|
|
|
2868
2922
|
* This value is used when no itemsPerPage is explicitly specified in the configuration.
|
|
2869
2923
|
*/
|
|
2870
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
|
+
*/
|
|
2871
2936
|
function makeFirestoreItemPageIteratorDelegate() {
|
|
2872
2937
|
return {
|
|
2873
2938
|
loadItemsForPage: (request) => {
|
|
@@ -3025,7 +3090,14 @@ function _firestoreItemPageIterationWithSnapshotIteration(snapshotIteration) {
|
|
|
3025
3090
|
return result;
|
|
3026
3091
|
}
|
|
3027
3092
|
/**
|
|
3028
|
-
* 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
|
|
3029
3101
|
*/
|
|
3030
3102
|
function firestoreFixedItemPageIterationFactory(baseConfig, documentAccessor) {
|
|
3031
3103
|
return (items, filter) => {
|
|
@@ -3042,7 +3114,17 @@ function firestoreFixedItemPageIterationFactory(baseConfig, documentAccessor) {
|
|
|
3042
3114
|
};
|
|
3043
3115
|
}
|
|
3044
3116
|
/**
|
|
3045
|
-
* 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
|
|
3046
3128
|
*/
|
|
3047
3129
|
function firestoreFixedItemPageIteration(config) {
|
|
3048
3130
|
const { items, documentAccessor } = config;
|
|
@@ -3259,24 +3341,47 @@ function readFirestoreModelKeyFromDocumentSnapshot(snapshot) {
|
|
|
3259
3341
|
/**
|
|
3260
3342
|
* @module Firestore Query Iteration
|
|
3261
3343
|
*
|
|
3262
|
-
*
|
|
3263
|
-
*
|
|
3264
|
-
*
|
|
3265
|
-
*
|
|
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.
|
|
3266
3359
|
*/
|
|
3267
3360
|
/**
|
|
3268
|
-
* Iterates through
|
|
3361
|
+
* Iterates through Firestore query results, loading each snapshot as a
|
|
3362
|
+
* {@link FirestoreDocumentSnapshotDataPairWithData} before processing.
|
|
3269
3363
|
*
|
|
3270
|
-
*
|
|
3271
|
-
*
|
|
3272
|
-
*
|
|
3273
|
-
*
|
|
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.
|
|
3274
3369
|
*
|
|
3275
|
-
* @
|
|
3276
|
-
* @
|
|
3277
|
-
*
|
|
3278
|
-
* @
|
|
3279
|
-
*
|
|
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
|
+
* ```
|
|
3280
3385
|
*/
|
|
3281
3386
|
async function iterateFirestoreDocumentSnapshotPairs(config) {
|
|
3282
3387
|
const { iterateSnapshotPair, documentAccessor } = config;
|
|
@@ -3290,16 +3395,32 @@ async function iterateFirestoreDocumentSnapshotPairs(config) {
|
|
|
3290
3395
|
});
|
|
3291
3396
|
}
|
|
3292
3397
|
/**
|
|
3293
|
-
* Iterates through
|
|
3398
|
+
* Iterates through Firestore query results, processing each document snapshot individually.
|
|
3294
3399
|
*
|
|
3295
|
-
*
|
|
3296
|
-
*
|
|
3297
|
-
*
|
|
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.
|
|
3298
3404
|
*
|
|
3299
|
-
*
|
|
3300
|
-
* @
|
|
3301
|
-
*
|
|
3302
|
-
* @
|
|
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
|
+
* ```
|
|
3303
3424
|
*/
|
|
3304
3425
|
async function iterateFirestoreDocumentSnapshots(config) {
|
|
3305
3426
|
const { iterateSnapshot, performTasksConfig, snapshotsPerformTasksConfig } = config;
|
|
@@ -3316,10 +3437,32 @@ async function iterateFirestoreDocumentSnapshots(config) {
|
|
|
3316
3437
|
});
|
|
3317
3438
|
}
|
|
3318
3439
|
/**
|
|
3319
|
-
* Iterates through
|
|
3440
|
+
* Iterates through Firestore query results in batches, loading each batch as
|
|
3441
|
+
* {@link FirestoreDocumentSnapshotDataPairWithData} instances before processing.
|
|
3320
3442
|
*
|
|
3321
|
-
* @
|
|
3322
|
-
*
|
|
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
|
+
* ```
|
|
3323
3466
|
*/
|
|
3324
3467
|
async function iterateFirestoreDocumentSnapshotPairBatches(config) {
|
|
3325
3468
|
const { iterateSnapshotPairsBatch, documentAccessor } = config;
|
|
@@ -3340,10 +3483,32 @@ async function iterateFirestoreDocumentSnapshotPairBatches(config) {
|
|
|
3340
3483
|
*/
|
|
3341
3484
|
const DEFAULT_ITERATE_FIRESTORE_DOCUMENT_SNAPSHOT_BATCHES_BATCH_SIZE = 25;
|
|
3342
3485
|
/**
|
|
3343
|
-
* Iterates through
|
|
3486
|
+
* Iterates through Firestore query results by subdividing each checkpoint into smaller batches.
|
|
3344
3487
|
*
|
|
3345
|
-
* @
|
|
3346
|
-
*
|
|
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
|
+
* ```
|
|
3347
3512
|
*/
|
|
3348
3513
|
async function iterateFirestoreDocumentSnapshotBatches(config) {
|
|
3349
3514
|
const { iterateSnapshotBatch, batchSizeForSnapshots: inputBatchSizeForSnapshots, performTasksConfig, batchSize: inputBatchSize } = config;
|
|
@@ -3369,29 +3534,75 @@ async function iterateFirestoreDocumentSnapshotBatches(config) {
|
|
|
3369
3534
|
});
|
|
3370
3535
|
}
|
|
3371
3536
|
/**
|
|
3372
|
-
* Creates a
|
|
3537
|
+
* Creates a checkpoint filter that deduplicates documents across checkpoints.
|
|
3373
3538
|
*
|
|
3374
|
-
* Repeat documents can
|
|
3375
|
-
*
|
|
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.
|
|
3376
3542
|
*
|
|
3377
|
-
*
|
|
3378
|
-
*
|
|
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
|
+
* ```
|
|
3379
3563
|
*/
|
|
3380
3564
|
function filterRepeatCheckpointSnapshots(readKeyFunction = (x) => x.id) {
|
|
3381
3565
|
const allowOnceFilter = util.allowValueOnceFilter(readKeyFunction);
|
|
3382
3566
|
return async (snapshots) => snapshots.filter(allowOnceFilter);
|
|
3383
3567
|
}
|
|
3384
3568
|
/**
|
|
3385
|
-
*
|
|
3569
|
+
* Core cursor-based pagination engine for iterating through Firestore query results.
|
|
3386
3570
|
*
|
|
3387
|
-
* This is the
|
|
3388
|
-
*
|
|
3389
|
-
*
|
|
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.
|
|
3390
3575
|
*
|
|
3391
|
-
*
|
|
3392
|
-
*
|
|
3393
|
-
*
|
|
3394
|
-
*
|
|
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
|
+
* ```
|
|
3395
3606
|
*/
|
|
3396
3607
|
async function iterateFirestoreDocumentSnapshotCheckpoints(config) {
|
|
3397
3608
|
const { iterateCheckpoint, filterCheckpointSnapshots: inputFilterCheckpointSnapshot, handleRepeatCursor: inputHandleRepeatCursor, waitBetweenCheckpoints, useCheckpointResult, constraintsFactory: inputConstraintsFactory, dynamicConstraints: inputDynamicConstraints, queryFactory, maxParallelCheckpoints = 1, limitPerCheckpoint: inputLimitPerCheckpoint, totalSnapshotsLimit: inputTotalSnapshotsLimit } = config;
|
|
@@ -3494,13 +3705,20 @@ async function iterateFirestoreDocumentSnapshotCheckpoints(config) {
|
|
|
3494
3705
|
}
|
|
3495
3706
|
// MARK: Utility
|
|
3496
3707
|
/**
|
|
3497
|
-
* 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.
|
|
3498
3710
|
*
|
|
3499
|
-
*
|
|
3500
|
-
*
|
|
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.
|
|
3501
3714
|
*
|
|
3502
|
-
* @
|
|
3503
|
-
*
|
|
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
|
+
* ```
|
|
3504
3722
|
*/
|
|
3505
3723
|
function allowDocumentSnapshotWithPathOnceFilter() {
|
|
3506
3724
|
return util.allowValueOnceFilter(readFirestoreModelKeyFromDocumentSnapshot);
|
|
@@ -9907,6 +10125,7 @@ exports.limit = limit;
|
|
|
9907
10125
|
exports.limitToLast = limitToLast;
|
|
9908
10126
|
exports.limitUploadFileTypeDeterminer = limitUploadFileTypeDeterminer;
|
|
9909
10127
|
exports.limitedFirestoreDocumentAccessorFactory = limitedFirestoreDocumentAccessorFactory;
|
|
10128
|
+
exports.limitedFirestoreDocumentAccessorSnapshotCache = limitedFirestoreDocumentAccessorSnapshotCache;
|
|
9910
10129
|
exports.loadAllFirestoreDocumentSnapshot = loadAllFirestoreDocumentSnapshot;
|
|
9911
10130
|
exports.loadAllFirestoreDocumentSnapshotPairs = loadAllFirestoreDocumentSnapshotPairs;
|
|
9912
10131
|
exports.loadDocumentsForDocumentReferences = loadDocumentsForDocumentReferences;
|
|
@@ -10064,6 +10283,7 @@ exports.storagePathFactory = storagePathFactory;
|
|
|
10064
10283
|
exports.storedFileReaderFactory = storedFileReaderFactory;
|
|
10065
10284
|
exports.streamDocumentSnapshotDataPairs = streamDocumentSnapshotDataPairs;
|
|
10066
10285
|
exports.streamDocumentSnapshotDataPairsWithData = streamDocumentSnapshotDataPairsWithData;
|
|
10286
|
+
exports.streamDocumentSnapshotsData = streamDocumentSnapshotsData;
|
|
10067
10287
|
exports.streamFromOnSnapshot = streamFromOnSnapshot;
|
|
10068
10288
|
exports.systemStateCollectionReference = systemStateCollectionReference;
|
|
10069
10289
|
exports.systemStateConverter = systemStateConverter;
|