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