@classytic/mongokit 3.0.0 → 3.0.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 +251 -846
- package/dist/actions/index.d.ts +2 -2
- package/dist/actions/index.js +13 -2
- package/dist/{index-CgOJ2pqz.d.ts → index-CMCrkd2v.d.ts} +11 -11
- package/dist/index.d.ts +19 -17
- package/dist/index.js +250 -23
- package/dist/{memory-cache-DG2oSSbx.d.ts → memory-cache-Bn_-Kk-0.d.ts} +1 -1
- package/dist/pagination/PaginationEngine.d.ts +1 -1
- package/dist/pagination/PaginationEngine.js +0 -2
- package/dist/plugins/index.d.ts +37 -2
- package/dist/plugins/index.js +181 -4
- package/dist/{types-Nxhmi1aI.d.ts → types-B3dPUKjs.d.ts} +28 -2
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +0 -2
- package/package.json +2 -1
- package/dist/actions/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/pagination/PaginationEngine.js.map +0 -1
- package/dist/plugins/index.js.map +0 -1
- package/dist/utils/index.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Model } from 'mongoose';
|
|
2
|
-
import { A as AnyDocument, P as PaginationConfig, O as OffsetPaginationOptions, a as OffsetPaginationResult, K as KeysetPaginationOptions, b as KeysetPaginationResult, c as AggregatePaginationOptions, d as AggregatePaginationResult } from '../types-
|
|
2
|
+
import { A as AnyDocument, P as PaginationConfig, O as OffsetPaginationOptions, a as OffsetPaginationResult, K as KeysetPaginationOptions, b as KeysetPaginationResult, c as AggregatePaginationOptions, d as AggregatePaginationResult } from '../types-B3dPUKjs.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Pagination Engine
|
package/dist/plugins/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { F as FieldPreset,
|
|
1
|
+
import { F as FieldPreset, r as Plugin, L as Logger, I as SoftDeleteOptions, t as RepositoryInstance, B as ValidatorDefinition, G as ValidationChainOptions, i as RepositoryContext, W as CacheOptions, _ as CascadeOptions } from '../types-B3dPUKjs.js';
|
|
2
2
|
import 'mongoose';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -272,4 +272,39 @@ declare function subdocumentPlugin(): Plugin;
|
|
|
272
272
|
*/
|
|
273
273
|
declare function cachePlugin(options: CacheOptions): Plugin;
|
|
274
274
|
|
|
275
|
-
|
|
275
|
+
/**
|
|
276
|
+
* Cascade Delete Plugin
|
|
277
|
+
* Automatically deletes related documents when a parent document is deleted
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```typescript
|
|
281
|
+
* import mongoose from 'mongoose';
|
|
282
|
+
* import { Repository, cascadePlugin, methodRegistryPlugin } from '@classytic/mongokit';
|
|
283
|
+
*
|
|
284
|
+
* const productRepo = new Repository(Product, [
|
|
285
|
+
* methodRegistryPlugin(),
|
|
286
|
+
* cascadePlugin({
|
|
287
|
+
* relations: [
|
|
288
|
+
* { model: 'StockEntry', foreignKey: 'product' },
|
|
289
|
+
* { model: 'StockMovement', foreignKey: 'product' },
|
|
290
|
+
* ]
|
|
291
|
+
* })
|
|
292
|
+
* ]);
|
|
293
|
+
*
|
|
294
|
+
* // When a product is deleted, all related StockEntry and StockMovement docs are also deleted
|
|
295
|
+
* await productRepo.delete(productId);
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Cascade delete plugin
|
|
301
|
+
*
|
|
302
|
+
* Deletes related documents after the parent document is deleted.
|
|
303
|
+
* Works with both hard delete and soft delete scenarios.
|
|
304
|
+
*
|
|
305
|
+
* @param options - Cascade configuration
|
|
306
|
+
* @returns Plugin
|
|
307
|
+
*/
|
|
308
|
+
declare function cascadePlugin(options: CascadeOptions): Plugin;
|
|
309
|
+
|
|
310
|
+
export { type MethodRegistryRepository, aggregateHelpersPlugin, auditLogPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, fieldFilterPlugin, immutableField, methodRegistryPlugin, mongoOperationsPlugin, requireField, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin };
|
package/dist/plugins/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import mongoose from 'mongoose';
|
|
2
|
+
|
|
1
3
|
// src/utils/field-selection.ts
|
|
2
4
|
function getFieldsForUser(user, preset) {
|
|
3
5
|
if (!preset) {
|
|
@@ -420,9 +422,16 @@ function batchOperationsPlugin() {
|
|
|
420
422
|
const context = await _buildContext.call(this, "updateMany", { query, data, options });
|
|
421
423
|
try {
|
|
422
424
|
this.emit("before:updateMany", context);
|
|
425
|
+
if (Array.isArray(data) && options.updatePipeline !== true) {
|
|
426
|
+
throw createError(
|
|
427
|
+
400,
|
|
428
|
+
"Update pipelines (array updates) are disabled by default; pass `{ updatePipeline: true }` to explicitly allow pipeline-style updates."
|
|
429
|
+
);
|
|
430
|
+
}
|
|
423
431
|
const result = await this.Model.updateMany(query, data, {
|
|
424
432
|
runValidators: true,
|
|
425
|
-
session: options.session
|
|
433
|
+
session: options.session,
|
|
434
|
+
...options.updatePipeline !== void 0 ? { updatePipeline: options.updatePipeline } : {}
|
|
426
435
|
}).exec();
|
|
427
436
|
this.emit("after:updateMany", { context, result });
|
|
428
437
|
return result;
|
|
@@ -851,7 +860,175 @@ function cachePlugin(options) {
|
|
|
851
860
|
}
|
|
852
861
|
};
|
|
853
862
|
}
|
|
863
|
+
function cascadePlugin(options) {
|
|
864
|
+
const { relations, parallel = true, logger } = options;
|
|
865
|
+
if (!relations || relations.length === 0) {
|
|
866
|
+
throw new Error("cascadePlugin requires at least one relation");
|
|
867
|
+
}
|
|
868
|
+
return {
|
|
869
|
+
name: "cascade",
|
|
870
|
+
apply(repo) {
|
|
871
|
+
repo.on("after:delete", async (payload) => {
|
|
872
|
+
const { context } = payload;
|
|
873
|
+
const deletedId = context.id;
|
|
874
|
+
if (!deletedId) {
|
|
875
|
+
logger?.warn?.("Cascade delete skipped: no document ID in context", {
|
|
876
|
+
model: context.model
|
|
877
|
+
});
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
const isSoftDelete = context.softDeleted === true;
|
|
881
|
+
const cascadeDelete = async (relation) => {
|
|
882
|
+
const RelatedModel = mongoose.models[relation.model];
|
|
883
|
+
if (!RelatedModel) {
|
|
884
|
+
logger?.warn?.(`Cascade delete skipped: model '${relation.model}' not found`, {
|
|
885
|
+
parentModel: context.model,
|
|
886
|
+
parentId: String(deletedId)
|
|
887
|
+
});
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
const query = { [relation.foreignKey]: deletedId };
|
|
891
|
+
try {
|
|
892
|
+
const shouldSoftDelete = relation.softDelete ?? isSoftDelete;
|
|
893
|
+
if (shouldSoftDelete) {
|
|
894
|
+
const updateResult = await RelatedModel.updateMany(
|
|
895
|
+
query,
|
|
896
|
+
{
|
|
897
|
+
deletedAt: /* @__PURE__ */ new Date(),
|
|
898
|
+
...context.user ? { deletedBy: context.user._id || context.user.id } : {}
|
|
899
|
+
},
|
|
900
|
+
{ session: context.session }
|
|
901
|
+
);
|
|
902
|
+
logger?.info?.(`Cascade soft-deleted ${updateResult.modifiedCount} documents`, {
|
|
903
|
+
parentModel: context.model,
|
|
904
|
+
parentId: String(deletedId),
|
|
905
|
+
relatedModel: relation.model,
|
|
906
|
+
foreignKey: relation.foreignKey,
|
|
907
|
+
count: updateResult.modifiedCount
|
|
908
|
+
});
|
|
909
|
+
} else {
|
|
910
|
+
const deleteResult = await RelatedModel.deleteMany(query, {
|
|
911
|
+
session: context.session
|
|
912
|
+
});
|
|
913
|
+
logger?.info?.(`Cascade deleted ${deleteResult.deletedCount} documents`, {
|
|
914
|
+
parentModel: context.model,
|
|
915
|
+
parentId: String(deletedId),
|
|
916
|
+
relatedModel: relation.model,
|
|
917
|
+
foreignKey: relation.foreignKey,
|
|
918
|
+
count: deleteResult.deletedCount
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
} catch (error) {
|
|
922
|
+
logger?.error?.(`Cascade delete failed for model '${relation.model}'`, {
|
|
923
|
+
parentModel: context.model,
|
|
924
|
+
parentId: String(deletedId),
|
|
925
|
+
relatedModel: relation.model,
|
|
926
|
+
foreignKey: relation.foreignKey,
|
|
927
|
+
error: error.message
|
|
928
|
+
});
|
|
929
|
+
throw error;
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
if (parallel) {
|
|
933
|
+
await Promise.all(relations.map(cascadeDelete));
|
|
934
|
+
} else {
|
|
935
|
+
for (const relation of relations) {
|
|
936
|
+
await cascadeDelete(relation);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
});
|
|
940
|
+
repo.on("after:deleteMany", async (payload) => {
|
|
941
|
+
const { context, result } = payload;
|
|
942
|
+
const query = context.query;
|
|
943
|
+
if (!query || Object.keys(query).length === 0) {
|
|
944
|
+
logger?.warn?.("Cascade deleteMany skipped: empty query", {
|
|
945
|
+
model: context.model
|
|
946
|
+
});
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
logger?.warn?.("Cascade deleteMany: use before:deleteMany hook for complete cascade support", {
|
|
950
|
+
model: context.model
|
|
951
|
+
});
|
|
952
|
+
});
|
|
953
|
+
repo.on("before:deleteMany", async (context) => {
|
|
954
|
+
const query = context.query;
|
|
955
|
+
if (!query || Object.keys(query).length === 0) {
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
const docs = await repo.Model.find(query, { _id: 1 }).lean().session(context.session ?? null);
|
|
959
|
+
const ids = docs.map((doc) => doc._id);
|
|
960
|
+
context._cascadeIds = ids;
|
|
961
|
+
});
|
|
962
|
+
const originalAfterDeleteMany = repo._hooks.get("after:deleteMany") || [];
|
|
963
|
+
repo._hooks.set("after:deleteMany", [
|
|
964
|
+
...originalAfterDeleteMany,
|
|
965
|
+
async (payload) => {
|
|
966
|
+
const { context } = payload;
|
|
967
|
+
const ids = context._cascadeIds;
|
|
968
|
+
if (!ids || ids.length === 0) {
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
const isSoftDelete = context.softDeleted === true;
|
|
972
|
+
const cascadeDeleteMany = async (relation) => {
|
|
973
|
+
const RelatedModel = mongoose.models[relation.model];
|
|
974
|
+
if (!RelatedModel) {
|
|
975
|
+
logger?.warn?.(`Cascade deleteMany skipped: model '${relation.model}' not found`, {
|
|
976
|
+
parentModel: context.model
|
|
977
|
+
});
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
const query = { [relation.foreignKey]: { $in: ids } };
|
|
981
|
+
const shouldSoftDelete = relation.softDelete ?? isSoftDelete;
|
|
982
|
+
try {
|
|
983
|
+
if (shouldSoftDelete) {
|
|
984
|
+
const updateResult = await RelatedModel.updateMany(
|
|
985
|
+
query,
|
|
986
|
+
{
|
|
987
|
+
deletedAt: /* @__PURE__ */ new Date(),
|
|
988
|
+
...context.user ? { deletedBy: context.user._id || context.user.id } : {}
|
|
989
|
+
},
|
|
990
|
+
{ session: context.session }
|
|
991
|
+
);
|
|
992
|
+
logger?.info?.(`Cascade soft-deleted ${updateResult.modifiedCount} documents (bulk)`, {
|
|
993
|
+
parentModel: context.model,
|
|
994
|
+
parentCount: ids.length,
|
|
995
|
+
relatedModel: relation.model,
|
|
996
|
+
foreignKey: relation.foreignKey,
|
|
997
|
+
count: updateResult.modifiedCount
|
|
998
|
+
});
|
|
999
|
+
} else {
|
|
1000
|
+
const deleteResult = await RelatedModel.deleteMany(query, {
|
|
1001
|
+
session: context.session
|
|
1002
|
+
});
|
|
1003
|
+
logger?.info?.(`Cascade deleted ${deleteResult.deletedCount} documents (bulk)`, {
|
|
1004
|
+
parentModel: context.model,
|
|
1005
|
+
parentCount: ids.length,
|
|
1006
|
+
relatedModel: relation.model,
|
|
1007
|
+
foreignKey: relation.foreignKey,
|
|
1008
|
+
count: deleteResult.deletedCount
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
} catch (error) {
|
|
1012
|
+
logger?.error?.(`Cascade deleteMany failed for model '${relation.model}'`, {
|
|
1013
|
+
parentModel: context.model,
|
|
1014
|
+
relatedModel: relation.model,
|
|
1015
|
+
foreignKey: relation.foreignKey,
|
|
1016
|
+
error: error.message
|
|
1017
|
+
});
|
|
1018
|
+
throw error;
|
|
1019
|
+
}
|
|
1020
|
+
};
|
|
1021
|
+
if (parallel) {
|
|
1022
|
+
await Promise.all(relations.map(cascadeDeleteMany));
|
|
1023
|
+
} else {
|
|
1024
|
+
for (const relation of relations) {
|
|
1025
|
+
await cascadeDeleteMany(relation);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
]);
|
|
1030
|
+
}
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
854
1033
|
|
|
855
|
-
export { aggregateHelpersPlugin, auditLogPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, fieldFilterPlugin, immutableField, methodRegistryPlugin, mongoOperationsPlugin, requireField, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin };
|
|
856
|
-
//# sourceMappingURL=index.js.map
|
|
857
|
-
//# sourceMappingURL=index.js.map
|
|
1034
|
+
export { aggregateHelpersPlugin, auditLogPlugin, autoInject, batchOperationsPlugin, blockIf, cachePlugin, cascadePlugin, fieldFilterPlugin, immutableField, methodRegistryPlugin, mongoOperationsPlugin, requireField, softDeletePlugin, subdocumentPlugin, timestampPlugin, uniqueField, validationChainPlugin };
|
|
@@ -24,6 +24,13 @@ type PopulateSpec = string | string[] | PopulateOptions | PopulateOptions[];
|
|
|
24
24
|
type SelectSpec = string | string[] | Record<string, 0 | 1>;
|
|
25
25
|
/** Filter query type for MongoDB queries (compatible with Mongoose 8 & 9) */
|
|
26
26
|
type FilterQuery<T> = Record<string, unknown>;
|
|
27
|
+
/** Hook execution mode */
|
|
28
|
+
type HookMode = 'sync' | 'async';
|
|
29
|
+
/** Repository options */
|
|
30
|
+
interface RepositoryOptions {
|
|
31
|
+
/** Whether repository event hooks are awaited */
|
|
32
|
+
hooks?: HookMode;
|
|
33
|
+
}
|
|
27
34
|
/** Pagination configuration */
|
|
28
35
|
interface PaginationConfig {
|
|
29
36
|
/** Default number of documents per page (default: 10) */
|
|
@@ -253,12 +260,13 @@ interface RepositoryInstance {
|
|
|
253
260
|
use(plugin: PluginType): this;
|
|
254
261
|
on(event: string, listener: (data: any) => void | Promise<void>): this;
|
|
255
262
|
emit(event: string, data: unknown): void;
|
|
263
|
+
emitAsync(event: string, data: unknown): Promise<void>;
|
|
256
264
|
registerMethod?(name: string, fn: Function): void;
|
|
257
265
|
hasMethod?(name: string): boolean;
|
|
258
266
|
[key: string]: unknown;
|
|
259
267
|
}
|
|
260
268
|
/** Repository event names */
|
|
261
|
-
type RepositoryEvent = 'before:create' | 'after:create' | 'error:create' | 'before:createMany' | 'after:createMany' | 'error:createMany' | 'before:update' | 'after:update' | 'error:update' | 'before:updateMany' | 'after:updateMany' | 'error:updateMany' | 'before:delete' | 'after:delete' | 'error:delete' | 'before:deleteMany' | 'after:deleteMany' | 'error:deleteMany' | 'before:getById' | 'after:getById' | 'before:getByQuery' | 'after:getByQuery' | 'before:getAll' | 'after:getAll' | 'before:aggregatePaginate' | 'method:registered';
|
|
269
|
+
type RepositoryEvent = 'before:create' | 'after:create' | 'error:create' | 'before:createMany' | 'after:createMany' | 'error:createMany' | 'before:update' | 'after:update' | 'error:update' | 'before:updateMany' | 'after:updateMany' | 'error:updateMany' | 'before:delete' | 'after:delete' | 'error:delete' | 'before:deleteMany' | 'after:deleteMany' | 'error:deleteMany' | 'before:getById' | 'after:getById' | 'before:getByQuery' | 'after:getByQuery' | 'before:getAll' | 'after:getAll' | 'before:aggregatePaginate' | 'method:registered' | 'error:hook';
|
|
262
270
|
/** Event payload */
|
|
263
271
|
interface EventPayload {
|
|
264
272
|
context: RepositoryContext;
|
|
@@ -498,6 +506,24 @@ interface CacheStats {
|
|
|
498
506
|
sets: number;
|
|
499
507
|
invalidations: number;
|
|
500
508
|
}
|
|
509
|
+
/** Cascade relation definition */
|
|
510
|
+
interface CascadeRelation {
|
|
511
|
+
/** Model name to cascade delete to */
|
|
512
|
+
model: string;
|
|
513
|
+
/** Foreign key field in the related model that references the deleted document */
|
|
514
|
+
foreignKey: string;
|
|
515
|
+
/** Whether to use soft delete if available (default: follows parent behavior) */
|
|
516
|
+
softDelete?: boolean;
|
|
517
|
+
}
|
|
518
|
+
/** Cascade delete plugin options */
|
|
519
|
+
interface CascadeOptions {
|
|
520
|
+
/** Relations to cascade delete */
|
|
521
|
+
relations: CascadeRelation[];
|
|
522
|
+
/** Run cascade deletes in parallel (default: true) */
|
|
523
|
+
parallel?: boolean;
|
|
524
|
+
/** Logger for cascade operations */
|
|
525
|
+
logger?: Logger;
|
|
526
|
+
}
|
|
501
527
|
/** HTTP Error with status code */
|
|
502
528
|
interface HttpError extends Error {
|
|
503
529
|
status: number;
|
|
@@ -507,4 +533,4 @@ interface HttpError extends Error {
|
|
|
507
533
|
}>;
|
|
508
534
|
}
|
|
509
535
|
|
|
510
|
-
export type { AnyDocument as A,
|
|
536
|
+
export type { AnyDocument as A, ValidatorDefinition as B, CreateOptions as C, DeleteResult as D, EventPayload as E, FieldPreset as F, ValidationChainOptions as G, HttpError as H, SoftDeleteOptions as I, JsonSchema as J, KeysetPaginationOptions as K, Logger as L, LookupOptions as M, GroupResult as N, OffsetPaginationOptions as O, PaginationConfig as P, MinMaxResult as Q, RepositoryOptions as R, SelectSpec as S, CacheAdapter as T, UpdateOptions as U, ValidationResult as V, CacheOptions as W, CacheOperationOptions as X, CacheStats as Y, CascadeRelation as Z, CascadeOptions as _, OffsetPaginationResult as a, KeysetPaginationResult as b, AggregatePaginationOptions as c, AggregatePaginationResult as d, PluginType as e, ObjectId as f, PopulateSpec as g, SortSpec as h, RepositoryContext as i, AnyModel as j, SortDirection as k, HookMode as l, PaginationResult as m, OperationOptions as n, UpdateManyResult as o, UpdateWithValidationResult as p, UserContext as q, Plugin as r, PluginFunction as s, RepositoryInstance as t, RepositoryEvent as u, ParsedQuery as v, FieldRules as w, SchemaBuilderOptions as x, CrudSchemas as y, DecodedCursor as z };
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { b as createError, c as createFieldPreset, d as createMemoryCache, f as filterResponseData, g as getFieldsForUser, a as getMongooseProjection } from '../memory-cache-
|
|
2
|
-
import {
|
|
1
|
+
export { b as createError, c as createFieldPreset, d as createMemoryCache, f as filterResponseData, g as getFieldsForUser, a as getMongooseProjection } from '../memory-cache-Bn_-Kk-0.js';
|
|
2
|
+
import { v as ParsedQuery, x as SchemaBuilderOptions, y as CrudSchemas, V as ValidationResult, S as SelectSpec, g as PopulateSpec, h as SortSpec } from '../types-B3dPUKjs.js';
|
|
3
3
|
import mongoose__default, { Schema } from 'mongoose';
|
|
4
4
|
|
|
5
5
|
/**
|
package/dist/utils/index.js
CHANGED
|
@@ -639,5 +639,3 @@ function listPattern(prefix, model) {
|
|
|
639
639
|
}
|
|
640
640
|
|
|
641
641
|
export { buildCrudSchemasFromModel, buildCrudSchemasFromMongooseSchema, byIdKey, byQueryKey, createError, createFieldPreset, createMemoryCache, filterResponseData, getFieldsForUser, getImmutableFields, getMongooseProjection, getSystemManagedFields, isFieldUpdateAllowed, listPattern, listQueryKey, modelPattern, queryParser_default as queryParser, validateUpdateBody, versionKey };
|
|
642
|
-
//# sourceMappingURL=index.js.map
|
|
643
|
-
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/mongokit",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "Production-grade MongoDB repositories with zero dependencies - smart pagination, events, and plugins",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -91,6 +91,7 @@
|
|
|
91
91
|
"devDependencies": {
|
|
92
92
|
"@types/node": "^22.0.0",
|
|
93
93
|
"@vitest/coverage-v8": "^3.2.4",
|
|
94
|
+
"mongodb-memory-server": "^10.2.3",
|
|
94
95
|
"mongoose": "^9.0.0",
|
|
95
96
|
"tsup": "^8.0.0",
|
|
96
97
|
"typescript": "^5.7.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/actions/create.ts","../../src/actions/read.ts","../../src/utils/error.ts","../../src/actions/update.ts","../../src/actions/delete.ts","../../src/actions/aggregate.ts"],"names":["parsePopulate"],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * Create Actions\r\n * Pure functions for document creation\r\n */\r\n\r\nimport type { Model, ClientSession, SchemaType } from 'mongoose';\r\nimport type { CreateOptions, AnyDocument } from '../types.js';\r\n\r\n/**\r\n * Create single document\r\n */\r\nexport async function create<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n data: Record<string, unknown>,\r\n options: CreateOptions = {}\r\n): Promise<TDoc> {\r\n const document = new Model(data);\r\n await document.save({ session: options.session });\r\n return document as TDoc;\r\n}\r\n\r\n/**\r\n * Create multiple documents\r\n */\r\nexport async function createMany<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n dataArray: Record<string, unknown>[],\r\n options: CreateOptions = {}\r\n): Promise<TDoc[]> {\r\n return Model.insertMany(dataArray, {\r\n session: options.session,\r\n ordered: options.ordered !== false,\r\n }) as Promise<TDoc[]>;\r\n}\r\n\r\n/**\r\n * Create with defaults (useful for initialization)\r\n */\r\nexport async function createDefault<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n overrides: Record<string, unknown> = {},\r\n options: CreateOptions = {}\r\n): Promise<TDoc> {\r\n const defaults: Record<string, unknown> = {};\r\n\r\n // Extract defaults from schema\r\n Model.schema.eachPath((path: string, schemaType: SchemaType) => {\r\n const schemaOptions = schemaType.options as { default?: unknown };\r\n if (schemaOptions.default !== undefined && path !== '_id') {\r\n defaults[path] = typeof schemaOptions.default === 'function'\r\n ? schemaOptions.default()\r\n : schemaOptions.default;\r\n }\r\n });\r\n\r\n return create(Model, { ...defaults, ...overrides }, options);\r\n}\r\n\r\n/**\r\n * Upsert (create or update)\r\n */\r\nexport async function upsert<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n query: Record<string, unknown>,\r\n data: Record<string, unknown>,\r\n options: { session?: ClientSession; updatePipeline?: boolean } = {}\r\n): Promise<TDoc | null> {\r\n return Model.findOneAndUpdate(\r\n query,\r\n { $setOnInsert: data },\r\n {\r\n upsert: true,\r\n new: true,\r\n runValidators: true,\r\n session: options.session,\r\n ...(options.updatePipeline !== undefined ? { updatePipeline: options.updatePipeline } : {}),\r\n }\r\n );\r\n}\r\n","/**\r\n * Read Actions\r\n * Pure functions for document retrieval\r\n */\r\n\r\nimport type { Model, ClientSession, PopulateOptions } from 'mongoose';\r\nimport { createError } from '../utils/error.js';\r\nimport type { AnyDocument, SelectSpec, PopulateSpec, SortSpec, OperationOptions } from '../types.js';\r\n\r\n/**\r\n * Parse populate specification into consistent format\r\n */\r\nfunction parsePopulate(populate: PopulateSpec | undefined): (string | PopulateOptions)[] {\r\n if (!populate) return [];\r\n if (typeof populate === 'string') {\r\n return populate.split(',').map(p => p.trim());\r\n }\r\n if (Array.isArray(populate)) {\r\n return populate.map(p => typeof p === 'string' ? p.trim() : p);\r\n }\r\n return [populate];\r\n}\r\n\r\n/**\r\n * Get document by ID\r\n *\r\n * @param Model - Mongoose model\r\n * @param id - Document ID\r\n * @param options - Query options\r\n * @returns Document or null\r\n * @throws Error if document not found and throwOnNotFound is true\r\n */\r\nexport async function getById<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n options: OperationOptions = {}\r\n): Promise<TDoc | null> {\r\n // If additional query filters are provided (e.g., soft delete filter), use findOne\r\n const query = options.query\r\n ? Model.findOne({ _id: id, ...options.query })\r\n : Model.findById(id);\r\n\r\n if (options.select) query.select(options.select);\r\n if (options.populate) query.populate(parsePopulate(options.populate));\r\n if (options.lean) query.lean();\r\n if (options.session) query.session(options.session);\r\n\r\n const document = await query.exec();\r\n if (!document && options.throwOnNotFound !== false) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return document;\r\n}\r\n\r\n/**\r\n * Get document by query\r\n *\r\n * @param Model - Mongoose model\r\n * @param query - MongoDB query\r\n * @param options - Query options\r\n * @returns Document or null\r\n * @throws Error if document not found and throwOnNotFound is true\r\n */\r\nexport async function getByQuery<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n query: Record<string, unknown>,\r\n options: OperationOptions = {}\r\n): Promise<TDoc | null> {\r\n const mongoQuery = Model.findOne(query);\r\n\r\n if (options.select) mongoQuery.select(options.select);\r\n if (options.populate) mongoQuery.populate(parsePopulate(options.populate));\r\n if (options.lean) mongoQuery.lean();\r\n if (options.session) mongoQuery.session(options.session);\r\n\r\n const document = await mongoQuery.exec();\r\n if (!document && options.throwOnNotFound !== false) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return document;\r\n}\r\n\r\n/**\r\n * Get document by query without throwing (returns null if not found)\r\n */\r\nexport async function tryGetByQuery<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n query: Record<string, unknown>,\r\n options: Omit<OperationOptions, 'throwOnNotFound'> = {}\r\n): Promise<TDoc | null> {\r\n return getByQuery(Model, query, { ...options, throwOnNotFound: false });\r\n}\r\n\r\n/**\r\n * Get all documents (basic query without pagination)\r\n * For pagination, use Repository.paginate() or Repository.stream()\r\n */\r\nexport async function getAll<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n query: Record<string, unknown> = {},\r\n options: {\r\n select?: SelectSpec;\r\n populate?: PopulateSpec;\r\n sort?: SortSpec;\r\n limit?: number;\r\n skip?: number;\r\n lean?: boolean;\r\n session?: ClientSession;\r\n } = {}\r\n): Promise<TDoc[]> {\r\n let mongoQuery = Model.find(query);\r\n\r\n if (options.select) mongoQuery = mongoQuery.select(options.select);\r\n if (options.populate) mongoQuery = mongoQuery.populate(parsePopulate(options.populate));\r\n if (options.sort) mongoQuery = mongoQuery.sort(options.sort);\r\n if (options.limit) mongoQuery = mongoQuery.limit(options.limit);\r\n if (options.skip) mongoQuery = mongoQuery.skip(options.skip);\r\n\r\n mongoQuery = mongoQuery.lean(options.lean !== false);\r\n if (options.session) mongoQuery = mongoQuery.session(options.session);\r\n\r\n return mongoQuery.exec() as Promise<TDoc[]>;\r\n}\r\n\r\n/**\r\n * Get or create document (upsert)\r\n */\r\nexport async function getOrCreate<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n query: Record<string, unknown>,\r\n createData: Record<string, unknown>,\r\n options: { session?: ClientSession; updatePipeline?: boolean } = {}\r\n): Promise<TDoc | null> {\r\n return Model.findOneAndUpdate(\r\n query,\r\n { $setOnInsert: createData },\r\n {\r\n upsert: true,\r\n new: true,\r\n runValidators: true,\r\n session: options.session,\r\n ...(options.updatePipeline !== undefined ? { updatePipeline: options.updatePipeline } : {}),\r\n }\r\n );\r\n}\r\n\r\n/**\r\n * Count documents matching query\r\n */\r\nexport async function count(\r\n Model: Model<any>,\r\n query: Record<string, unknown> = {},\r\n options: { session?: ClientSession } = {}\r\n): Promise<number> {\r\n return Model.countDocuments(query).session(options.session ?? null);\r\n}\r\n\r\n/**\r\n * Check if document exists\r\n */\r\nexport async function exists(\r\n Model: Model<any>,\r\n query: Record<string, unknown>,\r\n options: { session?: ClientSession } = {}\r\n): Promise<{ _id: unknown } | null> {\r\n return Model.exists(query).session(options.session ?? null);\r\n}\r\n","/**\r\n * Error Utilities\r\n * \r\n * HTTP-compatible error creation for repository operations\r\n */\r\n\r\nimport type { HttpError } from '../types.js';\r\n\r\n/**\r\n * Creates an error with HTTP status code\r\n *\r\n * @param status - HTTP status code\r\n * @param message - Error message\r\n * @returns Error with status property\r\n * \r\n * @example\r\n * throw createError(404, 'Document not found');\r\n * throw createError(400, 'Invalid input');\r\n * throw createError(403, 'Access denied');\r\n */\r\nexport function createError(status: number, message: string): HttpError {\r\n const error = new Error(message) as HttpError;\r\n error.status = status;\r\n return error;\r\n}\r\n","/**\r\n * Update Actions\r\n * Pure functions for document updates with optimizations\r\n */\r\n\r\nimport type { Model, ClientSession, PopulateOptions } from 'mongoose';\r\nimport { createError } from '../utils/error.js';\r\nimport type { AnyDocument, UpdateOptions, UpdateManyResult, UpdateWithValidationResult } from '../types.js';\r\n\r\n/**\r\n * Parse populate specification into consistent format\r\n */\r\nfunction parsePopulate(populate: unknown): (string | PopulateOptions)[] {\r\n if (!populate) return [];\r\n if (typeof populate === 'string') {\r\n return populate.split(',').map(p => p.trim());\r\n }\r\n if (Array.isArray(populate)) {\r\n return populate.map(p => typeof p === 'string' ? p.trim() : p as PopulateOptions);\r\n }\r\n return [populate as PopulateOptions];\r\n}\r\n\r\n/**\r\n * Update by ID\r\n */\r\nexport async function update<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n data: Record<string, unknown>,\r\n options: UpdateOptions = {}\r\n): Promise<TDoc> {\r\n const document = await Model.findByIdAndUpdate(id, data, {\r\n new: true,\r\n runValidators: true,\r\n session: options.session,\r\n ...(options.updatePipeline !== undefined ? { updatePipeline: options.updatePipeline } : {}),\r\n })\r\n .select(options.select || '')\r\n .populate(parsePopulate(options.populate))\r\n .lean(options.lean ?? false);\r\n\r\n if (!document) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return document as TDoc;\r\n}\r\n\r\n/**\r\n * Update with query constraints (optimized)\r\n * Returns null if constraints not met (not an error)\r\n */\r\nexport async function updateWithConstraints<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n data: Record<string, unknown>,\r\n constraints: Record<string, unknown> = {},\r\n options: UpdateOptions = {}\r\n): Promise<TDoc | null> {\r\n const query = { _id: id, ...constraints };\r\n\r\n const document = await Model.findOneAndUpdate(query, data, {\r\n new: true,\r\n runValidators: true,\r\n session: options.session,\r\n ...(options.updatePipeline !== undefined ? { updatePipeline: options.updatePipeline } : {}),\r\n })\r\n .select(options.select || '')\r\n .populate(parsePopulate(options.populate))\r\n .lean(options.lean ?? false);\r\n\r\n return document as TDoc | null;\r\n}\r\n\r\n/**\r\n * Validation options for smart update\r\n */\r\ninterface ValidationOptions {\r\n buildConstraints?: (data: Record<string, unknown>) => Record<string, unknown>;\r\n validateUpdate?: (\r\n existing: Record<string, unknown>,\r\n data: Record<string, unknown>\r\n ) => { valid: boolean; message?: string; violations?: Array<{ field: string; reason: string }> };\r\n}\r\n\r\n/**\r\n * Update with validation (smart optimization)\r\n * 1-query on success, 2-queries for detailed errors\r\n */\r\nexport async function updateWithValidation<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n data: Record<string, unknown>,\r\n validationOptions: ValidationOptions = {},\r\n options: UpdateOptions = {}\r\n): Promise<UpdateWithValidationResult<TDoc>> {\r\n const { buildConstraints, validateUpdate } = validationOptions;\r\n\r\n // Try optimized update with constraints\r\n if (buildConstraints) {\r\n const constraints = buildConstraints(data);\r\n const document = await updateWithConstraints(Model, id, data, constraints, options);\r\n\r\n if (document) {\r\n return { success: true, data: document };\r\n }\r\n }\r\n\r\n // Fetch for validation\r\n const existing = await Model.findById(id).select(options.select || '').lean();\r\n\r\n if (!existing) {\r\n return {\r\n success: false,\r\n error: {\r\n code: 404,\r\n message: 'Document not found',\r\n },\r\n };\r\n }\r\n\r\n // Run custom validation\r\n if (validateUpdate) {\r\n const validation = validateUpdate(existing as Record<string, unknown>, data);\r\n if (!validation.valid) {\r\n return {\r\n success: false,\r\n error: {\r\n code: 403,\r\n message: validation.message || 'Update not allowed',\r\n violations: validation.violations,\r\n },\r\n };\r\n }\r\n }\r\n\r\n // Validation passed - perform update\r\n const updated = await update(Model, id, data, options);\r\n return { success: true, data: updated };\r\n}\r\n\r\n/**\r\n * Update many documents\r\n */\r\nexport async function updateMany(\r\n Model: Model<unknown>,\r\n query: Record<string, unknown>,\r\n data: Record<string, unknown>,\r\n options: { session?: ClientSession; updatePipeline?: boolean } = {}\r\n): Promise<UpdateManyResult> {\r\n const result = await Model.updateMany(query, data, {\r\n runValidators: true,\r\n session: options.session,\r\n ...(options.updatePipeline !== undefined ? { updatePipeline: options.updatePipeline } : {}),\r\n });\r\n\r\n return {\r\n matchedCount: result.matchedCount,\r\n modifiedCount: result.modifiedCount,\r\n };\r\n}\r\n\r\n/**\r\n * Update by query\r\n */\r\nexport async function updateByQuery<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n query: Record<string, unknown>,\r\n data: Record<string, unknown>,\r\n options: UpdateOptions = {}\r\n): Promise<TDoc | null> {\r\n const document = await Model.findOneAndUpdate(query, data, {\r\n new: true,\r\n runValidators: true,\r\n session: options.session,\r\n ...(options.updatePipeline !== undefined ? { updatePipeline: options.updatePipeline } : {}),\r\n })\r\n .select(options.select || '')\r\n .populate(parsePopulate(options.populate))\r\n .lean(options.lean ?? false);\r\n\r\n if (!document && options.throwOnNotFound !== false) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return document as TDoc | null;\r\n}\r\n\r\n/**\r\n * Increment field\r\n */\r\nexport async function increment<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n field: string,\r\n value: number = 1,\r\n options: UpdateOptions = {}\r\n): Promise<TDoc> {\r\n return update(Model, id, { $inc: { [field]: value } }, options);\r\n}\r\n\r\n/**\r\n * Push to array\r\n */\r\nexport async function pushToArray<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n field: string,\r\n value: unknown,\r\n options: UpdateOptions = {}\r\n): Promise<TDoc> {\r\n return update(Model, id, { $push: { [field]: value } }, options);\r\n}\r\n\r\n/**\r\n * Pull from array\r\n */\r\nexport async function pullFromArray<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n field: string,\r\n value: unknown,\r\n options: UpdateOptions = {}\r\n): Promise<TDoc> {\r\n return update(Model, id, { $pull: { [field]: value } }, options);\r\n}\r\n","/**\r\n * Delete Actions\r\n * Pure functions for document deletion\r\n */\r\n\r\nimport type { Model, ClientSession } from 'mongoose';\r\nimport { createError } from '../utils/error.js';\r\nimport type { DeleteResult, AnyDocument } from '../types.js';\r\n\r\n/**\r\n * Delete by ID\r\n */\r\nexport async function deleteById(\r\n Model: Model<any>,\r\n id: string,\r\n options: { session?: ClientSession } = {}\r\n): Promise<DeleteResult> {\r\n const document = await Model.findByIdAndDelete(id).session(options.session ?? null);\r\n\r\n if (!document) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return { success: true, message: 'Deleted successfully' };\r\n}\r\n\r\n/**\r\n * Delete many documents\r\n */\r\nexport async function deleteMany(\r\n Model: Model<any>,\r\n query: Record<string, unknown>,\r\n options: { session?: ClientSession } = {}\r\n): Promise<DeleteResult> {\r\n const result = await Model.deleteMany(query).session(options.session ?? null);\r\n\r\n return {\r\n success: true,\r\n count: result.deletedCount,\r\n message: 'Deleted successfully',\r\n };\r\n}\r\n\r\n/**\r\n * Delete by query\r\n */\r\nexport async function deleteByQuery(\r\n Model: Model<any>,\r\n query: Record<string, unknown>,\r\n options: { session?: ClientSession; throwOnNotFound?: boolean } = {}\r\n): Promise<DeleteResult> {\r\n const document = await Model.findOneAndDelete(query).session(options.session ?? null);\r\n\r\n if (!document && options.throwOnNotFound !== false) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return { success: true, message: 'Deleted successfully' };\r\n}\r\n\r\n/**\r\n * Soft delete (set deleted flag)\r\n */\r\nexport async function softDelete<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n options: { session?: ClientSession; userId?: string } = {}\r\n): Promise<DeleteResult> {\r\n const document = await Model.findByIdAndUpdate(\r\n id,\r\n {\r\n deleted: true,\r\n deletedAt: new Date(),\r\n deletedBy: options.userId,\r\n },\r\n { new: true, session: options.session }\r\n );\r\n\r\n if (!document) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return { success: true, message: 'Soft deleted successfully' };\r\n}\r\n\r\n/**\r\n * Restore soft deleted document\r\n */\r\nexport async function restore<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n id: string,\r\n options: { session?: ClientSession } = {}\r\n): Promise<DeleteResult> {\r\n const document = await Model.findByIdAndUpdate(\r\n id,\r\n {\r\n deleted: false,\r\n deletedAt: null,\r\n deletedBy: null,\r\n },\r\n { new: true, session: options.session }\r\n );\r\n\r\n if (!document) {\r\n throw createError(404, 'Document not found');\r\n }\r\n\r\n return { success: true, message: 'Restored successfully' };\r\n}\r\n","/**\r\n * Aggregate Actions\r\n * MongoDB aggregation pipeline operations\r\n */\r\n\r\nimport type { Model, ClientSession, PipelineStage } from 'mongoose';\r\nimport type { AnyDocument, LookupOptions, GroupResult, MinMaxResult } from '../types.js';\r\n\r\n/**\r\n * Execute aggregation pipeline\r\n */\r\nexport async function aggregate<TResult = unknown>(\r\n Model: Model<any>,\r\n pipeline: PipelineStage[],\r\n options: { session?: ClientSession } = {}\r\n): Promise<TResult[]> {\r\n const aggregation = Model.aggregate(pipeline);\r\n\r\n if (options.session) {\r\n aggregation.session(options.session);\r\n }\r\n\r\n return aggregation.exec() as Promise<TResult[]>;\r\n}\r\n\r\n/**\r\n * Aggregate with pagination using native MongoDB $facet\r\n * WARNING: $facet results must be <16MB. For larger results (limit >1000),\r\n * consider using Repository.aggregatePaginate() or splitting into separate queries.\r\n */\r\nexport async function aggregatePaginate<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n pipeline: PipelineStage[],\r\n options: { page?: number; limit?: number; session?: ClientSession } = {}\r\n): Promise<{\r\n docs: TDoc[];\r\n total: number;\r\n page: number;\r\n limit: number;\r\n pages: number;\r\n hasNext: boolean;\r\n hasPrev: boolean;\r\n}> {\r\n const page = parseInt(String(options.page || 1), 10);\r\n const limit = parseInt(String(options.limit || 10), 10);\r\n const skip = (page - 1) * limit;\r\n\r\n // 16MB MongoDB document size limit safety check\r\n const SAFE_LIMIT = 1000;\r\n if (limit > SAFE_LIMIT) {\r\n console.warn(\r\n `[mongokit] Large aggregation limit (${limit}). $facet results must be <16MB. ` +\r\n `Consider using Repository.aggregatePaginate() for safer handling of large datasets.`\r\n );\r\n }\r\n\r\n const facetPipeline: PipelineStage[] = [\r\n ...pipeline,\r\n {\r\n $facet: {\r\n docs: [{ $skip: skip }, { $limit: limit }],\r\n total: [{ $count: 'count' }],\r\n },\r\n },\r\n ];\r\n\r\n const aggregation = Model.aggregate(facetPipeline);\r\n if (options.session) {\r\n aggregation.session(options.session);\r\n }\r\n\r\n const [result] = await aggregation.exec() as [{ docs: TDoc[]; total: { count: number }[] }];\r\n const docs = result.docs || [];\r\n const total = result.total[0]?.count || 0;\r\n const pages = Math.ceil(total / limit);\r\n\r\n return {\r\n docs,\r\n total,\r\n page,\r\n limit,\r\n pages,\r\n hasNext: page < pages,\r\n hasPrev: page > 1,\r\n };\r\n}\r\n\r\n/**\r\n * Group documents by field value\r\n */\r\nexport async function groupBy(\r\n Model: Model<any>,\r\n field: string,\r\n options: { limit?: number; session?: ClientSession } = {}\r\n): Promise<GroupResult[]> {\r\n const pipeline: PipelineStage[] = [\r\n { $group: { _id: `$${field}`, count: { $sum: 1 } } },\r\n { $sort: { count: -1 } },\r\n ];\r\n\r\n if (options.limit) {\r\n pipeline.push({ $limit: options.limit });\r\n }\r\n\r\n return aggregate(Model, pipeline, options);\r\n}\r\n\r\n/**\r\n * Count by field values\r\n */\r\nexport async function countBy(\r\n Model: Model<any>,\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: { session?: ClientSession } = {}\r\n): Promise<GroupResult[]> {\r\n const pipeline: PipelineStage[] = [];\r\n\r\n if (Object.keys(query).length > 0) {\r\n pipeline.push({ $match: query });\r\n }\r\n\r\n pipeline.push(\r\n { $group: { _id: `$${field}`, count: { $sum: 1 } } },\r\n { $sort: { count: -1 } }\r\n );\r\n\r\n return aggregate(Model, pipeline, options);\r\n}\r\n\r\n/**\r\n * Lookup (join) with another collection\r\n */\r\nexport async function lookup<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n lookupOptions: LookupOptions\r\n): Promise<TDoc[]> {\r\n const { from, localField, foreignField, as, pipeline = [], query = {}, options = {} } = lookupOptions;\r\n\r\n const aggPipeline: PipelineStage[] = [];\r\n\r\n if (Object.keys(query).length > 0) {\r\n aggPipeline.push({ $match: query });\r\n }\r\n\r\n aggPipeline.push({\r\n $lookup: {\r\n from,\r\n localField,\r\n foreignField,\r\n as,\r\n ...(pipeline.length > 0 ? { pipeline: pipeline as any } : {}),\r\n },\r\n } as any);\r\n\r\n return aggregate(Model, aggPipeline, options);\r\n}\r\n\r\n/**\r\n * Unwind array field\r\n */\r\nexport async function unwind<TDoc = AnyDocument>(\r\n Model: Model<TDoc>,\r\n field: string,\r\n options: { preserveEmpty?: boolean; session?: ClientSession } = {}\r\n): Promise<TDoc[]> {\r\n const pipeline: PipelineStage[] = [\r\n {\r\n $unwind: {\r\n path: `$${field}`,\r\n preserveNullAndEmptyArrays: options.preserveEmpty !== false,\r\n },\r\n },\r\n ];\r\n\r\n return aggregate(Model, pipeline, { session: options.session });\r\n}\r\n\r\n/**\r\n * Facet search (multiple aggregations in one query)\r\n */\r\nexport async function facet<TResult = Record<string, unknown[]>>(\r\n Model: Model<any>,\r\n facets: Record<string, PipelineStage[]>,\r\n options: { session?: ClientSession } = {}\r\n): Promise<TResult[]> {\r\n const pipeline: PipelineStage[] = [{ $facet: facets as any } as any];\r\n\r\n return aggregate(Model, pipeline, options);\r\n}\r\n\r\n/**\r\n * Get distinct values\r\n */\r\nexport async function distinct<T = unknown>(\r\n Model: Model<any>,\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: { session?: ClientSession } = {}\r\n): Promise<T[]> {\r\n return Model.distinct(field, query).session(options.session ?? null) as Promise<T[]>;\r\n}\r\n\r\n/**\r\n * Calculate sum\r\n */\r\nexport async function sum(\r\n Model: Model<any>,\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: { session?: ClientSession } = {}\r\n): Promise<number> {\r\n const pipeline: PipelineStage[] = [];\r\n\r\n if (Object.keys(query).length > 0) {\r\n pipeline.push({ $match: query });\r\n }\r\n\r\n pipeline.push({\r\n $group: {\r\n _id: null,\r\n total: { $sum: `$${field}` },\r\n },\r\n });\r\n\r\n const result = await aggregate<{ total: number }>(Model, pipeline, options);\r\n return result[0]?.total || 0;\r\n}\r\n\r\n/**\r\n * Calculate average\r\n */\r\nexport async function average(\r\n Model: Model<any>,\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: { session?: ClientSession } = {}\r\n): Promise<number> {\r\n const pipeline: PipelineStage[] = [];\r\n\r\n if (Object.keys(query).length > 0) {\r\n pipeline.push({ $match: query });\r\n }\r\n\r\n pipeline.push({\r\n $group: {\r\n _id: null,\r\n average: { $avg: `$${field}` },\r\n },\r\n });\r\n\r\n const result = await aggregate<{ average: number }>(Model, pipeline, options);\r\n return result[0]?.average || 0;\r\n}\r\n\r\n/**\r\n * Min/Max\r\n */\r\nexport async function minMax(\r\n Model: Model<any>,\r\n field: string,\r\n query: Record<string, unknown> = {},\r\n options: { session?: ClientSession } = {}\r\n): Promise<MinMaxResult> {\r\n const pipeline: PipelineStage[] = [];\r\n\r\n if (Object.keys(query).length > 0) {\r\n pipeline.push({ $match: query });\r\n }\r\n\r\n pipeline.push({\r\n $group: {\r\n _id: null,\r\n min: { $min: `$${field}` },\r\n max: { $max: `$${field}` },\r\n },\r\n });\r\n\r\n const result = await aggregate<MinMaxResult>(Model, pipeline, options);\r\n return result[0] || { min: null, max: null };\r\n}\r\n"]}
|