@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/LICENSE +21 -0
- package/README.md +592 -0
- package/dist/index.cjs +755 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +420 -0
- package/dist/index.d.ts +420 -0
- package/dist/index.js +746 -0
- package/dist/index.js.map +1 -0
- package/package.json +74 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import { DocumentReference, Firestore, DocumentSnapshot, WhereFilterOp, Query, QuerySnapshot, CollectionReference, WriteBatch, Transaction } from 'firebase-admin/firestore';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extract the documentRef signature from refCb (without the db parameter)
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
type ExtractDocumentRefSignature<T> = T extends (db: Firestore, ...args: infer P) => DocumentReference ? (...args: P) => DocumentReference : never;
|
|
8
|
+
/**
|
|
9
|
+
* Extract the update signature from refCb
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
type ExtractUpdateSignature<T, TType> = T extends (db: Firestore, ...args: infer P) => DocumentReference ? (...args: [...P, Partial<TType>]) => Promise<TType> : never;
|
|
13
|
+
/**
|
|
14
|
+
* Type for a where condition with strict value typing based on the field
|
|
15
|
+
* @template T - Data model type
|
|
16
|
+
*/
|
|
17
|
+
type WhereClause<T = any> = {
|
|
18
|
+
[K in keyof T]: {
|
|
19
|
+
field: K;
|
|
20
|
+
operator: WhereFilterOp;
|
|
21
|
+
value: T[K] | T[K][];
|
|
22
|
+
};
|
|
23
|
+
}[keyof T];
|
|
24
|
+
/**
|
|
25
|
+
* Query options for filtering, sorting and paginating results
|
|
26
|
+
* @template T - Data model type
|
|
27
|
+
*/
|
|
28
|
+
interface QueryOptions<T = any> {
|
|
29
|
+
where?: WhereClause<T>[];
|
|
30
|
+
orWhere?: WhereClause<T>[][];
|
|
31
|
+
orderBy?: {
|
|
32
|
+
field: keyof T;
|
|
33
|
+
direction?: "asc" | "desc";
|
|
34
|
+
}[];
|
|
35
|
+
limit?: number;
|
|
36
|
+
offset?: number;
|
|
37
|
+
startAt?: DocumentSnapshot | any[];
|
|
38
|
+
startAfter?: DocumentSnapshot | any[];
|
|
39
|
+
endAt?: DocumentSnapshot | any[];
|
|
40
|
+
endBefore?: DocumentSnapshot | any[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Result type for get operations with optional document snapshot
|
|
44
|
+
* @internal
|
|
45
|
+
*/
|
|
46
|
+
type GetResult<T, ReturnDoc extends boolean> = ReturnDoc extends true ? {
|
|
47
|
+
data: T;
|
|
48
|
+
doc: DocumentSnapshot;
|
|
49
|
+
} | null : T | null;
|
|
50
|
+
/**
|
|
51
|
+
* Relation configuration for a field with strict typing
|
|
52
|
+
* @template TRepoKey - Target repository name (key from mapping)
|
|
53
|
+
* @template TForeignKey - Target foreign key name
|
|
54
|
+
* @template TType - Relation type: "one" for one-to-one, "many" for one-to-many
|
|
55
|
+
* @template TTargetModel - Type of the target model (inferred from mapping)
|
|
56
|
+
*/
|
|
57
|
+
interface RelationConfig<TRepoKey extends string = string, TForeignKey extends string = string, TType extends "one" | "many" = "one" | "many", TTargetModel = any> {
|
|
58
|
+
repo: TRepoKey;
|
|
59
|
+
key: TForeignKey;
|
|
60
|
+
type: TType;
|
|
61
|
+
targetType?: TTargetModel;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Relational key mapping between repositories with strict typing
|
|
65
|
+
* Maps a field from the current model to a target repository and foreign key
|
|
66
|
+
* @template T - Current model type
|
|
67
|
+
* @template TMapping - All repositories mapping for validation
|
|
68
|
+
* @example { userId: { repo: "users", key: "docId", type: "one" } }
|
|
69
|
+
*
|
|
70
|
+
* IMPORTANT: Keys must exist in T (the current model)
|
|
71
|
+
* This prevents creating relations on non-existent fields
|
|
72
|
+
*/
|
|
73
|
+
type RelationalKeys<T = any, TMapping = any> = {
|
|
74
|
+
[K in keyof T]?: TMapping extends Record<string, any> ? {
|
|
75
|
+
[R in keyof TMapping]: TMapping[R] extends RepositoryConfig<any, infer FKeys, any, any, any, any> ? {
|
|
76
|
+
repo: R;
|
|
77
|
+
key: FKeys[number];
|
|
78
|
+
type: "one" | "many";
|
|
79
|
+
} : never;
|
|
80
|
+
}[keyof TMapping] : RelationConfig;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Configuration interface for repositories with strict literal type inference
|
|
84
|
+
* @template T - The data model type
|
|
85
|
+
* @template TForeignKeys - Foreign keys used for unique document retrieval
|
|
86
|
+
* @template TQueryKeys - Query keys used for multiple document searches
|
|
87
|
+
* @template TIsGroup - Whether this is a collection group query
|
|
88
|
+
* @template TRefCb - Callback function signature for creating document references
|
|
89
|
+
* @template TRelationalKeys - Relational keys mapping to other repositories
|
|
90
|
+
*/
|
|
91
|
+
interface RepositoryConfig<T, TForeignKeys extends readonly (keyof T)[], TQueryKeys extends readonly (keyof T)[], TIsGroup extends boolean = boolean, TRefCb = any, TRelationalKeys = {}> {
|
|
92
|
+
path: string;
|
|
93
|
+
isGroup: TIsGroup;
|
|
94
|
+
foreignKeys: TForeignKeys;
|
|
95
|
+
queryKeys: TQueryKeys;
|
|
96
|
+
type: T;
|
|
97
|
+
refCb?: TRefCb;
|
|
98
|
+
relationalKeys?: TRelationalKeys;
|
|
99
|
+
documentRef: TRefCb extends undefined ? TIsGroup extends true ? (...pathSegments: string[]) => DocumentReference : (docId: string) => DocumentReference : ExtractDocumentRefSignature<TRefCb>;
|
|
100
|
+
update: TRefCb extends undefined ? TIsGroup extends true ? (...args: [...string[], Partial<T>]) => Promise<T> : (docId: string, data: Partial<T>) => Promise<T> : ExtractUpdateSignature<TRefCb, T>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Pagination result with data and cursor information
|
|
105
|
+
* @template T - Data model type
|
|
106
|
+
*/
|
|
107
|
+
interface PaginationResult<T> {
|
|
108
|
+
/** Array of documents for the current page */
|
|
109
|
+
data: T[];
|
|
110
|
+
/** Cursor to the next page (undefined if no more pages) */
|
|
111
|
+
nextCursor?: DocumentSnapshot;
|
|
112
|
+
/** Cursor to the previous page (undefined if on first page) */
|
|
113
|
+
prevCursor?: DocumentSnapshot;
|
|
114
|
+
/** Whether there are more pages after this one */
|
|
115
|
+
hasNextPage: boolean;
|
|
116
|
+
/** Whether there are pages before this one */
|
|
117
|
+
hasPrevPage: boolean;
|
|
118
|
+
/** Total number of items in current page */
|
|
119
|
+
pageSize: number;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Pagination options for cursor-based pagination
|
|
123
|
+
* @template T - Data model type
|
|
124
|
+
*/
|
|
125
|
+
interface PaginationOptions<T> extends Omit<QueryOptions<T>, "limit"> {
|
|
126
|
+
/** Number of items per page */
|
|
127
|
+
pageSize: number;
|
|
128
|
+
/** Cursor to start after (for next page) */
|
|
129
|
+
cursor?: DocumentSnapshot;
|
|
130
|
+
/** Direction of pagination */
|
|
131
|
+
direction?: "next" | "prev";
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Helper to apply query options to a Firestore query
|
|
135
|
+
*/
|
|
136
|
+
declare function applyQueryOptions<T>(q: Query, options: QueryOptions<T>): Query;
|
|
137
|
+
/**
|
|
138
|
+
* Executes a paginated query and returns results with pagination info
|
|
139
|
+
* Uses the advanced query builder that handles OR conditions and automatic splitting
|
|
140
|
+
* @template T - Data model type
|
|
141
|
+
* @param baseQuery - Base Firestore query
|
|
142
|
+
* @param options - Pagination options
|
|
143
|
+
* @returns Pagination result with data and cursor information
|
|
144
|
+
*/
|
|
145
|
+
declare function executePaginatedQuery<T>(baseQuery: Query, options: PaginationOptions<T>): Promise<PaginationResult<T>>;
|
|
146
|
+
/**
|
|
147
|
+
* Creates an async generator for iterating through all pages
|
|
148
|
+
* @template T - Data model type
|
|
149
|
+
* @param baseQuery - Base Firestore query
|
|
150
|
+
* @param options - Pagination options (without cursor)
|
|
151
|
+
* @yields Pagination results for each page
|
|
152
|
+
* @example
|
|
153
|
+
* ```typescript
|
|
154
|
+
* const pageIterator = createPaginationIterator(query, { pageSize: 10 });
|
|
155
|
+
* for await (const page of pageIterator) {
|
|
156
|
+
* console.log(`Page with ${page.pageSize} items`);
|
|
157
|
+
* page.data.forEach(item => console.log(item));
|
|
158
|
+
* if (!page.hasNextPage) break;
|
|
159
|
+
* }
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
declare function createPaginationIterator<T>(baseQuery: Query, options: Omit<PaginationOptions<T>, "cursor" | "direction">): AsyncGenerator<PaginationResult<T>, void, unknown>;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Build and execute query with automatic splitting for in/array-contains-any
|
|
166
|
+
* Handles both simple AND conditions and complex OR conditions
|
|
167
|
+
*/
|
|
168
|
+
declare function buildAndExecuteQuery<T>(baseQuery: Query, options: QueryOptions<T>): Promise<QuerySnapshot>;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Helper type to extract populated data structure from a single relation
|
|
172
|
+
* @internal
|
|
173
|
+
*/
|
|
174
|
+
type ExtractPopulatedFromRelation<TRelation> = TRelation extends RelationConfig<infer TRepo, any, infer TType, infer TTargetModel> ? {
|
|
175
|
+
[P in TRepo]: TType extends "one" ? TTargetModel | null : TTargetModel[];
|
|
176
|
+
} : Record<string, never>;
|
|
177
|
+
/**
|
|
178
|
+
* Helper type to merge multiple populated objects into one
|
|
179
|
+
* @internal
|
|
180
|
+
*/
|
|
181
|
+
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
182
|
+
/**
|
|
183
|
+
* Generates get.by* methods from foreign keys
|
|
184
|
+
* @internal
|
|
185
|
+
*/
|
|
186
|
+
type GenerateGetMethods<TConfig extends RepositoryConfig<any, any, any, any, any, any>> = {
|
|
187
|
+
[K in TConfig["foreignKeys"][number] as K extends string ? `by${Capitalize<K>}` : never]: <ReturnDoc extends boolean = false>(value: TConfig["type"][K], returnDoc?: ReturnDoc) => Promise<GetResult<TConfig["type"], ReturnDoc>>;
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* Generates query.by* methods from query keys
|
|
191
|
+
* @internal
|
|
192
|
+
*/
|
|
193
|
+
type GenerateQueryMethods<TConfig extends RepositoryConfig<any, any, any, any, any, any>> = {
|
|
194
|
+
[K in TConfig["queryKeys"][number] as K extends string ? `by${Capitalize<K>}` : never]: (value: TConfig["type"][K], options?: QueryOptions<TConfig["type"]>) => Promise<TConfig["type"][]>;
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Configured repository with organized methods
|
|
198
|
+
*/
|
|
199
|
+
type ConfiguredRepository<T extends RepositoryConfig<any, any, any, any, any, any>> = {
|
|
200
|
+
ref: CollectionReference | Query;
|
|
201
|
+
get: GenerateGetMethods<T> & {
|
|
202
|
+
byList: <K extends keyof T["type"], ReturnDoc extends boolean = false>(key: K, values: T["type"][K][], operator?: "in" | "array-contains-any", returnDoc?: ReturnDoc) => Promise<ReturnDoc extends true ? Array<{
|
|
203
|
+
data: T["type"];
|
|
204
|
+
doc: DocumentSnapshot;
|
|
205
|
+
}> : T["type"][]>;
|
|
206
|
+
};
|
|
207
|
+
query: GenerateQueryMethods<T> & {
|
|
208
|
+
by: (options: QueryOptions<T["type"]>) => Promise<T["type"][]>;
|
|
209
|
+
getAll: (options?: QueryOptions<T["type"]>) => Promise<T["type"][]>;
|
|
210
|
+
onSnapshot: (options: QueryOptions<T["type"]>, onNext: (data: T["type"][]) => void, onError?: (error: Error) => void) => () => void;
|
|
211
|
+
paginate: (options: PaginationOptions<T["type"]>) => ReturnType<typeof executePaginatedQuery<T["type"]>>;
|
|
212
|
+
paginateAll: (options: Omit<PaginationOptions<T["type"]>, "cursor" | "direction">) => ReturnType<typeof createPaginationIterator<T["type"]>>;
|
|
213
|
+
};
|
|
214
|
+
aggregate: {
|
|
215
|
+
count: (options?: QueryOptions<T["type"]>) => Promise<number>;
|
|
216
|
+
sum: <K extends keyof T["type"]>(field: K, options?: QueryOptions<T["type"]>) => Promise<number>;
|
|
217
|
+
average: <K extends keyof T["type"]>(field: K, options?: QueryOptions<T["type"]>) => Promise<number | null>;
|
|
218
|
+
};
|
|
219
|
+
documentRef: T["documentRef"];
|
|
220
|
+
create: (data: Partial<T["type"]>) => Promise<T["type"] & {
|
|
221
|
+
docId: string;
|
|
222
|
+
}>;
|
|
223
|
+
set: (...args: [
|
|
224
|
+
...Parameters<T["documentRef"]>,
|
|
225
|
+
Partial<T["type"]>,
|
|
226
|
+
{
|
|
227
|
+
merge?: boolean;
|
|
228
|
+
}?
|
|
229
|
+
]) => Promise<T["type"]>;
|
|
230
|
+
update: T["update"];
|
|
231
|
+
delete: (...args: Parameters<T["documentRef"]>) => Promise<void>;
|
|
232
|
+
batch: {
|
|
233
|
+
create: () => {
|
|
234
|
+
batch: WriteBatch;
|
|
235
|
+
set: (...args: [
|
|
236
|
+
...Parameters<T["documentRef"]>,
|
|
237
|
+
Partial<T["type"]>,
|
|
238
|
+
{
|
|
239
|
+
merge?: boolean;
|
|
240
|
+
}?
|
|
241
|
+
]) => void;
|
|
242
|
+
update: (...args: [...Parameters<T["documentRef"]>, Partial<T["type"]>]) => void;
|
|
243
|
+
delete: (...args: Parameters<T["documentRef"]>) => void;
|
|
244
|
+
commit: () => Promise<void>;
|
|
245
|
+
};
|
|
246
|
+
};
|
|
247
|
+
transaction: {
|
|
248
|
+
run: <R>(updateFunction: (transaction: {
|
|
249
|
+
get: (...args: Parameters<T["documentRef"]>) => Promise<T["type"] | null>;
|
|
250
|
+
set: (...args: [
|
|
251
|
+
...Parameters<T["documentRef"]>,
|
|
252
|
+
Partial<T["type"]>,
|
|
253
|
+
{
|
|
254
|
+
merge?: boolean;
|
|
255
|
+
}?
|
|
256
|
+
]) => void;
|
|
257
|
+
update: (...args: [...Parameters<T["documentRef"]>, Partial<T["type"]>]) => void;
|
|
258
|
+
delete: (...args: Parameters<T["documentRef"]>) => void;
|
|
259
|
+
raw: Transaction;
|
|
260
|
+
}) => Promise<R>) => Promise<R>;
|
|
261
|
+
};
|
|
262
|
+
bulk: {
|
|
263
|
+
set: (items: Array<{
|
|
264
|
+
docRef: DocumentReference;
|
|
265
|
+
data: Partial<T["type"]>;
|
|
266
|
+
merge?: boolean;
|
|
267
|
+
}>) => Promise<void>;
|
|
268
|
+
update: (items: Array<{
|
|
269
|
+
docRef: DocumentReference;
|
|
270
|
+
data: Partial<T["type"]>;
|
|
271
|
+
}>) => Promise<void>;
|
|
272
|
+
delete: (docRefs: DocumentReference[]) => Promise<void>;
|
|
273
|
+
};
|
|
274
|
+
populate: <K extends keyof NonNullable<T["relationalKeys"]>>(document: T["type"], relationKey: K | K[]) => Promise<T["type"] & {
|
|
275
|
+
populated: UnionToIntersection<K extends keyof NonNullable<T["relationalKeys"]> ? ExtractPopulatedFromRelation<NonNullable<T["relationalKeys"]>[K]> : Record<string, never>>;
|
|
276
|
+
}>;
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Helper to create a typed repository configuration with literal type preservation
|
|
281
|
+
* Uses currying pattern to allow type parameter inference
|
|
282
|
+
* @template T - The data model type
|
|
283
|
+
* @returns Builder function that accepts repository configuration with withRelations method
|
|
284
|
+
* @example
|
|
285
|
+
* ```typescript
|
|
286
|
+
* const mapping = {
|
|
287
|
+
* users: createRepositoryConfig<UserModel>()({
|
|
288
|
+
* path: "users",
|
|
289
|
+
* foreignKeys: ["docId", "email"] as const,
|
|
290
|
+
* queryKeys: ["isActive"] as const,
|
|
291
|
+
* refCb: (db, docId: string) => db.collection("users").doc(docId),
|
|
292
|
+
* }),
|
|
293
|
+
* posts: createRepositoryConfig<PostModel>()({
|
|
294
|
+
* path: "posts",
|
|
295
|
+
* foreignKeys: ["docId", "userId"] as const,
|
|
296
|
+
* queryKeys: ["status"] as const,
|
|
297
|
+
* refCb: (db, docId: string) => db.collection("posts").doc(docId),
|
|
298
|
+
* }).withRelations<typeof mapping>()({
|
|
299
|
+
* userId: { repo: "users", key: "docId", type: "one" as const }
|
|
300
|
+
* })
|
|
301
|
+
* };
|
|
302
|
+
* ```
|
|
303
|
+
*/
|
|
304
|
+
declare function createRepositoryConfig<T>(): <const TForeignKeys extends readonly (keyof T)[], const TQueryKeys extends readonly (keyof T)[], const TIsGroup extends boolean, TRefCb = undefined>(config: {
|
|
305
|
+
path: string;
|
|
306
|
+
isGroup: TIsGroup;
|
|
307
|
+
foreignKeys: TForeignKeys;
|
|
308
|
+
queryKeys: TQueryKeys;
|
|
309
|
+
refCb: TRefCb;
|
|
310
|
+
}) => RepositoryConfig<T, TForeignKeys, TQueryKeys, TIsGroup, TRefCb, {}>;
|
|
311
|
+
/**
|
|
312
|
+
* Helper type to resolve a single relation configuration
|
|
313
|
+
* Extracts the target model type from the mapping
|
|
314
|
+
*/
|
|
315
|
+
type ResolveRelation<TMapping, TRelationConfig> = TRelationConfig extends {
|
|
316
|
+
repo: infer R;
|
|
317
|
+
key: infer FK;
|
|
318
|
+
type: infer RT;
|
|
319
|
+
} ? R extends keyof TMapping ? TMapping[R] extends {
|
|
320
|
+
type: infer TTarget;
|
|
321
|
+
} ? RelationConfig<R & string, FK & string, RT & ("one" | "many"), TTarget> : never : never : never;
|
|
322
|
+
/**
|
|
323
|
+
* Helper to add relations to a repository mapping with full type validation
|
|
324
|
+
* Validates that repo names and foreign keys exist in the mapping
|
|
325
|
+
* @template TMapping - The complete repository mapping for validation
|
|
326
|
+
* @template TRelations - Relations configuration with strict typing
|
|
327
|
+
* @param mapping - The base repository mapping
|
|
328
|
+
* @param relations - Relations configuration for each repository
|
|
329
|
+
* @returns Updated mapping with relations and full type safety
|
|
330
|
+
* @example
|
|
331
|
+
* ```typescript
|
|
332
|
+
* const mapping = {
|
|
333
|
+
* users: createRepositoryConfig<UserModel>()({ ... }),
|
|
334
|
+
* posts: createRepositoryConfig<PostModel>()({ ... }),
|
|
335
|
+
* };
|
|
336
|
+
*
|
|
337
|
+
* const mappingWithRelations = buildRepositoryRelations(mapping, {
|
|
338
|
+
* posts: {
|
|
339
|
+
* userId: { repo: "users", key: "docId", type: "one" as const }
|
|
340
|
+
* }
|
|
341
|
+
* });
|
|
342
|
+
*
|
|
343
|
+
* const repos = createRepositoryMapping(db, mappingWithRelations);
|
|
344
|
+
* ```
|
|
345
|
+
*/
|
|
346
|
+
declare function buildRepositoryRelations<TMapping extends Record<string, any>, const TRelations extends {
|
|
347
|
+
[K in keyof TMapping]?: TMapping[K] extends RepositoryConfig<infer T, any, any, any, any, any> ? {
|
|
348
|
+
[RK in keyof T]?: {
|
|
349
|
+
[R in keyof TMapping]: TMapping[R] extends RepositoryConfig<infer TTargetModel, infer TForeignKeys, any, any, any, any> ? {
|
|
350
|
+
repo: R;
|
|
351
|
+
key: TForeignKeys[number];
|
|
352
|
+
type: "one" | "many";
|
|
353
|
+
} : never;
|
|
354
|
+
}[keyof TMapping];
|
|
355
|
+
} : never;
|
|
356
|
+
}>(mapping: TMapping, relations: TRelations): {
|
|
357
|
+
[K in keyof TMapping]: K extends keyof TRelations ? TMapping[K] extends RepositoryConfig<infer T, infer TForeignKeys, infer TQueryKeys, infer TIsGroup, infer TRefCb, any> ? RepositoryConfig<T, TForeignKeys, TQueryKeys, TIsGroup, TRefCb, {
|
|
358
|
+
[RK in keyof TRelations[K]]: ResolveRelation<TMapping, TRelations[K][RK]>;
|
|
359
|
+
}> : TMapping[K] : TMapping[K];
|
|
360
|
+
};
|
|
361
|
+
/**
|
|
362
|
+
* Repository mapping class that manages Firestore repositories with type safety
|
|
363
|
+
* @template T - Record of repository configurations
|
|
364
|
+
*/
|
|
365
|
+
declare class RepositoryMapping<T extends Record<string, any>> {
|
|
366
|
+
private db;
|
|
367
|
+
private repositoryCache;
|
|
368
|
+
private mapping;
|
|
369
|
+
private allRepositories;
|
|
370
|
+
/**
|
|
371
|
+
* Creates a new RepositoryMapping instance
|
|
372
|
+
* @param db - Firestore instance from firebase-admin
|
|
373
|
+
* @param mapping - Repository configuration mapping
|
|
374
|
+
*/
|
|
375
|
+
constructor(db: Firestore, mapping: T);
|
|
376
|
+
/**
|
|
377
|
+
* Initialize all repositories in two passes to handle circular dependencies
|
|
378
|
+
* @private
|
|
379
|
+
*/
|
|
380
|
+
private initializeRepositories;
|
|
381
|
+
/**
|
|
382
|
+
* Gets a repository (already initialized)
|
|
383
|
+
* @template K - Repository key
|
|
384
|
+
* @param key - Repository identifier
|
|
385
|
+
* @returns Configured repository instance
|
|
386
|
+
*/
|
|
387
|
+
getRepository<K extends keyof T>(key: K): ConfiguredRepository<T[K]>;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Helper function to create a RepositoryMapping instance with full typing
|
|
391
|
+
* @template T - Record of repository configurations
|
|
392
|
+
* @param db - Firestore instance from firebase-admin
|
|
393
|
+
* @param mapping - Repository configurations
|
|
394
|
+
* @returns RepositoryMapping instance with repository access via getters
|
|
395
|
+
* @example
|
|
396
|
+
* ```typescript
|
|
397
|
+
* import * as admin from 'firebase-admin';
|
|
398
|
+
*
|
|
399
|
+
* admin.initializeApp();
|
|
400
|
+
* const db = admin.firestore();
|
|
401
|
+
*
|
|
402
|
+
* const repos = createRepositoryMapping(db, {
|
|
403
|
+
* users: createRepositoryConfig<UserModel>()({
|
|
404
|
+
* path: "users",
|
|
405
|
+
* isGroup: false,
|
|
406
|
+
* foreignKeys: ["docId", "email"] as const,
|
|
407
|
+
* queryKeys: ["isActive"] as const,
|
|
408
|
+
* refCb: (db, docId: string) => db.collection("users").doc(docId),
|
|
409
|
+
* }),
|
|
410
|
+
* });
|
|
411
|
+
*
|
|
412
|
+
* // Access repositories directly
|
|
413
|
+
* const user = await repos.users.get.byDocId("123");
|
|
414
|
+
* ```
|
|
415
|
+
*/
|
|
416
|
+
declare function createRepositoryMapping<T extends Record<string, any>>(db: Firestore, mapping: T): RepositoryMapping<T> & {
|
|
417
|
+
[K in keyof T]: ConfiguredRepository<T[K]>;
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
export { type ConfiguredRepository, type ExtractDocumentRefSignature, type ExtractUpdateSignature, type GenerateGetMethods, type GenerateQueryMethods, type GetResult, type PaginationOptions, type PaginationResult, type QueryOptions, type RelationConfig, type RelationalKeys, type RepositoryConfig, RepositoryMapping, type WhereClause, applyQueryOptions as applyPaginationQueryOptions, buildAndExecuteQuery, buildRepositoryRelations, createPaginationIterator, createRepositoryConfig, createRepositoryMapping, executePaginatedQuery };
|