@lpdjs/firestore-repo-service 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,755 @@
1
+ 'use strict';
2
+
3
+ // src/query-builder.ts
4
+ function chunkArray(array, size) {
5
+ const chunks = [];
6
+ for (let i = 0; i < array.length; i += size) {
7
+ chunks.push(array.slice(i, i + size));
8
+ }
9
+ return chunks;
10
+ }
11
+ function applyBasicQueryOptions(q, options) {
12
+ if (options.orderBy) {
13
+ options.orderBy.forEach((o) => {
14
+ q = q.orderBy(String(o.field), o.direction || "asc");
15
+ });
16
+ }
17
+ if (options.limit) {
18
+ q = q.limit(options.limit);
19
+ }
20
+ if (options.offset) {
21
+ q = q.offset(options.offset);
22
+ }
23
+ if (options.startAt) {
24
+ q = Array.isArray(options.startAt) ? q.startAt(...options.startAt) : q.startAt(options.startAt);
25
+ }
26
+ if (options.startAfter) {
27
+ q = Array.isArray(options.startAfter) ? q.startAfter(...options.startAfter) : q.startAfter(options.startAfter);
28
+ }
29
+ if (options.endAt) {
30
+ q = Array.isArray(options.endAt) ? q.endAt(...options.endAt) : q.endAt(options.endAt);
31
+ }
32
+ if (options.endBefore) {
33
+ q = Array.isArray(options.endBefore) ? q.endBefore(...options.endBefore) : q.endBefore(options.endBefore);
34
+ }
35
+ return q;
36
+ }
37
+ function needsSplitting(clause) {
38
+ const { operator, value } = clause;
39
+ return (operator === "in" || operator === "array-contains-any") && Array.isArray(value) && value.length > 30;
40
+ }
41
+ function splitWhereClause(clause) {
42
+ const { field, operator, value } = clause;
43
+ if (!needsSplitting(clause)) {
44
+ return [clause];
45
+ }
46
+ const chunks = chunkArray(value, 30);
47
+ return chunks.map((chunk) => ({
48
+ field,
49
+ operator,
50
+ value: chunk
51
+ }));
52
+ }
53
+ function applyWhereClausesToQuery(baseQuery, whereClauses) {
54
+ let q = baseQuery;
55
+ for (const clause of whereClauses) {
56
+ q = q.where(String(clause.field), clause.operator, clause.value);
57
+ }
58
+ return q;
59
+ }
60
+ async function executeAndMergeQueries(queries) {
61
+ const snapshots = await Promise.all(queries.map((q) => q.get()));
62
+ const docsMap = /* @__PURE__ */ new Map();
63
+ snapshots.forEach((snapshot) => {
64
+ snapshot.docs.forEach((doc) => {
65
+ if (!docsMap.has(doc.id)) {
66
+ docsMap.set(doc.id, doc);
67
+ }
68
+ });
69
+ });
70
+ const firstSnapshot = snapshots[0];
71
+ if (!firstSnapshot) {
72
+ throw new Error("No snapshots returned");
73
+ }
74
+ return {
75
+ ...firstSnapshot,
76
+ docs: Array.from(docsMap.values()),
77
+ size: docsMap.size,
78
+ empty: docsMap.size === 0
79
+ };
80
+ }
81
+ async function buildAndExecuteQuery(baseQuery, options) {
82
+ if (options.where && !options.orWhere) {
83
+ const needsSplit = options.where.some(needsSplitting);
84
+ if (!needsSplit) {
85
+ let q2 = applyWhereClausesToQuery(baseQuery, options.where);
86
+ q2 = applyBasicQueryOptions(q2, options);
87
+ return q2.get();
88
+ }
89
+ const splitClauses = options.where.map(splitWhereClause);
90
+ const combinations = cartesianProduct(splitClauses);
91
+ const queries = combinations.map((combination) => {
92
+ let q2 = applyWhereClausesToQuery(baseQuery, combination);
93
+ q2 = applyBasicQueryOptions(q2, options);
94
+ return q2;
95
+ });
96
+ return executeAndMergeQueries(queries);
97
+ }
98
+ if (options.orWhere) {
99
+ const allQueries = [];
100
+ for (const orGroup of options.orWhere) {
101
+ const needsSplit = orGroup.some(needsSplitting);
102
+ if (!needsSplit) {
103
+ let q2 = applyWhereClausesToQuery(baseQuery, orGroup);
104
+ q2 = applyBasicQueryOptions(q2, options);
105
+ allQueries.push(q2);
106
+ } else {
107
+ const splitClauses = orGroup.map(splitWhereClause);
108
+ const combinations = cartesianProduct(splitClauses);
109
+ const groupQueries = combinations.map((combination) => {
110
+ let q2 = applyWhereClausesToQuery(baseQuery, combination);
111
+ q2 = applyBasicQueryOptions(q2, options);
112
+ return q2;
113
+ });
114
+ allQueries.push(...groupQueries);
115
+ }
116
+ }
117
+ return executeAndMergeQueries(allQueries);
118
+ }
119
+ const q = applyBasicQueryOptions(baseQuery, options);
120
+ return q.get();
121
+ }
122
+ function cartesianProduct(arrays) {
123
+ if (arrays.length === 0) return [[]];
124
+ const first = arrays[0];
125
+ if (arrays.length === 1 && first) {
126
+ return first.map((item) => [item]);
127
+ }
128
+ if (!first) return [[]];
129
+ const rest = arrays.slice(1);
130
+ const restProduct = cartesianProduct(rest);
131
+ const result = [];
132
+ for (const item of first) {
133
+ for (const combo of restProduct) {
134
+ result.push([item, ...combo]);
135
+ }
136
+ }
137
+ return result;
138
+ }
139
+
140
+ // src/pagination.ts
141
+ function applyQueryOptions(q, options) {
142
+ if (options.where) {
143
+ options.where.forEach((w) => {
144
+ q = q.where(String(w.field), w.operator, w.value);
145
+ });
146
+ }
147
+ if (options.orderBy) {
148
+ options.orderBy.forEach((o) => {
149
+ q = q.orderBy(String(o.field), o.direction || "asc");
150
+ });
151
+ }
152
+ if (options.limit) {
153
+ q = q.limit(options.limit);
154
+ }
155
+ if (options.offset) {
156
+ q = q.offset(options.offset);
157
+ }
158
+ if (options.startAt) {
159
+ q = Array.isArray(options.startAt) ? q.startAt(...options.startAt) : q.startAt(options.startAt);
160
+ }
161
+ if (options.startAfter) {
162
+ q = Array.isArray(options.startAfter) ? q.startAfter(...options.startAfter) : q.startAfter(options.startAfter);
163
+ }
164
+ if (options.endAt) {
165
+ q = Array.isArray(options.endAt) ? q.endAt(...options.endAt) : q.endAt(options.endAt);
166
+ }
167
+ if (options.endBefore) {
168
+ q = Array.isArray(options.endBefore) ? q.endBefore(...options.endBefore) : q.endBefore(options.endBefore);
169
+ }
170
+ return q;
171
+ }
172
+ async function executePaginatedQuery(baseQuery, options) {
173
+ const queryOptions = {
174
+ ...options,
175
+ limit: options.pageSize + 1
176
+ // Fetch one extra to check if there's a next page
177
+ };
178
+ if (options.cursor) {
179
+ if (options.direction === "prev") {
180
+ queryOptions.endBefore = options.cursor;
181
+ } else {
182
+ queryOptions.startAfter = options.cursor;
183
+ }
184
+ }
185
+ const snapshot = await buildAndExecuteQuery(baseQuery, queryOptions);
186
+ const docs = snapshot.docs;
187
+ const hasMore = docs.length > options.pageSize;
188
+ const actualDocs = hasMore ? docs.slice(0, options.pageSize) : docs;
189
+ const data = actualDocs.map((doc) => ({
190
+ ...doc.data(),
191
+ docId: doc.id
192
+ }));
193
+ return {
194
+ data,
195
+ nextCursor: hasMore ? actualDocs[actualDocs.length - 1] : void 0,
196
+ prevCursor: actualDocs[0],
197
+ hasNextPage: hasMore,
198
+ hasPrevPage: !!options.cursor,
199
+ pageSize: data.length
200
+ };
201
+ }
202
+ async function* createPaginationIterator(baseQuery, options) {
203
+ let cursor;
204
+ let hasMore = true;
205
+ while (hasMore) {
206
+ const result = await executePaginatedQuery(baseQuery, {
207
+ ...options,
208
+ cursor,
209
+ direction: "next"
210
+ });
211
+ yield result;
212
+ hasMore = result.hasNextPage;
213
+ cursor = result.nextCursor;
214
+ }
215
+ }
216
+
217
+ // src/shared/utils.ts
218
+ function chunkArray2(array, size) {
219
+ const chunks = [];
220
+ for (let i = 0; i < array.length; i += size) {
221
+ chunks.push(array.slice(i, i + size));
222
+ }
223
+ return chunks;
224
+ }
225
+ function capitalize(str) {
226
+ return str.charAt(0).toUpperCase() + str.slice(1);
227
+ }
228
+
229
+ // src/methods/query.ts
230
+ function applyQueryOptions2(q, options) {
231
+ if (options.where) {
232
+ options.where.forEach((w) => {
233
+ q = q.where(String(w.field), w.operator, w.value);
234
+ });
235
+ }
236
+ if (options.orderBy) {
237
+ options.orderBy.forEach((o) => {
238
+ q = q.orderBy(String(o.field), o.direction || "asc");
239
+ });
240
+ }
241
+ if (options.limit) {
242
+ q = q.limit(options.limit);
243
+ }
244
+ if (options.offset) {
245
+ q = q.offset(options.offset);
246
+ }
247
+ if (options.startAt) {
248
+ q = Array.isArray(options.startAt) ? q.startAt(...options.startAt) : q.startAt(options.startAt);
249
+ }
250
+ if (options.startAfter) {
251
+ q = Array.isArray(options.startAfter) ? q.startAfter(...options.startAfter) : q.startAfter(options.startAfter);
252
+ }
253
+ if (options.endAt) {
254
+ q = Array.isArray(options.endAt) ? q.endAt(...options.endAt) : q.endAt(options.endAt);
255
+ }
256
+ if (options.endBefore) {
257
+ q = Array.isArray(options.endBefore) ? q.endBefore(...options.endBefore) : q.endBefore(options.endBefore);
258
+ }
259
+ return q;
260
+ }
261
+ function createQueryMethods(collectionRef, queryKeys) {
262
+ const queryMethods = {};
263
+ queryKeys.forEach((queryKey) => {
264
+ const methodName = `by${capitalize(String(queryKey))}`;
265
+ queryMethods[methodName] = async (value, options = {}) => {
266
+ let q = collectionRef;
267
+ q = q.where(String(queryKey), "==", value);
268
+ q = applyQueryOptions2(q, options);
269
+ const snapshot = await q.get();
270
+ return snapshot.docs.map((doc) => ({ ...doc.data(), docId: doc.id }));
271
+ };
272
+ });
273
+ queryMethods.by = async (options) => {
274
+ let q = collectionRef;
275
+ q = applyQueryOptions2(q, options);
276
+ const snapshot = await q.get();
277
+ return snapshot.docs.map((doc) => ({ ...doc.data(), docId: doc.id }));
278
+ };
279
+ queryMethods.getAll = async (options = {}) => {
280
+ let q = collectionRef;
281
+ q = applyQueryOptions2(q, options);
282
+ const snapshot = await q.get();
283
+ return snapshot.docs.map((doc) => ({ ...doc.data(), docId: doc.id }));
284
+ };
285
+ queryMethods.onSnapshot = (options, onNext, onError) => {
286
+ let q = collectionRef;
287
+ q = applyQueryOptions2(q, options);
288
+ return q.onSnapshot((snapshot) => {
289
+ const data = snapshot.docs.map((doc) => ({
290
+ ...doc.data(),
291
+ docId: doc.id
292
+ }));
293
+ onNext(data);
294
+ }, onError);
295
+ };
296
+ queryMethods.paginate = async (options) => {
297
+ return executePaginatedQuery(collectionRef, options);
298
+ };
299
+ queryMethods.paginateAll = (options) => {
300
+ return createPaginationIterator(collectionRef, options);
301
+ };
302
+ return queryMethods;
303
+ }
304
+
305
+ // src/methods/aggregate.ts
306
+ function createAggregateMethods(collectionRef) {
307
+ return {
308
+ // Count documents matching query options
309
+ count: async (options = {}) => {
310
+ let q = collectionRef;
311
+ q = applyQueryOptions2(q, options);
312
+ const snapshot = await q.count().get();
313
+ return snapshot.data().count;
314
+ },
315
+ // Sum of a numeric field
316
+ sum: async (field, options = {}) => {
317
+ let q = collectionRef;
318
+ q = applyQueryOptions2(q, options);
319
+ const snapshot = await q.get();
320
+ let total = 0;
321
+ snapshot.forEach((doc) => {
322
+ const value = doc.data()[field];
323
+ if (typeof value === "number") {
324
+ total += value;
325
+ }
326
+ });
327
+ return total;
328
+ },
329
+ // Average of a numeric field
330
+ average: async (field, options = {}) => {
331
+ let q = collectionRef;
332
+ q = applyQueryOptions2(q, options);
333
+ const snapshot = await q.get();
334
+ if (snapshot.empty) return null;
335
+ let total = 0;
336
+ let count = 0;
337
+ snapshot.forEach((doc) => {
338
+ const value = doc.data()[field];
339
+ if (typeof value === "number") {
340
+ total += value;
341
+ count++;
342
+ }
343
+ });
344
+ return count > 0 ? total / count : null;
345
+ }
346
+ };
347
+ }
348
+
349
+ // src/methods/batch.ts
350
+ function createBatchMethods(db, documentRef) {
351
+ return {
352
+ create: () => {
353
+ const batch = db.batch();
354
+ return {
355
+ batch,
356
+ set: (...args) => {
357
+ const lastArg = args[args.length - 1];
358
+ const hasOptions = typeof lastArg === "object" && lastArg !== null && "merge" in lastArg;
359
+ const data = hasOptions ? args[args.length - 2] : args[args.length - 1];
360
+ const pathArgs = hasOptions ? args.slice(0, -2) : args.slice(0, -1);
361
+ const mergeOption = hasOptions ? lastArg : { merge: true };
362
+ const docRef = documentRef(...pathArgs);
363
+ batch.set(docRef, data, mergeOption);
364
+ },
365
+ update: (...args) => {
366
+ const data = args.pop();
367
+ const pathArgs = args;
368
+ const docRef = documentRef(...pathArgs);
369
+ batch.update(docRef, data);
370
+ },
371
+ delete: (...args) => {
372
+ const docRef = documentRef(...args);
373
+ batch.delete(docRef);
374
+ },
375
+ commit: async () => {
376
+ await batch.commit();
377
+ }
378
+ };
379
+ }
380
+ };
381
+ }
382
+
383
+ // src/methods/bulk.ts
384
+ function createBulkMethods(db) {
385
+ return {
386
+ // Set multiple documents with automatic batching (500 ops per flush)
387
+ set: async (items) => {
388
+ const bulkWriter = db.bulkWriter();
389
+ let pendingOps = 0;
390
+ for (const item of items) {
391
+ if (!item) continue;
392
+ const { docRef, data, merge = true } = item;
393
+ bulkWriter.set(docRef, data, { merge });
394
+ pendingOps++;
395
+ if (pendingOps >= 500) {
396
+ await bulkWriter.flush();
397
+ pendingOps = 0;
398
+ }
399
+ }
400
+ await bulkWriter.close();
401
+ },
402
+ // Update multiple documents with automatic batching
403
+ update: async (items) => {
404
+ const bulkWriter = db.bulkWriter();
405
+ let pendingOps = 0;
406
+ for (const item of items) {
407
+ if (!item) continue;
408
+ const { docRef, data } = item;
409
+ bulkWriter.update(docRef, data);
410
+ pendingOps++;
411
+ if (pendingOps >= 500) {
412
+ await bulkWriter.flush();
413
+ pendingOps = 0;
414
+ }
415
+ }
416
+ await bulkWriter.close();
417
+ },
418
+ // Delete multiple documents with automatic batching
419
+ delete: async (docRefs) => {
420
+ const bulkWriter = db.bulkWriter();
421
+ let pendingOps = 0;
422
+ for (const docRef of docRefs) {
423
+ if (!docRef) continue;
424
+ bulkWriter.delete(docRef);
425
+ pendingOps++;
426
+ if (pendingOps >= 500) {
427
+ await bulkWriter.flush();
428
+ pendingOps = 0;
429
+ }
430
+ }
431
+ await bulkWriter.close();
432
+ }
433
+ };
434
+ }
435
+
436
+ // src/methods/crud.ts
437
+ function createCrudMethods(actualCollection, documentRef) {
438
+ const create = async (data) => {
439
+ if (!actualCollection) {
440
+ throw new Error(
441
+ "Cannot use create() on collection groups. Use set() with a specific document ID instead."
442
+ );
443
+ }
444
+ const docRef = await actualCollection.add(data);
445
+ const createdDoc = await docRef.get();
446
+ return { ...createdDoc.data(), docId: docRef.id };
447
+ };
448
+ const set = async (...args) => {
449
+ const lastArg = args[args.length - 1];
450
+ const hasOptions = typeof lastArg === "object" && lastArg !== null && "merge" in lastArg;
451
+ const data = hasOptions ? args[args.length - 2] : args[args.length - 1];
452
+ const pathArgs = hasOptions ? args.slice(0, -2) : args.slice(0, -1);
453
+ const mergeOption = hasOptions ? lastArg : { merge: true };
454
+ const docRef = documentRef(...pathArgs);
455
+ await docRef.set(data, mergeOption);
456
+ const setDocument = await docRef.get();
457
+ return { ...setDocument.data(), docId: docRef.id };
458
+ };
459
+ const update = async (...args) => {
460
+ const data = args.pop();
461
+ const pathArgs = args;
462
+ const docRef = documentRef(...pathArgs);
463
+ await docRef.update(data);
464
+ const updatedDoc = await docRef.get();
465
+ return { ...updatedDoc.data(), docId: docRef.id };
466
+ };
467
+ const deleteMethod = async (...args) => {
468
+ const docRef = documentRef(...args);
469
+ await docRef.delete();
470
+ };
471
+ return {
472
+ create,
473
+ set,
474
+ update,
475
+ delete: deleteMethod
476
+ };
477
+ }
478
+
479
+ // src/methods/get.ts
480
+ function createGetMethods(collectionRef, foreignKeys, actualCollection, documentRef) {
481
+ const getMethods = {};
482
+ getMethods.byList = async (key, values, operator = "in", returnDoc = false) => {
483
+ if (values.length === 0) return [];
484
+ const results = [];
485
+ const chunks = chunkArray2(values, 30);
486
+ for (const chunk of chunks) {
487
+ let q = collectionRef;
488
+ q = q.where(key, operator, chunk);
489
+ const snapshot = await q.get();
490
+ snapshot.forEach((doc) => {
491
+ const data = doc.data();
492
+ results.push(returnDoc ? { data, doc } : { ...data, docId: doc.id });
493
+ });
494
+ }
495
+ return results;
496
+ };
497
+ foreignKeys.forEach((foreignKey) => {
498
+ const methodName = `by${capitalize(String(foreignKey))}`;
499
+ getMethods[methodName] = async (value, returnDoc = false) => {
500
+ if (String(foreignKey) === "docId") {
501
+ const docRef = documentRef(value);
502
+ const doc2 = await docRef.get();
503
+ if (!doc2.exists) return null;
504
+ const data2 = doc2.data();
505
+ return returnDoc ? { data: data2, doc: doc2 } : { ...data2, docId: doc2.id };
506
+ }
507
+ let q = collectionRef;
508
+ q = q.where(String(foreignKey), "==", value).limit(1);
509
+ const snapshot = await q.get();
510
+ if (snapshot.empty) return null;
511
+ const doc = snapshot.docs[0];
512
+ if (!doc) return null;
513
+ const data = doc.data();
514
+ return returnDoc ? { data, doc } : { ...data, docId: doc.id };
515
+ };
516
+ });
517
+ return getMethods;
518
+ }
519
+
520
+ // src/methods/relations.ts
521
+ function createPopulateMethods(config, allRepositories) {
522
+ return {
523
+ populate: async (document, relationKey) => {
524
+ if (!config.relationalKeys) {
525
+ return { ...document, populated: {} };
526
+ }
527
+ const keys = Array.isArray(relationKey) ? relationKey : [relationKey];
528
+ const result = { ...document };
529
+ const populated = {};
530
+ for (const key of keys) {
531
+ const relation = config.relationalKeys?.[key];
532
+ if (!relation) {
533
+ console.warn(
534
+ `[populate] Relation "${String(key)}" not found in config`
535
+ );
536
+ continue;
537
+ }
538
+ const targetRepo = allRepositories[relation.repo];
539
+ if (!targetRepo) {
540
+ console.warn(
541
+ `[populate] Repository "${relation.repo}" not found in mapping`
542
+ );
543
+ continue;
544
+ }
545
+ const fieldValue = document[key];
546
+ if (fieldValue === void 0 || fieldValue === null) {
547
+ populated[relation.repo] = relation.type === "one" ? null : [];
548
+ continue;
549
+ }
550
+ try {
551
+ if (relation.type === "one") {
552
+ const getMethod = `by${capitalize2(relation.key)}`;
553
+ if (typeof targetRepo.get?.[getMethod] === "function") {
554
+ populated[relation.repo] = await targetRepo.get[getMethod](
555
+ fieldValue
556
+ );
557
+ } else {
558
+ console.warn(
559
+ `[populate] Method "get.${getMethod}" not found in ${relation.repo}`
560
+ );
561
+ populated[relation.repo] = null;
562
+ }
563
+ } else {
564
+ const queryMethod = `by${capitalize2(relation.key)}`;
565
+ if (typeof targetRepo.query[queryMethod] === "function") {
566
+ populated[relation.repo] = await targetRepo.query[queryMethod](
567
+ fieldValue
568
+ );
569
+ } else {
570
+ console.warn(
571
+ `[populate] Method "query.${queryMethod}" not found in ${relation.repo}`
572
+ );
573
+ populated[relation.repo] = [];
574
+ }
575
+ }
576
+ } catch (error) {
577
+ console.error(`[populate] Error populating "${String(key)}":`, error);
578
+ populated[relation.repo] = relation.type === "one" ? null : [];
579
+ }
580
+ }
581
+ return { ...result, populated };
582
+ }
583
+ };
584
+ }
585
+ function capitalize2(str) {
586
+ return str.charAt(0).toUpperCase() + str.slice(1);
587
+ }
588
+
589
+ // src/methods/transaction.ts
590
+ function createTransactionMethods(db, documentRef) {
591
+ return {
592
+ run: async (updateFunction) => {
593
+ return db.runTransaction(async (rawTransaction) => {
594
+ const typedTransaction = {
595
+ // Type-safe get method
596
+ get: async (...args) => {
597
+ const docRef = documentRef(...args);
598
+ const docSnap = await rawTransaction.get(docRef);
599
+ if (!docSnap.exists) return null;
600
+ return { ...docSnap.data(), docId: docSnap.id };
601
+ },
602
+ // Type-safe set method
603
+ set: (...args) => {
604
+ const options = args[args.length - 1];
605
+ const hasOptions = typeof options === "object" && options !== null && "merge" in options;
606
+ const data = hasOptions ? args[args.length - 2] : args[args.length - 1];
607
+ const pathArgs = hasOptions ? args.slice(0, -2) : args.slice(0, -1);
608
+ const mergeOption = hasOptions ? options : { merge: true };
609
+ const docRef = documentRef(...pathArgs);
610
+ rawTransaction.set(docRef, data, mergeOption);
611
+ },
612
+ // Type-safe update method
613
+ update: (...args) => {
614
+ const data = args[args.length - 1];
615
+ const pathArgs = args.slice(0, -1);
616
+ const docRef = documentRef(...pathArgs);
617
+ rawTransaction.update(docRef, data);
618
+ },
619
+ // Delete method
620
+ delete: (...args) => {
621
+ const docRef = documentRef(...args);
622
+ rawTransaction.delete(docRef);
623
+ },
624
+ // Access to raw transaction
625
+ raw: rawTransaction
626
+ };
627
+ return updateFunction(typedTransaction);
628
+ });
629
+ }
630
+ };
631
+ }
632
+
633
+ // src/repositories/factory.ts
634
+ function createRepository(db, config, allRepositories = {}) {
635
+ const collectionRef = config.isGroup ? db.collectionGroup(config.path) : db.collection(config.path);
636
+ const actualCollection = config.isGroup ? null : db.collection(config.path);
637
+ const documentRef = (...args) => config.refCb(db, ...args);
638
+ const getMethods = createGetMethods(
639
+ collectionRef,
640
+ config.foreignKeys,
641
+ actualCollection,
642
+ documentRef
643
+ );
644
+ const queryMethods = createQueryMethods(
645
+ collectionRef,
646
+ config.queryKeys
647
+ );
648
+ const aggregateMethods = createAggregateMethods(collectionRef);
649
+ const crudMethods = createCrudMethods(actualCollection, documentRef);
650
+ const batchMethods = createBatchMethods(db, documentRef);
651
+ const transactionMethods = createTransactionMethods(db, documentRef);
652
+ const bulkMethods = createBulkMethods(db);
653
+ const populateMethods = createPopulateMethods(config, allRepositories);
654
+ return {
655
+ ref: collectionRef,
656
+ documentRef,
657
+ get: getMethods,
658
+ query: queryMethods,
659
+ aggregate: aggregateMethods,
660
+ ...crudMethods,
661
+ batch: batchMethods,
662
+ transaction: transactionMethods,
663
+ bulk: bulkMethods,
664
+ ...populateMethods
665
+ };
666
+ }
667
+
668
+ // index.ts
669
+ function createRepositoryConfig() {
670
+ return (config) => {
671
+ return {
672
+ ...config,
673
+ type: null,
674
+ documentRef: null,
675
+ update: null
676
+ };
677
+ };
678
+ }
679
+ function buildRepositoryRelations(mapping, relations) {
680
+ const result = { ...mapping };
681
+ for (const repoKey in relations) {
682
+ if (relations[repoKey]) {
683
+ result[repoKey] = {
684
+ ...mapping[repoKey],
685
+ relationalKeys: relations[repoKey]
686
+ };
687
+ }
688
+ }
689
+ return result;
690
+ }
691
+ var RepositoryMapping = class {
692
+ /**
693
+ * Creates a new RepositoryMapping instance
694
+ * @param db - Firestore instance from firebase-admin
695
+ * @param mapping - Repository configuration mapping
696
+ */
697
+ constructor(db, mapping) {
698
+ this.repositoryCache = /* @__PURE__ */ new Map();
699
+ this.allRepositories = {};
700
+ this.db = db;
701
+ this.mapping = mapping;
702
+ this.initializeRepositories();
703
+ }
704
+ /**
705
+ * Initialize all repositories in two passes to handle circular dependencies
706
+ * @private
707
+ */
708
+ initializeRepositories() {
709
+ for (const key of Object.keys(this.mapping)) {
710
+ this.allRepositories[key] = createRepository(
711
+ this.db,
712
+ this.mapping[key],
713
+ {}
714
+ );
715
+ }
716
+ for (const key of Object.keys(this.mapping)) {
717
+ this.allRepositories[key] = createRepository(
718
+ this.db,
719
+ this.mapping[key],
720
+ this.allRepositories
721
+ );
722
+ }
723
+ }
724
+ /**
725
+ * Gets a repository (already initialized)
726
+ * @template K - Repository key
727
+ * @param key - Repository identifier
728
+ * @returns Configured repository instance
729
+ */
730
+ getRepository(key) {
731
+ return this.allRepositories[key];
732
+ }
733
+ };
734
+ function createRepositoryMapping(db, mapping) {
735
+ const instance = new RepositoryMapping(db, mapping);
736
+ return new Proxy(instance, {
737
+ get(target, prop) {
738
+ if (typeof prop === "string" && prop in mapping) {
739
+ return target.getRepository(prop);
740
+ }
741
+ return target[prop];
742
+ }
743
+ });
744
+ }
745
+
746
+ exports.RepositoryMapping = RepositoryMapping;
747
+ exports.applyPaginationQueryOptions = applyQueryOptions;
748
+ exports.buildAndExecuteQuery = buildAndExecuteQuery;
749
+ exports.buildRepositoryRelations = buildRepositoryRelations;
750
+ exports.createPaginationIterator = createPaginationIterator;
751
+ exports.createRepositoryConfig = createRepositoryConfig;
752
+ exports.createRepositoryMapping = createRepositoryMapping;
753
+ exports.executePaginatedQuery = executePaginatedQuery;
754
+ //# sourceMappingURL=index.cjs.map
755
+ //# sourceMappingURL=index.cjs.map