@classytic/mongokit 3.2.0 → 3.2.2
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/README.md +470 -193
- package/dist/actions/index.d.mts +9 -0
- package/dist/actions/index.mjs +15 -0
- package/dist/aggregate-BAi4Do-X.mjs +767 -0
- package/dist/aggregate-CCHI7F51.d.mts +269 -0
- package/dist/ai/index.d.mts +125 -0
- package/dist/ai/index.mjs +203 -0
- package/dist/cache-keys-C8Z9B5sw.mjs +204 -0
- package/dist/chunk-DQk6qfdC.mjs +18 -0
- package/dist/create-BuO6xt0v.mjs +55 -0
- package/dist/custom-id.plugin-B_zIs6gE.mjs +1818 -0
- package/dist/custom-id.plugin-BzZI4gnE.d.mts +893 -0
- package/dist/index.d.mts +1012 -0
- package/dist/index.mjs +1906 -0
- package/dist/limits-DsNeCx4D.mjs +299 -0
- package/dist/logger-D8ily-PP.mjs +51 -0
- package/dist/mongooseToJsonSchema-COdDEkIJ.mjs +317 -0
- package/dist/{mongooseToJsonSchema-CaRF_bCN.d.ts → mongooseToJsonSchema-Wbvjfwkn.d.mts} +16 -89
- package/dist/pagination/PaginationEngine.d.mts +93 -0
- package/dist/pagination/PaginationEngine.mjs +196 -0
- package/dist/plugins/index.d.mts +3 -0
- package/dist/plugins/index.mjs +3 -0
- package/dist/types-D-gploPr.d.mts +1241 -0
- package/dist/utils/{index.d.ts → index.d.mts} +14 -21
- package/dist/utils/index.mjs +5 -0
- package/package.json +21 -21
- package/dist/actions/index.d.ts +0 -3
- package/dist/actions/index.js +0 -5
- package/dist/ai/index.d.ts +0 -175
- package/dist/ai/index.js +0 -206
- package/dist/chunks/chunk-2ZN65ZOP.js +0 -93
- package/dist/chunks/chunk-44KXLGPO.js +0 -388
- package/dist/chunks/chunk-DEVXDBRL.js +0 -1226
- package/dist/chunks/chunk-I7CWNAJB.js +0 -46
- package/dist/chunks/chunk-JWUAVZ3L.js +0 -8
- package/dist/chunks/chunk-UE2IEXZJ.js +0 -306
- package/dist/chunks/chunk-URLJFIR7.js +0 -22
- package/dist/chunks/chunk-VWKIKZYF.js +0 -737
- package/dist/chunks/chunk-WSFCRVEQ.js +0 -7
- package/dist/index-BDn5fSTE.d.ts +0 -516
- package/dist/index.d.ts +0 -1422
- package/dist/index.js +0 -1893
- package/dist/pagination/PaginationEngine.d.ts +0 -117
- package/dist/pagination/PaginationEngine.js +0 -3
- package/dist/plugins/index.d.ts +0 -922
- package/dist/plugins/index.js +0 -6
- package/dist/types-Jni1KgkP.d.ts +0 -780
- package/dist/utils/index.js +0 -5
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,1012 @@
|
|
|
1
|
+
import { $ as SchemaBuilderOptions, A as KeysetPaginationOptions, B as PaginationResult, C as GroupResult, D as InferRawDoc, E as InferDocument, F as ObjectId, G as PopulateSpec, H as Plugin, I as OffsetPaginationOptions, J as RepositoryEvent, K as ReadPreferenceType, L as OffsetPaginationResult, M as Logger, N as MinMaxResult, O as JsonSchema, P as NonNullableFields, Q as RequiredBy, R as OperationOptions, S as FieldRules, St as LookupOptions, T as HttpError, U as PluginFunction, V as PartialBy, W as PluginType, X as RepositoryOperation, Y as RepositoryInstance, Z as RepositoryOptions, _ as DeleteResult, _t as IController, a as AnyModel, at as SortSpec, b as EventPhase, bt as IResponseFormatter, c as CacheOptions, ct as UpdateManyResult, d as CascadeRelation, dt as UserContext, et as SelectSpec, f as CreateInput, ft as ValidationChainOptions, g as DeepPartial, gt as WithTransactionOptions, h as DecodedCursor, ht as WithPlugins, i as AnyDocument, it as SortDirection, j as KeysetPaginationResult, k as KeysOfType, l as CacheStats, lt as UpdateOptions, m as CrudSchemas, mt as ValidatorDefinition, n as AggregatePaginationResult, nt as SoftDeleteOptions, o as CacheAdapter, ot as Strict, p as CreateOptions, pt as ValidationResult, q as RepositoryContext, r as AllPluginMethods, rt as SoftDeleteRepository, s as CacheOperationOptions, st as UpdateInput, t as AggregatePaginationOptions, tt as SoftDeleteFilterMode, u as CascadeOptions, ut as UpdateWithValidationResult, v as EventHandlers, vt as IControllerResponse, w as HookMode, x as FieldPreset, xt as LookupBuilder, y as EventPayload, yt as IRequestContext, z as PaginationConfig } from "./types-D-gploPr.mjs";
|
|
2
|
+
import "./aggregate-CCHI7F51.mjs";
|
|
3
|
+
import { t as index_d_exports } from "./actions/index.mjs";
|
|
4
|
+
import { PaginationEngine } from "./pagination/PaginationEngine.mjs";
|
|
5
|
+
import { A as blockIf, B as timestampPlugin, C as AggregateHelpersMethods, D as MongoOperationsMethods, E as batchOperationsPlugin, I as methodRegistryPlugin, L as SoftDeleteMethods, M as requireField, N as uniqueField, O as mongoOperationsPlugin, P as validationChainPlugin, R as softDeletePlugin, S as subdocumentPlugin, T as BatchOperationsMethods, V as fieldFilterPlugin, _ as multiTenantPlugin, a as SequentialIdOptions, b as cachePlugin, c as getNextSequence, d as ElasticSearchOptions, f as elasticSearchPlugin, g as MultiTenantOptions, h as observabilityPlugin, i as PrefixedIdOptions, j as immutableField, k as autoInject, l as prefixedId, m as OperationMetric, n as DateSequentialIdOptions, o as customIdPlugin, p as ObservabilityOptions, r as IdGenerator, s as dateSequentialId, t as CustomIdOptions, u as sequentialId, v as cascadePlugin, w as aggregateHelpersPlugin, x as SubdocumentMethods, y as CacheMethods, z as auditLogPlugin } from "./custom-id.plugin-BzZI4gnE.mjs";
|
|
6
|
+
import { a as isFieldUpdateAllowed, c as configureLogger, d as filterResponseData, f as getFieldsForUser, i as getSystemManagedFields, l as createError, n as buildCrudSchemasFromMongooseSchema, o as validateUpdateBody, p as getMongooseProjection, r as getImmutableFields, s as createMemoryCache, t as buildCrudSchemasFromModel, u as createFieldPreset } from "./mongooseToJsonSchema-Wbvjfwkn.mjs";
|
|
7
|
+
import * as mongoose$1 from "mongoose";
|
|
8
|
+
import { ClientSession, Expression, Model, PipelineStage, PopulateOptions } from "mongoose";
|
|
9
|
+
|
|
10
|
+
//#region src/query/AggregationBuilder.d.ts
|
|
11
|
+
/** Options for $vectorSearch stage (Atlas only) */
|
|
12
|
+
interface VectorSearchOptions {
|
|
13
|
+
/** Atlas Search index name */
|
|
14
|
+
index: string;
|
|
15
|
+
/** Field path containing the vector embedding */
|
|
16
|
+
path: string;
|
|
17
|
+
/** Query vector to search against */
|
|
18
|
+
queryVector: number[];
|
|
19
|
+
/** Number of candidates to consider (higher = more accurate, slower) */
|
|
20
|
+
numCandidates?: number;
|
|
21
|
+
/** Max results to return */
|
|
22
|
+
limit: number;
|
|
23
|
+
/** Pre-filter documents before vector search */
|
|
24
|
+
filter?: Record<string, unknown>;
|
|
25
|
+
/** Use exact search instead of ANN (slower but precise) */
|
|
26
|
+
exact?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** Result from build() including execution options */
|
|
29
|
+
interface AggregationPlan {
|
|
30
|
+
pipeline: PipelineStage[];
|
|
31
|
+
allowDiskUse: boolean;
|
|
32
|
+
}
|
|
33
|
+
type SortOrder = 1 | -1 | 'asc' | 'desc';
|
|
34
|
+
type SortSpec$2 = Record<string, SortOrder>;
|
|
35
|
+
type ProjectionSpec = Record<string, 0 | 1 | Expression>;
|
|
36
|
+
type GroupSpec = {
|
|
37
|
+
_id: string | Record<string, unknown> | null;
|
|
38
|
+
[key: string]: unknown;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Fluent builder for MongoDB aggregation pipelines
|
|
42
|
+
* Optimized for complex queries at scale
|
|
43
|
+
*/
|
|
44
|
+
declare class AggregationBuilder {
|
|
45
|
+
private pipeline;
|
|
46
|
+
private _diskUse;
|
|
47
|
+
/**
|
|
48
|
+
* Get the current pipeline
|
|
49
|
+
*/
|
|
50
|
+
get(): PipelineStage[];
|
|
51
|
+
/**
|
|
52
|
+
* Build and return the final pipeline
|
|
53
|
+
*/
|
|
54
|
+
build(): PipelineStage[];
|
|
55
|
+
/**
|
|
56
|
+
* Build pipeline with execution options (allowDiskUse, etc.)
|
|
57
|
+
*/
|
|
58
|
+
plan(): AggregationPlan;
|
|
59
|
+
/**
|
|
60
|
+
* Build and execute the pipeline against a model
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const results = await new AggregationBuilder()
|
|
65
|
+
* .match({ status: 'active' })
|
|
66
|
+
* .allowDiskUse()
|
|
67
|
+
* .exec(MyModel);
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
exec<T = unknown>(model: Model<any>, session?: mongoose$1.ClientSession): Promise<T[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Reset the pipeline
|
|
73
|
+
*/
|
|
74
|
+
reset(): this;
|
|
75
|
+
/**
|
|
76
|
+
* Add a raw pipeline stage
|
|
77
|
+
*/
|
|
78
|
+
addStage(stage: PipelineStage): this;
|
|
79
|
+
/**
|
|
80
|
+
* Add multiple raw pipeline stages
|
|
81
|
+
*/
|
|
82
|
+
addStages(stages: PipelineStage[]): this;
|
|
83
|
+
/**
|
|
84
|
+
* $match - Filter documents
|
|
85
|
+
* IMPORTANT: Place $match as early as possible for performance
|
|
86
|
+
*/
|
|
87
|
+
match(query: Record<string, unknown>): this;
|
|
88
|
+
/**
|
|
89
|
+
* $project - Include/exclude fields or compute new fields
|
|
90
|
+
*/
|
|
91
|
+
project(projection: ProjectionSpec): this;
|
|
92
|
+
/**
|
|
93
|
+
* $group - Group documents and compute aggregations
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* .group({
|
|
98
|
+
* _id: '$department',
|
|
99
|
+
* count: { $sum: 1 },
|
|
100
|
+
* avgSalary: { $avg: '$salary' }
|
|
101
|
+
* })
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
group(groupSpec: GroupSpec): this;
|
|
105
|
+
/**
|
|
106
|
+
* $sort - Sort documents
|
|
107
|
+
*/
|
|
108
|
+
sort(sortSpec: SortSpec$2 | string): this;
|
|
109
|
+
/**
|
|
110
|
+
* $limit - Limit number of documents
|
|
111
|
+
*/
|
|
112
|
+
limit(count: number): this;
|
|
113
|
+
/**
|
|
114
|
+
* $skip - Skip documents
|
|
115
|
+
*/
|
|
116
|
+
skip(count: number): this;
|
|
117
|
+
/**
|
|
118
|
+
* $unwind - Deconstruct array field
|
|
119
|
+
*/
|
|
120
|
+
unwind(path: string, preserveNullAndEmptyArrays?: boolean): this;
|
|
121
|
+
/**
|
|
122
|
+
* $addFields - Add new fields or replace existing fields
|
|
123
|
+
*/
|
|
124
|
+
addFields(fields: Record<string, unknown>): this;
|
|
125
|
+
/**
|
|
126
|
+
* $set - Alias for $addFields
|
|
127
|
+
*/
|
|
128
|
+
set(fields: Record<string, unknown>): this;
|
|
129
|
+
/**
|
|
130
|
+
* $unset - Remove fields
|
|
131
|
+
*/
|
|
132
|
+
unset(fields: string | string[]): this;
|
|
133
|
+
/**
|
|
134
|
+
* $replaceRoot - Replace the root document
|
|
135
|
+
*/
|
|
136
|
+
replaceRoot(newRoot: string | Record<string, unknown>): this;
|
|
137
|
+
/**
|
|
138
|
+
* $lookup - Join with another collection (simple form)
|
|
139
|
+
*
|
|
140
|
+
* @param from - Collection to join with
|
|
141
|
+
* @param localField - Field from source collection
|
|
142
|
+
* @param foreignField - Field from target collection
|
|
143
|
+
* @param as - Output field name
|
|
144
|
+
* @param single - Unwrap array to single object
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```typescript
|
|
148
|
+
* // Join employees with departments by slug
|
|
149
|
+
* .lookup('departments', 'deptSlug', 'slug', 'department', true)
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
lookup(from: string, localField: string, foreignField: string, as?: string, single?: boolean): this;
|
|
153
|
+
/**
|
|
154
|
+
* $lookup - Join with another collection (advanced form with pipeline)
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```typescript
|
|
158
|
+
* .lookupWithPipeline({
|
|
159
|
+
* from: 'products',
|
|
160
|
+
* localField: 'productIds',
|
|
161
|
+
* foreignField: 'sku',
|
|
162
|
+
* as: 'products',
|
|
163
|
+
* pipeline: [
|
|
164
|
+
* { $match: { status: 'active' } },
|
|
165
|
+
* { $project: { name: 1, price: 1 } }
|
|
166
|
+
* ]
|
|
167
|
+
* })
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
lookupWithPipeline(options: LookupOptions): this;
|
|
171
|
+
/**
|
|
172
|
+
* Multiple lookups at once
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* .multiLookup([
|
|
177
|
+
* { from: 'departments', localField: 'deptSlug', foreignField: 'slug', single: true },
|
|
178
|
+
* { from: 'managers', localField: 'managerId', foreignField: '_id', single: true }
|
|
179
|
+
* ])
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
multiLookup(lookups: LookupOptions[]): this;
|
|
183
|
+
/**
|
|
184
|
+
* $facet - Process multiple aggregation pipelines in a single stage
|
|
185
|
+
* Useful for computing multiple aggregations in parallel
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* .facet({
|
|
190
|
+
* totalCount: [{ $count: 'count' }],
|
|
191
|
+
* avgPrice: [{ $group: { _id: null, avg: { $avg: '$price' } } }],
|
|
192
|
+
* topProducts: [{ $sort: { sales: -1 } }, { $limit: 10 }]
|
|
193
|
+
* })
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
facet(facets: Record<string, PipelineStage[]>): this;
|
|
197
|
+
/**
|
|
198
|
+
* $bucket - Categorize documents into buckets
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```typescript
|
|
202
|
+
* .bucket({
|
|
203
|
+
* groupBy: '$price',
|
|
204
|
+
* boundaries: [0, 50, 100, 200],
|
|
205
|
+
* default: 'Other',
|
|
206
|
+
* output: {
|
|
207
|
+
* count: { $sum: 1 },
|
|
208
|
+
* products: { $push: '$name' }
|
|
209
|
+
* }
|
|
210
|
+
* })
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
bucket(options: {
|
|
214
|
+
groupBy: string | Expression;
|
|
215
|
+
boundaries: unknown[];
|
|
216
|
+
default?: string;
|
|
217
|
+
output?: Record<string, unknown>;
|
|
218
|
+
}): this;
|
|
219
|
+
/**
|
|
220
|
+
* $bucketAuto - Automatically determine bucket boundaries
|
|
221
|
+
*/
|
|
222
|
+
bucketAuto(options: {
|
|
223
|
+
groupBy: string | Expression;
|
|
224
|
+
buckets: number;
|
|
225
|
+
output?: Record<string, unknown>;
|
|
226
|
+
granularity?: string;
|
|
227
|
+
}): this;
|
|
228
|
+
/**
|
|
229
|
+
* $setWindowFields - Perform window functions (MongoDB 5.0+)
|
|
230
|
+
* Useful for rankings, running totals, moving averages
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```typescript
|
|
234
|
+
* .setWindowFields({
|
|
235
|
+
* partitionBy: '$department',
|
|
236
|
+
* sortBy: { salary: -1 },
|
|
237
|
+
* output: {
|
|
238
|
+
* rank: { $rank: {} },
|
|
239
|
+
* runningTotal: { $sum: '$salary', window: { documents: ['unbounded', 'current'] } }
|
|
240
|
+
* }
|
|
241
|
+
* })
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
244
|
+
setWindowFields(options: {
|
|
245
|
+
partitionBy?: string | Expression;
|
|
246
|
+
sortBy?: SortSpec$2;
|
|
247
|
+
output: Record<string, unknown>;
|
|
248
|
+
}): this;
|
|
249
|
+
/**
|
|
250
|
+
* $unionWith - Combine results from multiple collections (MongoDB 4.4+)
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```typescript
|
|
254
|
+
* .unionWith({
|
|
255
|
+
* coll: 'archivedOrders',
|
|
256
|
+
* pipeline: [{ $match: { year: 2024 } }]
|
|
257
|
+
* })
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
unionWith(options: {
|
|
261
|
+
coll: string;
|
|
262
|
+
pipeline?: PipelineStage[];
|
|
263
|
+
}): this;
|
|
264
|
+
/**
|
|
265
|
+
* $densify - Fill gaps in data (MongoDB 5.1+)
|
|
266
|
+
* Useful for time series data with missing points
|
|
267
|
+
*/
|
|
268
|
+
densify(options: {
|
|
269
|
+
field: string;
|
|
270
|
+
range: {
|
|
271
|
+
step: number;
|
|
272
|
+
unit?: 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year';
|
|
273
|
+
bounds: 'full' | 'partition' | [unknown, unknown];
|
|
274
|
+
};
|
|
275
|
+
}): this;
|
|
276
|
+
/**
|
|
277
|
+
* $fill - Fill null or missing field values (MongoDB 5.3+)
|
|
278
|
+
*/
|
|
279
|
+
fill(options: {
|
|
280
|
+
sortBy?: SortSpec$2;
|
|
281
|
+
output: Record<string, {
|
|
282
|
+
method: 'linear' | 'locf' | 'value';
|
|
283
|
+
value?: unknown;
|
|
284
|
+
}>;
|
|
285
|
+
}): this;
|
|
286
|
+
/**
|
|
287
|
+
* Enable allowDiskUse for large aggregations that exceed 100MB memory limit
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```typescript
|
|
291
|
+
* const results = await new AggregationBuilder()
|
|
292
|
+
* .match({ status: 'active' })
|
|
293
|
+
* .group({ _id: '$category', total: { $sum: '$amount' } })
|
|
294
|
+
* .allowDiskUse()
|
|
295
|
+
* .exec(Model);
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
allowDiskUse(enable?: boolean): this;
|
|
299
|
+
/**
|
|
300
|
+
* Paginate - Add skip and limit for offset-based pagination
|
|
301
|
+
*/
|
|
302
|
+
paginate(page: number, limit: number): this;
|
|
303
|
+
/**
|
|
304
|
+
* Count total documents (useful with $facet for pagination metadata)
|
|
305
|
+
*/
|
|
306
|
+
count(outputField?: string): this;
|
|
307
|
+
/**
|
|
308
|
+
* Sample - Randomly select N documents
|
|
309
|
+
*/
|
|
310
|
+
sample(size: number): this;
|
|
311
|
+
/**
|
|
312
|
+
* Out - Write results to a collection
|
|
313
|
+
*/
|
|
314
|
+
out(collection: string): this;
|
|
315
|
+
/**
|
|
316
|
+
* Merge - Merge results into a collection
|
|
317
|
+
*/
|
|
318
|
+
merge(options: string | {
|
|
319
|
+
into: string;
|
|
320
|
+
on?: string | string[];
|
|
321
|
+
whenMatched?: string;
|
|
322
|
+
whenNotMatched?: string;
|
|
323
|
+
}): this;
|
|
324
|
+
/**
|
|
325
|
+
* GeoNear - Perform geospatial queries
|
|
326
|
+
*/
|
|
327
|
+
geoNear(options: {
|
|
328
|
+
near: {
|
|
329
|
+
type: 'Point';
|
|
330
|
+
coordinates: [number, number];
|
|
331
|
+
};
|
|
332
|
+
distanceField: string;
|
|
333
|
+
maxDistance?: number;
|
|
334
|
+
query?: Record<string, unknown>;
|
|
335
|
+
spherical?: boolean;
|
|
336
|
+
}): this;
|
|
337
|
+
/**
|
|
338
|
+
* GraphLookup - Perform recursive search (graph traversal)
|
|
339
|
+
*/
|
|
340
|
+
graphLookup(options: {
|
|
341
|
+
from: string;
|
|
342
|
+
startWith: string | Expression;
|
|
343
|
+
connectFromField: string;
|
|
344
|
+
connectToField: string;
|
|
345
|
+
as: string;
|
|
346
|
+
maxDepth?: number;
|
|
347
|
+
depthField?: string;
|
|
348
|
+
restrictSearchWithMatch?: Record<string, unknown>;
|
|
349
|
+
}): this;
|
|
350
|
+
/**
|
|
351
|
+
* $search - Atlas Search full-text search (Atlas only)
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* ```typescript
|
|
355
|
+
* .search({
|
|
356
|
+
* index: 'default',
|
|
357
|
+
* text: {
|
|
358
|
+
* query: 'laptop computer',
|
|
359
|
+
* path: ['title', 'description'],
|
|
360
|
+
* fuzzy: { maxEdits: 2 }
|
|
361
|
+
* }
|
|
362
|
+
* })
|
|
363
|
+
* ```
|
|
364
|
+
*/
|
|
365
|
+
search(options: {
|
|
366
|
+
index?: string;
|
|
367
|
+
text?: {
|
|
368
|
+
query: string;
|
|
369
|
+
path: string | string[];
|
|
370
|
+
fuzzy?: {
|
|
371
|
+
maxEdits?: number;
|
|
372
|
+
prefixLength?: number;
|
|
373
|
+
};
|
|
374
|
+
score?: {
|
|
375
|
+
boost?: {
|
|
376
|
+
value?: number;
|
|
377
|
+
};
|
|
378
|
+
};
|
|
379
|
+
};
|
|
380
|
+
compound?: {
|
|
381
|
+
must?: unknown[];
|
|
382
|
+
mustNot?: unknown[];
|
|
383
|
+
should?: unknown[];
|
|
384
|
+
filter?: unknown[];
|
|
385
|
+
};
|
|
386
|
+
autocomplete?: unknown;
|
|
387
|
+
near?: unknown;
|
|
388
|
+
range?: unknown;
|
|
389
|
+
}): this;
|
|
390
|
+
/**
|
|
391
|
+
* $searchMeta - Get Atlas Search metadata (Atlas only)
|
|
392
|
+
*/
|
|
393
|
+
searchMeta(options: Record<string, unknown>): this;
|
|
394
|
+
/**
|
|
395
|
+
* $vectorSearch - Semantic similarity search using vector embeddings (Atlas only)
|
|
396
|
+
*
|
|
397
|
+
* Requires an Atlas Vector Search index on the target field.
|
|
398
|
+
* Must be the first stage in the pipeline.
|
|
399
|
+
*
|
|
400
|
+
* @example
|
|
401
|
+
* ```typescript
|
|
402
|
+
* const results = await new AggregationBuilder()
|
|
403
|
+
* .vectorSearch({
|
|
404
|
+
* index: 'vector_index',
|
|
405
|
+
* path: 'embedding',
|
|
406
|
+
* queryVector: await getEmbedding('running shoes'),
|
|
407
|
+
* limit: 10,
|
|
408
|
+
* numCandidates: 100,
|
|
409
|
+
* filter: { category: 'footwear' }
|
|
410
|
+
* })
|
|
411
|
+
* .project({ embedding: 0, score: { $meta: 'vectorSearchScore' } })
|
|
412
|
+
* .exec(ProductModel);
|
|
413
|
+
* ```
|
|
414
|
+
*/
|
|
415
|
+
vectorSearch(options: VectorSearchOptions): this;
|
|
416
|
+
/**
|
|
417
|
+
* Add vectorSearchScore as a field after $vectorSearch
|
|
418
|
+
* Convenience for `.addFields({ score: { $meta: 'vectorSearchScore' } })`
|
|
419
|
+
*/
|
|
420
|
+
withVectorScore(fieldName?: string): this;
|
|
421
|
+
/**
|
|
422
|
+
* Create a builder from an existing pipeline
|
|
423
|
+
*/
|
|
424
|
+
static from(pipeline: PipelineStage[]): AggregationBuilder;
|
|
425
|
+
/**
|
|
426
|
+
* Create a builder with initial match stage
|
|
427
|
+
*/
|
|
428
|
+
static startWith(query: Record<string, unknown>): AggregationBuilder;
|
|
429
|
+
}
|
|
430
|
+
//#endregion
|
|
431
|
+
//#region src/Repository.d.ts
|
|
432
|
+
type HookListener = (data: any) => void | Promise<void>;
|
|
433
|
+
/**
|
|
434
|
+
* Production-grade repository for MongoDB
|
|
435
|
+
* Event-driven, plugin-based, with smart pagination
|
|
436
|
+
*/
|
|
437
|
+
declare class Repository<TDoc = AnyDocument> {
|
|
438
|
+
readonly Model: Model<TDoc>;
|
|
439
|
+
readonly model: string;
|
|
440
|
+
readonly _hooks: Map<string, HookListener[]>;
|
|
441
|
+
readonly _pagination: PaginationEngine<TDoc>;
|
|
442
|
+
private readonly _hookMode;
|
|
443
|
+
[key: string]: unknown;
|
|
444
|
+
private _hasTextIndex;
|
|
445
|
+
constructor(Model: Model<TDoc, any, any, any>, plugins?: PluginType[], paginationConfig?: PaginationConfig, options?: RepositoryOptions);
|
|
446
|
+
/**
|
|
447
|
+
* Register a plugin
|
|
448
|
+
*/
|
|
449
|
+
use(plugin: PluginType): this;
|
|
450
|
+
/**
|
|
451
|
+
* Register event listener
|
|
452
|
+
*/
|
|
453
|
+
on(event: string, listener: HookListener): this;
|
|
454
|
+
/**
|
|
455
|
+
* Remove a specific event listener
|
|
456
|
+
*/
|
|
457
|
+
off(event: string, listener: HookListener): this;
|
|
458
|
+
/**
|
|
459
|
+
* Remove all listeners for an event, or all listeners entirely
|
|
460
|
+
*/
|
|
461
|
+
removeAllListeners(event?: string): this;
|
|
462
|
+
/**
|
|
463
|
+
* Emit event (sync - for backwards compatibility)
|
|
464
|
+
*/
|
|
465
|
+
emit(event: string, data: unknown): void;
|
|
466
|
+
/**
|
|
467
|
+
* Emit event and await all async handlers
|
|
468
|
+
*/
|
|
469
|
+
emitAsync(event: string, data: unknown): Promise<void>;
|
|
470
|
+
private _emitHook;
|
|
471
|
+
private _emitErrorHook;
|
|
472
|
+
/**
|
|
473
|
+
* Create single document
|
|
474
|
+
*/
|
|
475
|
+
create(data: Record<string, unknown>, options?: {
|
|
476
|
+
session?: ClientSession;
|
|
477
|
+
}): Promise<TDoc>;
|
|
478
|
+
/**
|
|
479
|
+
* Create multiple documents
|
|
480
|
+
*/
|
|
481
|
+
createMany(dataArray: Record<string, unknown>[], options?: {
|
|
482
|
+
session?: ClientSession;
|
|
483
|
+
ordered?: boolean;
|
|
484
|
+
}): Promise<TDoc[]>;
|
|
485
|
+
/**
|
|
486
|
+
* Get document by ID
|
|
487
|
+
*/
|
|
488
|
+
getById(id: string | ObjectId, options?: {
|
|
489
|
+
select?: SelectSpec;
|
|
490
|
+
populate?: PopulateSpec;
|
|
491
|
+
populateOptions?: PopulateOptions[];
|
|
492
|
+
lean?: boolean;
|
|
493
|
+
session?: ClientSession;
|
|
494
|
+
throwOnNotFound?: boolean;
|
|
495
|
+
skipCache?: boolean;
|
|
496
|
+
cacheTtl?: number;
|
|
497
|
+
readPreference?: ReadPreferenceType;
|
|
498
|
+
}): Promise<TDoc | null>;
|
|
499
|
+
/**
|
|
500
|
+
* Get single document by query
|
|
501
|
+
*/
|
|
502
|
+
getByQuery(query: Record<string, unknown>, options?: {
|
|
503
|
+
select?: SelectSpec;
|
|
504
|
+
populate?: PopulateSpec;
|
|
505
|
+
populateOptions?: PopulateOptions[];
|
|
506
|
+
lean?: boolean;
|
|
507
|
+
session?: ClientSession;
|
|
508
|
+
throwOnNotFound?: boolean;
|
|
509
|
+
skipCache?: boolean;
|
|
510
|
+
cacheTtl?: number;
|
|
511
|
+
readPreference?: ReadPreferenceType;
|
|
512
|
+
}): Promise<TDoc | null>;
|
|
513
|
+
/**
|
|
514
|
+
* Unified pagination - auto-detects offset vs keyset based on params
|
|
515
|
+
*
|
|
516
|
+
* Auto-detection logic:
|
|
517
|
+
* - If params has 'cursor' or 'after' → uses keyset pagination (stream)
|
|
518
|
+
* - If params has 'pagination' or 'page' → uses offset pagination (paginate)
|
|
519
|
+
* - Else → defaults to offset pagination with page=1
|
|
520
|
+
*
|
|
521
|
+
* @example
|
|
522
|
+
* // Offset pagination (page-based)
|
|
523
|
+
* await repo.getAll({ page: 1, limit: 50, filters: { status: 'active' } });
|
|
524
|
+
* await repo.getAll({ pagination: { page: 2, limit: 20 } });
|
|
525
|
+
*
|
|
526
|
+
* // Keyset pagination (cursor-based)
|
|
527
|
+
* await repo.getAll({ cursor: 'eyJ2Ij...', limit: 50 });
|
|
528
|
+
* await repo.getAll({ after: 'eyJ2Ij...', sort: { createdAt: -1 } });
|
|
529
|
+
*
|
|
530
|
+
* // Simple query (defaults to page 1)
|
|
531
|
+
* await repo.getAll({ filters: { status: 'active' } });
|
|
532
|
+
*
|
|
533
|
+
* // Skip cache for fresh data
|
|
534
|
+
* await repo.getAll({ filters: { status: 'active' } }, { skipCache: true });
|
|
535
|
+
*/
|
|
536
|
+
getAll(params?: {
|
|
537
|
+
filters?: Record<string, unknown>;
|
|
538
|
+
sort?: SortSpec | string;
|
|
539
|
+
cursor?: string;
|
|
540
|
+
after?: string;
|
|
541
|
+
page?: number;
|
|
542
|
+
pagination?: {
|
|
543
|
+
page?: number;
|
|
544
|
+
limit?: number;
|
|
545
|
+
};
|
|
546
|
+
limit?: number;
|
|
547
|
+
search?: string;
|
|
548
|
+
mode?: "offset" | "keyset";
|
|
549
|
+
hint?: string | Record<string, 1 | -1>;
|
|
550
|
+
maxTimeMS?: number;
|
|
551
|
+
countStrategy?: "exact" | "estimated" | "none";
|
|
552
|
+
readPreference?: ReadPreferenceType; /** Advanced populate options (from QueryParser or Arc's BaseController) */
|
|
553
|
+
populateOptions?: PopulateOptions[];
|
|
554
|
+
}, options?: {
|
|
555
|
+
select?: SelectSpec;
|
|
556
|
+
populate?: PopulateSpec;
|
|
557
|
+
populateOptions?: PopulateOptions[];
|
|
558
|
+
lean?: boolean;
|
|
559
|
+
session?: ClientSession;
|
|
560
|
+
skipCache?: boolean;
|
|
561
|
+
cacheTtl?: number;
|
|
562
|
+
readPreference?: ReadPreferenceType;
|
|
563
|
+
}): Promise<OffsetPaginationResult<TDoc> | KeysetPaginationResult<TDoc>>;
|
|
564
|
+
/**
|
|
565
|
+
* Get or create document
|
|
566
|
+
*/
|
|
567
|
+
getOrCreate(query: Record<string, unknown>, createData: Record<string, unknown>, options?: {
|
|
568
|
+
session?: ClientSession;
|
|
569
|
+
}): Promise<TDoc | null>;
|
|
570
|
+
/**
|
|
571
|
+
* Count documents
|
|
572
|
+
*/
|
|
573
|
+
count(query?: Record<string, unknown>, options?: {
|
|
574
|
+
session?: ClientSession;
|
|
575
|
+
readPreference?: ReadPreferenceType;
|
|
576
|
+
}): Promise<number>;
|
|
577
|
+
/**
|
|
578
|
+
* Check if document exists
|
|
579
|
+
*/
|
|
580
|
+
exists(query: Record<string, unknown>, options?: {
|
|
581
|
+
session?: ClientSession;
|
|
582
|
+
readPreference?: ReadPreferenceType;
|
|
583
|
+
}): Promise<{
|
|
584
|
+
_id: unknown;
|
|
585
|
+
} | null>;
|
|
586
|
+
/**
|
|
587
|
+
* Update document by ID
|
|
588
|
+
*/
|
|
589
|
+
update(id: string | ObjectId, data: Record<string, unknown>, options?: UpdateOptions): Promise<TDoc>;
|
|
590
|
+
/**
|
|
591
|
+
* Delete document by ID
|
|
592
|
+
*/
|
|
593
|
+
delete(id: string | ObjectId, options?: {
|
|
594
|
+
session?: ClientSession;
|
|
595
|
+
}): Promise<{
|
|
596
|
+
success: boolean;
|
|
597
|
+
message: string;
|
|
598
|
+
}>;
|
|
599
|
+
/**
|
|
600
|
+
* Execute aggregation pipeline
|
|
601
|
+
*/
|
|
602
|
+
aggregate<TResult = unknown>(pipeline: PipelineStage[], options?: {
|
|
603
|
+
session?: ClientSession;
|
|
604
|
+
}): Promise<TResult[]>;
|
|
605
|
+
/**
|
|
606
|
+
* Aggregate pipeline with pagination
|
|
607
|
+
* Best for: Complex queries, grouping, joins
|
|
608
|
+
*/
|
|
609
|
+
aggregatePaginate(options?: AggregatePaginationOptions): Promise<AggregatePaginationResult<TDoc>>;
|
|
610
|
+
/**
|
|
611
|
+
* Get distinct values
|
|
612
|
+
*/
|
|
613
|
+
distinct<T = unknown>(field: string, query?: Record<string, unknown>, options?: {
|
|
614
|
+
session?: ClientSession;
|
|
615
|
+
}): Promise<T[]>;
|
|
616
|
+
/**
|
|
617
|
+
* Query with custom field lookups ($lookup)
|
|
618
|
+
* Best for: Joins on slugs, SKUs, codes, or other indexed custom fields
|
|
619
|
+
*
|
|
620
|
+
* @example
|
|
621
|
+
* ```typescript
|
|
622
|
+
* // Join employees with departments using slug instead of ObjectId
|
|
623
|
+
* const employees = await employeeRepo.lookupPopulate({
|
|
624
|
+
* filters: { status: 'active' },
|
|
625
|
+
* lookups: [
|
|
626
|
+
* {
|
|
627
|
+
* from: 'departments',
|
|
628
|
+
* localField: 'departmentSlug',
|
|
629
|
+
* foreignField: 'slug',
|
|
630
|
+
* as: 'department',
|
|
631
|
+
* single: true
|
|
632
|
+
* }
|
|
633
|
+
* ],
|
|
634
|
+
* sort: '-createdAt',
|
|
635
|
+
* page: 1,
|
|
636
|
+
* limit: 50
|
|
637
|
+
* });
|
|
638
|
+
* ```
|
|
639
|
+
*/
|
|
640
|
+
lookupPopulate(options: {
|
|
641
|
+
filters?: Record<string, unknown>;
|
|
642
|
+
lookups: LookupOptions[];
|
|
643
|
+
sort?: SortSpec | string;
|
|
644
|
+
page?: number;
|
|
645
|
+
limit?: number;
|
|
646
|
+
select?: SelectSpec;
|
|
647
|
+
session?: ClientSession;
|
|
648
|
+
readPreference?: ReadPreferenceType;
|
|
649
|
+
}): Promise<{
|
|
650
|
+
data: TDoc[];
|
|
651
|
+
total?: number;
|
|
652
|
+
page?: number;
|
|
653
|
+
limit?: number;
|
|
654
|
+
}>;
|
|
655
|
+
/**
|
|
656
|
+
* Create an aggregation builder for this model
|
|
657
|
+
* Useful for building complex custom aggregations
|
|
658
|
+
*
|
|
659
|
+
* @example
|
|
660
|
+
* ```typescript
|
|
661
|
+
* const pipeline = repo.buildAggregation()
|
|
662
|
+
* .match({ status: 'active' })
|
|
663
|
+
* .lookup('departments', 'deptSlug', 'slug', 'department', true)
|
|
664
|
+
* .group({ _id: '$department', count: { $sum: 1 } })
|
|
665
|
+
* .sort({ count: -1 })
|
|
666
|
+
* .build();
|
|
667
|
+
*
|
|
668
|
+
* const results = await repo.Model.aggregate(pipeline);
|
|
669
|
+
* ```
|
|
670
|
+
*/
|
|
671
|
+
buildAggregation(): AggregationBuilder;
|
|
672
|
+
/**
|
|
673
|
+
* Create a lookup builder
|
|
674
|
+
* Useful for building $lookup stages independently
|
|
675
|
+
*
|
|
676
|
+
* @example
|
|
677
|
+
* ```typescript
|
|
678
|
+
* const lookupStages = repo.buildLookup('departments')
|
|
679
|
+
* .localField('deptSlug')
|
|
680
|
+
* .foreignField('slug')
|
|
681
|
+
* .as('department')
|
|
682
|
+
* .single()
|
|
683
|
+
* .build();
|
|
684
|
+
*
|
|
685
|
+
* const pipeline = [
|
|
686
|
+
* { $match: { status: 'active' } },
|
|
687
|
+
* ...lookupStages
|
|
688
|
+
* ];
|
|
689
|
+
* ```
|
|
690
|
+
*/
|
|
691
|
+
buildLookup(from?: string): LookupBuilder;
|
|
692
|
+
/**
|
|
693
|
+
* Execute callback within a transaction with automatic retry on transient failures.
|
|
694
|
+
*
|
|
695
|
+
* Uses the MongoDB driver's `session.withTransaction()` which automatically retries
|
|
696
|
+
* on `TransientTransactionError` and `UnknownTransactionCommitResult`.
|
|
697
|
+
*
|
|
698
|
+
* The callback always receives a `ClientSession`. When `allowFallback` is true
|
|
699
|
+
* and the MongoDB deployment doesn't support transactions (e.g., standalone),
|
|
700
|
+
* the callback runs without a transaction on the same session.
|
|
701
|
+
*
|
|
702
|
+
* @param callback - Receives a `ClientSession` to pass to repository operations
|
|
703
|
+
* @param options.allowFallback - Run without transaction on standalone MongoDB (default: false)
|
|
704
|
+
* @param options.onFallback - Called when falling back to non-transactional execution
|
|
705
|
+
* @param options.transactionOptions - MongoDB driver transaction options (readConcern, writeConcern, etc.)
|
|
706
|
+
*
|
|
707
|
+
* @example
|
|
708
|
+
* ```typescript
|
|
709
|
+
* const result = await repo.withTransaction(async (session) => {
|
|
710
|
+
* const order = await repo.create({ total: 100 }, { session });
|
|
711
|
+
* await paymentRepo.create({ orderId: order._id }, { session });
|
|
712
|
+
* return order;
|
|
713
|
+
* });
|
|
714
|
+
*
|
|
715
|
+
* // With fallback for standalone/dev environments
|
|
716
|
+
* await repo.withTransaction(callback, {
|
|
717
|
+
* allowFallback: true,
|
|
718
|
+
* onFallback: (err) => logger.warn('Running without transaction', err),
|
|
719
|
+
* });
|
|
720
|
+
* ```
|
|
721
|
+
*/
|
|
722
|
+
withTransaction<T>(callback: (session: ClientSession) => Promise<T>, options?: WithTransactionOptions): Promise<T>;
|
|
723
|
+
private _isTransactionUnsupported;
|
|
724
|
+
/**
|
|
725
|
+
* Execute custom query with event emission
|
|
726
|
+
*/
|
|
727
|
+
_executeQuery<T>(buildQuery: (Model: Model<TDoc>) => Promise<T>): Promise<T>;
|
|
728
|
+
/**
|
|
729
|
+
* Build operation context and run before hooks
|
|
730
|
+
*/
|
|
731
|
+
_buildContext(operation: string, options: Record<string, unknown>): Promise<RepositoryContext>;
|
|
732
|
+
/**
|
|
733
|
+
* Parse sort string or object
|
|
734
|
+
*/
|
|
735
|
+
_parseSort(sort: SortSpec | string | undefined): SortSpec;
|
|
736
|
+
/**
|
|
737
|
+
* Parse populate specification
|
|
738
|
+
*/
|
|
739
|
+
_parsePopulate(populate: PopulateSpec | undefined): string[] | PopulateOptions[];
|
|
740
|
+
/**
|
|
741
|
+
* Handle errors with proper HTTP status codes
|
|
742
|
+
*/
|
|
743
|
+
_handleError(error: Error): HttpError;
|
|
744
|
+
}
|
|
745
|
+
//#endregion
|
|
746
|
+
//#region src/query/QueryParser.d.ts
|
|
747
|
+
type SortSpec$1 = Record<string, 1 | -1>;
|
|
748
|
+
type FilterQuery = Record<string, unknown>;
|
|
749
|
+
/**
|
|
750
|
+
* Mongoose-compatible populate option
|
|
751
|
+
* Supports advanced populate with select, match, limit, sort, and nested populate
|
|
752
|
+
*
|
|
753
|
+
* @example
|
|
754
|
+
* ```typescript
|
|
755
|
+
* // URL: ?populate[author][select]=name,email&populate[author][match][active]=true
|
|
756
|
+
* // Generates: { path: 'author', select: 'name email', match: { active: true } }
|
|
757
|
+
* ```
|
|
758
|
+
*/
|
|
759
|
+
interface PopulateOption {
|
|
760
|
+
/** Field path to populate */
|
|
761
|
+
path: string;
|
|
762
|
+
/** Fields to select (space-separated) */
|
|
763
|
+
select?: string;
|
|
764
|
+
/** Filter conditions for populated documents */
|
|
765
|
+
match?: Record<string, unknown>;
|
|
766
|
+
/** Query options (limit, sort, skip) */
|
|
767
|
+
options?: {
|
|
768
|
+
limit?: number;
|
|
769
|
+
sort?: SortSpec$1;
|
|
770
|
+
skip?: number;
|
|
771
|
+
};
|
|
772
|
+
/** Nested populate configuration */
|
|
773
|
+
populate?: PopulateOption;
|
|
774
|
+
}
|
|
775
|
+
/** Parsed query result with optional lookup configuration */
|
|
776
|
+
interface ParsedQuery {
|
|
777
|
+
/** MongoDB filter query */
|
|
778
|
+
filters: FilterQuery;
|
|
779
|
+
/** Sort specification */
|
|
780
|
+
sort?: SortSpec$1;
|
|
781
|
+
/** Fields to populate (simple comma-separated string) */
|
|
782
|
+
populate?: string;
|
|
783
|
+
/**
|
|
784
|
+
* Advanced populate options (Mongoose-compatible)
|
|
785
|
+
* When this is set, `populate` will be undefined
|
|
786
|
+
* @example [{ path: 'author', select: 'name email' }]
|
|
787
|
+
*/
|
|
788
|
+
populateOptions?: PopulateOption[];
|
|
789
|
+
/** Page number for offset pagination */
|
|
790
|
+
page?: number;
|
|
791
|
+
/** Cursor for keyset pagination */
|
|
792
|
+
after?: string;
|
|
793
|
+
/** Limit */
|
|
794
|
+
limit: number;
|
|
795
|
+
/** Full-text search query */
|
|
796
|
+
search?: string;
|
|
797
|
+
/** Lookup configurations for custom field joins */
|
|
798
|
+
lookups?: LookupOptions[];
|
|
799
|
+
/** Aggregation pipeline stages (advanced) */
|
|
800
|
+
aggregation?: PipelineStage[];
|
|
801
|
+
/** Select/project fields */
|
|
802
|
+
select?: Record<string, 0 | 1>;
|
|
803
|
+
}
|
|
804
|
+
/** Search mode for query parser */
|
|
805
|
+
type SearchMode = "text" | "regex";
|
|
806
|
+
interface QueryParserOptions {
|
|
807
|
+
/** Maximum allowed regex pattern length (default: 500) */
|
|
808
|
+
maxRegexLength?: number;
|
|
809
|
+
/** Maximum allowed text search query length (default: 200) */
|
|
810
|
+
maxSearchLength?: number;
|
|
811
|
+
/** Maximum allowed filter depth (default: 10) */
|
|
812
|
+
maxFilterDepth?: number;
|
|
813
|
+
/** Maximum allowed limit value (default: 1000) */
|
|
814
|
+
maxLimit?: number;
|
|
815
|
+
/** Additional operators to block */
|
|
816
|
+
additionalDangerousOperators?: string[];
|
|
817
|
+
/** Enable lookup parsing (default: true) */
|
|
818
|
+
enableLookups?: boolean;
|
|
819
|
+
/** Enable aggregation parsing (default: false - requires explicit opt-in) */
|
|
820
|
+
enableAggregations?: boolean;
|
|
821
|
+
/**
|
|
822
|
+
* Search mode (default: 'text')
|
|
823
|
+
* - 'text': Uses MongoDB $text search (requires text index)
|
|
824
|
+
* - 'regex': Uses $or with $regex across searchFields (no index required)
|
|
825
|
+
*/
|
|
826
|
+
searchMode?: SearchMode;
|
|
827
|
+
/**
|
|
828
|
+
* Fields to search when searchMode is 'regex'
|
|
829
|
+
* Required when searchMode is 'regex'
|
|
830
|
+
* @example ['name', 'description', 'sku', 'tags']
|
|
831
|
+
*/
|
|
832
|
+
searchFields?: string[];
|
|
833
|
+
/**
|
|
834
|
+
* Whitelist of collection names allowed in lookups.
|
|
835
|
+
* When set, only these collections can be used in $lookup stages.
|
|
836
|
+
* When undefined, all collection names are allowed.
|
|
837
|
+
* @example ['departments', 'categories', 'users']
|
|
838
|
+
*/
|
|
839
|
+
allowedLookupCollections?: string[];
|
|
840
|
+
/** Allowed fields for filtering. If set, ignores unknown fields. */
|
|
841
|
+
allowedFilterFields?: string[];
|
|
842
|
+
/** Allowed fields for sorting. If set, ignores unknown fields. */
|
|
843
|
+
allowedSortFields?: string[];
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Modern Query Parser
|
|
847
|
+
* Converts URL parameters to MongoDB queries with $lookup support
|
|
848
|
+
*/
|
|
849
|
+
declare class QueryParser {
|
|
850
|
+
private readonly options;
|
|
851
|
+
private readonly operators;
|
|
852
|
+
private readonly dangerousOperators;
|
|
853
|
+
/**
|
|
854
|
+
* Regex patterns that can cause catastrophic backtracking (ReDoS attacks)
|
|
855
|
+
* Detects:
|
|
856
|
+
* - Quantifiers: {n,m}
|
|
857
|
+
* - Possessive quantifiers: *+, ++, ?+
|
|
858
|
+
* - Nested quantifiers: (a+)+, (a*)*
|
|
859
|
+
* - Backreferences: \1, \2, etc.
|
|
860
|
+
* - Complex character classes: [...]...[...]
|
|
861
|
+
*/
|
|
862
|
+
private readonly dangerousRegexPatterns;
|
|
863
|
+
constructor(options?: QueryParserOptions);
|
|
864
|
+
/**
|
|
865
|
+
* Parse URL query parameters into MongoDB query format
|
|
866
|
+
*
|
|
867
|
+
* @example
|
|
868
|
+
* ```typescript
|
|
869
|
+
* // URL: ?status=active&lookup[department][foreignField]=slug&sort=-createdAt&page=1
|
|
870
|
+
* const query = parser.parse(req.query);
|
|
871
|
+
* // Returns: { filters: {...}, lookups: [...], sort: {...}, page: 1 }
|
|
872
|
+
* ```
|
|
873
|
+
*/
|
|
874
|
+
parse(query: Record<string, unknown> | null | undefined): ParsedQuery;
|
|
875
|
+
/**
|
|
876
|
+
* Parse lookup configurations from URL parameters
|
|
877
|
+
*
|
|
878
|
+
* Supported formats:
|
|
879
|
+
* 1. Simple: ?lookup[department]=slug
|
|
880
|
+
* → Join with 'departments' collection on slug field
|
|
881
|
+
*
|
|
882
|
+
* 2. Detailed: ?lookup[department][localField]=deptSlug&lookup[department][foreignField]=slug
|
|
883
|
+
* → Full control over join configuration
|
|
884
|
+
*
|
|
885
|
+
* 3. Multiple: ?lookup[department]=slug&lookup[category]=categorySlug
|
|
886
|
+
* → Multiple lookups
|
|
887
|
+
*
|
|
888
|
+
* @example
|
|
889
|
+
* ```typescript
|
|
890
|
+
* // URL: ?lookup[department][localField]=deptSlug&lookup[department][foreignField]=slug&lookup[department][single]=true
|
|
891
|
+
* const lookups = parser._parseLookups({
|
|
892
|
+
* department: { localField: 'deptSlug', foreignField: 'slug', single: 'true' }
|
|
893
|
+
* });
|
|
894
|
+
* // Returns: [{ from: 'departments', localField: 'deptSlug', foreignField: 'slug', single: true }]
|
|
895
|
+
* ```
|
|
896
|
+
*/
|
|
897
|
+
private _parseLookups;
|
|
898
|
+
/**
|
|
899
|
+
* Parse a single lookup configuration
|
|
900
|
+
*/
|
|
901
|
+
private _parseSingleLookup;
|
|
902
|
+
/**
|
|
903
|
+
* Parse aggregation pipeline from URL (advanced feature)
|
|
904
|
+
*
|
|
905
|
+
* @example
|
|
906
|
+
* ```typescript
|
|
907
|
+
* // URL: ?aggregate[group][_id]=$status&aggregate[group][count]=$sum:1
|
|
908
|
+
* const pipeline = parser._parseAggregation({
|
|
909
|
+
* group: { _id: '$status', count: '$sum:1' }
|
|
910
|
+
* });
|
|
911
|
+
* ```
|
|
912
|
+
*/
|
|
913
|
+
private _parseAggregation;
|
|
914
|
+
/**
|
|
915
|
+
* Parse select/project fields
|
|
916
|
+
*
|
|
917
|
+
* @example
|
|
918
|
+
* ```typescript
|
|
919
|
+
* // URL: ?select=name,email,-password
|
|
920
|
+
* // Returns: { name: 1, email: 1, password: 0 }
|
|
921
|
+
* ```
|
|
922
|
+
*/
|
|
923
|
+
private _parseSelect;
|
|
924
|
+
/**
|
|
925
|
+
* Parse populate parameter - handles both simple string and advanced object format
|
|
926
|
+
*
|
|
927
|
+
* @example
|
|
928
|
+
* ```typescript
|
|
929
|
+
* // Simple: ?populate=author,category
|
|
930
|
+
* // Returns: { simplePopulate: 'author,category', populateOptions: undefined }
|
|
931
|
+
*
|
|
932
|
+
* // Advanced: ?populate[author][select]=name,email
|
|
933
|
+
* // Returns: { simplePopulate: undefined, populateOptions: [{ path: 'author', select: 'name email' }] }
|
|
934
|
+
* ```
|
|
935
|
+
*/
|
|
936
|
+
private _parsePopulate;
|
|
937
|
+
/**
|
|
938
|
+
* Parse a single populate configuration
|
|
939
|
+
*/
|
|
940
|
+
private _parseSinglePopulate;
|
|
941
|
+
/**
|
|
942
|
+
* Convert populate match values (handles boolean strings, etc.)
|
|
943
|
+
*/
|
|
944
|
+
private _convertPopulateMatch;
|
|
945
|
+
/**
|
|
946
|
+
* Parse filter parameters
|
|
947
|
+
*/
|
|
948
|
+
private _parseFilters;
|
|
949
|
+
/**
|
|
950
|
+
* Handle operator syntax: field[operator]=value
|
|
951
|
+
*/
|
|
952
|
+
private _handleOperatorSyntax;
|
|
953
|
+
/**
|
|
954
|
+
* Handle bracket syntax with object value
|
|
955
|
+
*/
|
|
956
|
+
private _handleBracketSyntax;
|
|
957
|
+
private _parseSort;
|
|
958
|
+
private _toMongoOperator;
|
|
959
|
+
private _createSafeRegex;
|
|
960
|
+
private _escapeRegex;
|
|
961
|
+
/**
|
|
962
|
+
* Sanitize $match configuration to prevent dangerous operators
|
|
963
|
+
* Recursively filters out operators like $where, $function, $accumulator
|
|
964
|
+
*/
|
|
965
|
+
private _sanitizeMatchConfig;
|
|
966
|
+
/**
|
|
967
|
+
* Sanitize pipeline stages for use in $lookup.
|
|
968
|
+
* Blocks dangerous stages ($out, $merge, etc.) and recursively sanitizes
|
|
969
|
+
* operator expressions within $match, $addFields, and $set stages.
|
|
970
|
+
*/
|
|
971
|
+
private _sanitizePipeline;
|
|
972
|
+
/**
|
|
973
|
+
* Recursively sanitize expression objects, blocking dangerous operators
|
|
974
|
+
* like $where, $function, $accumulator inside $addFields/$set stages.
|
|
975
|
+
*/
|
|
976
|
+
private _sanitizeExpressions;
|
|
977
|
+
private _sanitizeSearch;
|
|
978
|
+
/**
|
|
979
|
+
* Build regex-based multi-field search filters
|
|
980
|
+
* Creates an $or query with case-insensitive regex across all searchFields
|
|
981
|
+
*
|
|
982
|
+
* @example
|
|
983
|
+
* // searchFields: ['name', 'description', 'sku']
|
|
984
|
+
* // search: 'azure'
|
|
985
|
+
* // Returns: [
|
|
986
|
+
* // { name: { $regex: /azure/i } },
|
|
987
|
+
* // { description: { $regex: /azure/i } },
|
|
988
|
+
* // { sku: { $regex: /azure/i } }
|
|
989
|
+
* // ]
|
|
990
|
+
*/
|
|
991
|
+
private _buildRegexSearch;
|
|
992
|
+
private _convertValue;
|
|
993
|
+
private _parseOr;
|
|
994
|
+
private _enhanceWithBetween;
|
|
995
|
+
private _pluralize;
|
|
996
|
+
private _capitalize;
|
|
997
|
+
}
|
|
998
|
+
//#endregion
|
|
999
|
+
//#region src/index.d.ts
|
|
1000
|
+
/**
|
|
1001
|
+
* Factory function to create a repository instance
|
|
1002
|
+
*
|
|
1003
|
+
* @param Model - Mongoose model
|
|
1004
|
+
* @param plugins - Array of plugins to apply
|
|
1005
|
+
* @returns Repository instance
|
|
1006
|
+
*
|
|
1007
|
+
* @example
|
|
1008
|
+
* const userRepo = createRepository(UserModel, [timestampPlugin()]);
|
|
1009
|
+
*/
|
|
1010
|
+
declare function createRepository<TDoc>(Model: mongoose$1.Model<TDoc, any, any, any>, plugins?: PluginType[], paginationConfig?: PaginationConfig, options?: RepositoryOptions): Repository<TDoc>;
|
|
1011
|
+
//#endregion
|
|
1012
|
+
export { type AggregateHelpersMethods, type AggregatePaginationOptions, type AggregatePaginationResult, AggregationBuilder, type AllPluginMethods, type AnyDocument, type AnyModel, type BatchOperationsMethods, type CacheAdapter, type CacheMethods, type CacheOperationOptions, type CacheOptions, type CacheStats, type CascadeOptions, type CascadeRelation, type CreateInput, type CreateOptions, type CrudSchemas, type CustomIdOptions, type DateSequentialIdOptions, type DecodedCursor, type DeepPartial, type DeleteResult, type ElasticSearchOptions, type EventHandlers, type EventPayload, type EventPhase, type FieldPreset, type FieldRules, type FilterQuery, type GroupResult, type HookMode, type HttpError, type IController, type IControllerResponse, type IRequestContext, type IResponseFormatter, type IdGenerator, type InferDocument, type InferRawDoc, type JsonSchema, type KeysOfType, type KeysetPaginationOptions, type KeysetPaginationResult, type Logger, LookupBuilder, type LookupOptions, type MinMaxResult, type MongoOperationsMethods, type MultiTenantOptions, type NonNullableFields, type ObjectId, type ObservabilityOptions, type OffsetPaginationOptions, type OffsetPaginationResult, type OperationMetric, type OperationOptions, type PaginationConfig, PaginationEngine, type PaginationResult, type ParsedQuery, type PartialBy, type Plugin, type PluginFunction, type PluginType, type PopulateOption, type PopulateSpec, type PrefixedIdOptions, QueryParser, type QueryParserOptions, type ReadPreferenceType, Repository, Repository as default, type RepositoryContext, type RepositoryEvent, type RepositoryInstance, type RepositoryOperation, type RepositoryOptions, type RequiredBy, type SchemaBuilderOptions, type SearchMode, type SelectSpec, type SequentialIdOptions, type SoftDeleteFilterMode, type SoftDeleteMethods, type SoftDeleteOptions, type SoftDeleteRepository, type SortDirection, type SortSpec, type Strict, type SubdocumentMethods, type UpdateInput, type UpdateManyResult, type UpdateOptions, type UpdateWithValidationResult, type UserContext, type ValidationChainOptions, type ValidationResult, type ValidatorDefinition, type WithPlugins, type WithTransactionOptions, index_d_exports as actions, aggregateHelpersPlugin, auditLogPlugin, autoInject, batchOperationsPlugin, blockIf, buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, cachePlugin, cascadePlugin, configureLogger, createError, createFieldPreset, createMemoryCache, createRepository, customIdPlugin, dateSequentialId, elasticSearchPlugin, fieldFilterPlugin, filterResponseData, getFieldsForUser, getImmutableFields, getMongooseProjection, getNextSequence, getSystemManagedFields, immutableField, isFieldUpdateAllowed, methodRegistryPlugin, mongoOperationsPlugin, multiTenantPlugin, observabilityPlugin, prefixedId, requireField, sequentialId, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validateUpdateBody, validationChainPlugin };
|