@cyberskill/shared 3.9.0 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/config/env/env.util.js.map +1 -1
  2. package/dist/config/lint-staged/index.js +1 -1
  3. package/dist/config/lint-staged/index.js.map +1 -1
  4. package/dist/config/vitest/vitest.e2e.js +1 -1
  5. package/dist/config/vitest/vitest.unit.js +1 -1
  6. package/dist/constant/response-status.d.ts +4 -0
  7. package/dist/constant/response-status.js.map +1 -1
  8. package/dist/node/express/express.util.d.ts +6 -0
  9. package/dist/node/express/express.util.js +3 -4
  10. package/dist/node/express/express.util.js.map +1 -1
  11. package/dist/node/fs/fs.util.js +14 -14
  12. package/dist/node/mongo/index.js +5 -5
  13. package/dist/node/mongo/mongo.controller.helpers.d.ts +43 -0
  14. package/dist/node/mongo/mongo.controller.helpers.js +20 -0
  15. package/dist/node/mongo/mongo.controller.helpers.js.map +1 -0
  16. package/dist/node/mongo/mongo.controller.mongoose.js +86 -85
  17. package/dist/node/mongo/mongo.controller.mongoose.js.map +1 -1
  18. package/dist/node/mongo/mongo.controller.native.js +65 -93
  19. package/dist/node/mongo/mongo.controller.native.js.map +1 -1
  20. package/dist/node/mongo/mongo.dynamic-populate.d.ts +0 -4
  21. package/dist/node/mongo/mongo.dynamic-populate.js +14 -17
  22. package/dist/node/mongo/mongo.dynamic-populate.js.map +1 -1
  23. package/dist/node/mongo/mongo.util.js +2 -0
  24. package/dist/node/mongo/mongo.util.js.map +1 -1
  25. package/dist/node/storage/index.js +3 -3
  26. package/dist/node/storage/storage.constant.d.ts +0 -3
  27. package/dist/node/storage/storage.constant.js +2 -2
  28. package/dist/node/storage/storage.constant.js.map +1 -1
  29. package/dist/node/storage/storage.type.d.ts +0 -11
  30. package/dist/node/storage/storage.util.d.ts +1 -1
  31. package/dist/node/storage/storage.util.js +65 -67
  32. package/dist/node/storage/storage.util.js.map +1 -1
  33. package/dist/node/upload/upload.type.d.ts +2 -0
  34. package/dist/node/upload/upload.type.js.map +1 -1
  35. package/dist/node/upload/upload.util.js +42 -28
  36. package/dist/node/upload/upload.util.js.map +1 -1
  37. package/dist/node_modules/.pnpm/vitest@4.1.0_@types_node@25.5.0_jsdom@29.0.1_@noble_hashes@1.8.0__vite@8.0.1_@types_nod_5f6c16f4d4385f16c87b17afc93c851f/node_modules/vitest/dist/config.js +8 -0
  38. package/dist/node_modules/.pnpm/{vitest@4.1.0_@types_node@25.5.0_jsdom@29.0.0_@noble_hashes@1.8.0__vite@8.0.0_@types_nod_53aa4254f295b3c40bb8f17b6ab226b5 → vitest@4.1.0_@types_node@25.5.0_jsdom@29.0.1_@noble_hashes@1.8.0__vite@8.0.1_@types_nod_5f6c16f4d4385f16c87b17afc93c851f}/node_modules/vitest/dist/config.js.map +1 -1
  39. package/dist/react/storage/storage.hook.d.ts +1 -1
  40. package/dist/react/storage/storage.hook.js.map +1 -1
  41. package/dist/react/storage/storage.util.d.ts +6 -7
  42. package/dist/react/storage/storage.util.js +15 -10
  43. package/dist/react/storage/storage.util.js.map +1 -1
  44. package/dist/util/common/common.util.d.ts +15 -2
  45. package/dist/util/common/common.util.js +22 -9
  46. package/dist/util/common/common.util.js.map +1 -1
  47. package/dist/util/common/index.js +2 -2
  48. package/dist/util/index.js +7 -7
  49. package/dist/util/object/object.util.d.ts +7 -3
  50. package/dist/util/object/object.util.js.map +1 -1
  51. package/package.json +11 -12
  52. package/dist/node_modules/.pnpm/vitest@4.1.0_@types_node@25.5.0_jsdom@29.0.0_@noble_hashes@1.8.0__vite@8.0.0_@types_nod_53aa4254f295b3c40bb8f17b6ab226b5/node_modules/vitest/dist/config.js +0 -8
@@ -1,159 +1,131 @@
1
- import { RESPONSE_STATUS as e } from "../../constant/response-status.js";
2
- import { catchError as t, log as n } from "../log/log.util.js";
3
- import { mongo as r } from "./mongo.util.js";
1
+ import { catchError as e, log as t } from "../log/log.util.js";
2
+ import { mongo as n } from "./mongo.util.js";
3
+ import { wrapError as r, wrapNotFound as i } from "./mongo.controller.helpers.js";
4
4
  //#region src/node/mongo/mongo.controller.native.ts
5
- var i = class {
5
+ var a = class {
6
6
  collection;
7
7
  defaultLimit;
8
8
  collectionName;
9
9
  constructor(e, t, n) {
10
10
  this.collection = e.collection(t), this.collectionName = t, this.defaultLimit = n?.defaultLimit ?? 1e3;
11
11
  }
12
- async createOne(n) {
12
+ async createOne(t) {
13
13
  try {
14
- let t = {
15
- ...r.createGenericFields(),
16
- ...n
14
+ let e = {
15
+ ...n.createGenericFields(),
16
+ ...t
17
17
  };
18
- return (await this.collection.insertOne(t)).acknowledged ? {
18
+ return (await this.collection.insertOne(e)).acknowledged ? {
19
19
  success: !0,
20
20
  message: "Document created successfully",
21
- result: t
22
- } : {
23
- success: !1,
24
- message: "Document creation failed",
25
- code: e.INTERNAL_SERVER_ERROR.CODE
26
- };
27
- } catch (e) {
28
- return t(e);
21
+ result: e
22
+ } : r("Document creation failed");
23
+ } catch (t) {
24
+ return e(t);
29
25
  }
30
26
  }
31
- async createMany(n) {
27
+ async createMany(t) {
32
28
  try {
33
- let t = n.map((e) => ({
34
- ...r.createGenericFields(),
29
+ let e = t.map((e) => ({
30
+ ...n.createGenericFields(),
35
31
  ...e
36
- })), i = await this.collection.insertMany(t);
37
- return i.insertedCount === 0 ? {
38
- success: !1,
39
- message: "No documents were inserted",
40
- code: e.INTERNAL_SERVER_ERROR.CODE
41
- } : {
32
+ })), i = await this.collection.insertMany(e);
33
+ return i.insertedCount === 0 ? r("No documents were inserted") : {
42
34
  success: !0,
43
35
  message: `${i.insertedCount} documents created successfully`,
44
- result: t
36
+ result: e
45
37
  };
46
- } catch (e) {
47
- return t(e);
38
+ } catch (t) {
39
+ return e(t);
48
40
  }
49
41
  }
50
- async findOne(n) {
42
+ async findOne(t) {
51
43
  try {
52
- let t = await this.collection.findOne(n, { maxTimeMS: 3e4 });
53
- return t ? {
44
+ let e = await this.collection.findOne(t, { maxTimeMS: 3e4 });
45
+ return e ? {
54
46
  success: !0,
55
47
  message: "Document found",
56
- result: t
57
- } : {
58
- success: !1,
59
- message: "Document not found",
60
- code: e.NOT_FOUND.CODE
61
- };
62
- } catch (e) {
63
- return t(e);
48
+ result: e
49
+ } : i("Document");
50
+ } catch (t) {
51
+ return e(t);
64
52
  }
65
53
  }
66
- async findAll(e = {}) {
54
+ async findAll(n = {}) {
67
55
  try {
68
- let t = await this.collection.find(e).limit(this.defaultLimit).maxTimeMS(3e4).toArray(), r = t.length === this.defaultLimit;
69
- return r && n.warn(`[${this.collectionName}] findAll returned exactly ${this.defaultLimit} documents (the default limit). Results may be truncated. Consider using pagination or setting an explicit limit.`), {
56
+ let e = await this.collection.find(n).limit(this.defaultLimit).maxTimeMS(3e4).toArray(), r = e.length === this.defaultLimit;
57
+ return r && t.warn(`[${this.collectionName}] findAll returned exactly ${this.defaultLimit} documents (the default limit). Results may be truncated. Consider using pagination or setting an explicit limit.`), {
70
58
  success: !0,
71
59
  message: "Documents retrieved successfully",
72
- result: t,
60
+ result: e,
73
61
  truncated: r
74
62
  };
75
- } catch (e) {
76
- return t(e);
63
+ } catch (t) {
64
+ return e(t);
77
65
  }
78
66
  }
79
- async count(e = {}) {
67
+ async count(t = {}) {
80
68
  try {
81
- let t = await this.collection.countDocuments(e);
69
+ let e = await this.collection.countDocuments(t);
82
70
  return {
83
71
  success: !0,
84
- message: `${t} documents counted successfully`,
85
- result: t
72
+ message: `${e} documents counted successfully`,
73
+ result: e
86
74
  };
87
- } catch (e) {
88
- return t(e);
75
+ } catch (t) {
76
+ return e(t);
89
77
  }
90
78
  }
91
- async updateOne(n, r) {
79
+ async updateOne(t, n) {
92
80
  try {
93
- let t = await this.collection.updateOne(n, { $set: r });
94
- return t.matchedCount === 0 ? {
95
- success: !1,
96
- message: "No documents matched the filter",
97
- code: e.NOT_FOUND.CODE
98
- } : {
81
+ let e = await this.collection.updateOne(t, { $set: n });
82
+ return e.matchedCount === 0 ? i("No documents matched the filter") : {
99
83
  success: !0,
100
84
  message: "Document updated successfully",
101
- result: t
85
+ result: e
102
86
  };
103
- } catch (e) {
104
- return t(e);
87
+ } catch (t) {
88
+ return e(t);
105
89
  }
106
90
  }
107
- async updateMany(n, r) {
91
+ async updateMany(t, n) {
108
92
  try {
109
- let t = await this.collection.updateMany(n, { $set: r });
110
- return t.matchedCount === 0 ? {
111
- success: !1,
112
- message: "No documents matched the filter",
113
- code: e.NOT_FOUND.CODE
114
- } : {
93
+ let e = await this.collection.updateMany(t, { $set: n });
94
+ return e.matchedCount === 0 ? i("No documents matched the filter") : {
115
95
  success: !0,
116
96
  message: "Documents updated successfully",
117
- result: t
97
+ result: e
118
98
  };
119
- } catch (e) {
120
- return t(e);
99
+ } catch (t) {
100
+ return e(t);
121
101
  }
122
102
  }
123
- async deleteOne(n) {
103
+ async deleteOne(t) {
124
104
  try {
125
- let t = await this.collection.deleteOne(n);
126
- return t.deletedCount === 0 ? {
127
- success: !1,
128
- message: "No documents matched the filter",
129
- code: e.NOT_FOUND.CODE
130
- } : {
105
+ let e = await this.collection.deleteOne(t);
106
+ return e.deletedCount === 0 ? i("No documents matched the filter") : {
131
107
  success: !0,
132
108
  message: "Document deleted successfully",
133
- result: t
109
+ result: e
134
110
  };
135
- } catch (e) {
136
- return t(e);
111
+ } catch (t) {
112
+ return e(t);
137
113
  }
138
114
  }
139
- async deleteMany(n) {
115
+ async deleteMany(t) {
140
116
  try {
141
- let t = await this.collection.deleteMany(n);
142
- return t.deletedCount === 0 ? {
143
- success: !1,
144
- message: "No documents matched the filter",
145
- code: e.NOT_FOUND.CODE
146
- } : {
117
+ let e = await this.collection.deleteMany(t);
118
+ return e.deletedCount === 0 ? i("No documents matched the filter") : {
147
119
  success: !0,
148
120
  message: "Documents deleted successfully",
149
- result: t
121
+ result: e
150
122
  };
151
- } catch (e) {
152
- return t(e);
123
+ } catch (t) {
124
+ return e(t);
153
125
  }
154
126
  }
155
127
  };
156
128
  //#endregion
157
- export { i as MongoController };
129
+ export { a as MongoController };
158
130
 
159
131
  //# sourceMappingURL=mongo.controller.native.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mongo.controller.native.js","names":[],"sources":["../../../src/node/mongo/mongo.controller.native.ts"],"sourcesContent":["import type { I_Return } from '#typescript/index.js';\n\nimport { RESPONSE_STATUS } from '#constant/index.js';\n\nimport type { C_Collection, C_Db, C_Document, T_DeleteResult, T_Filter, T_OptionalUnlessRequiredId, T_UpdateResult, T_WithId } from './mongo.type.js';\n\nimport { catchError, log } from '../log/index.js';\nimport { mongo } from './mongo.util.js';\n\n/**\n * MongoDB native driver controller for direct database operations.\n * This class provides a simplified interface for MongoDB operations using the native driver,\n * with automatic generic field generation and standardized response formatting.\n *\n * @see I_MongoController for the shared polymorphic interface (use via type assertion when needed).\n */\nexport class MongoController<D extends Partial<C_Document>> {\n private collection: C_Collection<D>;\n private defaultLimit: number;\n private collectionName: string;\n\n /**\n * Creates a new MongoDB controller instance.\n *\n * @param db - The MongoDB database instance.\n * @param collectionName - The name of the collection to operate on.\n * @param options - Optional configuration for the controller.\n * @param options.defaultLimit - Maximum documents returned by findAll when no limit is specified (default: 1,000).\n */\n constructor(db: C_Db, collectionName: string, options?: { defaultLimit?: number }) {\n this.collection = db.collection<D>(collectionName);\n this.collectionName = collectionName;\n this.defaultLimit = options?.defaultLimit ?? 1_000;\n }\n\n /**\n * Creates a single document in the collection.\n * This method adds generic fields (id, isDel, timestamps) to the document before insertion.\n *\n * @param document - The document to create, with or without generic fields.\n * @returns A promise that resolves to a standardized response with the created document.\n */\n async createOne(document: D | Partial<D>): Promise<I_Return<D | Partial<D>>> {\n try {\n const finalDocument = {\n ...mongo.createGenericFields(),\n ...document,\n };\n\n const result = await this.collection.insertOne(finalDocument as unknown as T_OptionalUnlessRequiredId<D>);\n\n if (!result.acknowledged) {\n return {\n success: false,\n message: 'Document creation failed',\n code: RESPONSE_STATUS.INTERNAL_SERVER_ERROR.CODE,\n };\n }\n\n return {\n success: true,\n message: 'Document created successfully',\n result: finalDocument,\n };\n }\n catch (error) {\n return catchError<(D | Partial<D>)>(error);\n }\n }\n\n /**\n * Creates multiple documents in the collection.\n * This method adds generic fields to each document before bulk insertion.\n *\n * @param documents - An array of documents to create.\n * @returns A promise that resolves to a standardized response with the created documents.\n */\n async createMany(documents: (D | Partial<D>)[]): Promise<I_Return<(D | Partial<D>)[]>> {\n try {\n const finalDocuments = documents.map(document => ({\n ...mongo.createGenericFields(),\n ...document,\n }));\n\n const result = await this.collection.insertMany(finalDocuments as unknown as T_OptionalUnlessRequiredId<D>[]);\n\n if (result.insertedCount === 0) {\n return {\n success: false,\n message: 'No documents were inserted',\n code: RESPONSE_STATUS.INTERNAL_SERVER_ERROR.CODE,\n };\n }\n\n return {\n success: true,\n message: `${result.insertedCount} documents created successfully`,\n result: finalDocuments,\n };\n }\n catch (error) {\n return catchError<(D | Partial<D>)[]>(error);\n }\n }\n\n /**\n * Finds a single document by filter criteria.\n *\n * @param filter - The filter criteria to find the document.\n * @returns A promise that resolves to a standardized response with the found document.\n */\n async findOne(filter: T_Filter<D>): Promise<I_Return<T_WithId<D>>> {\n try {\n const result = await this.collection.findOne(filter, { maxTimeMS: 30_000 });\n\n if (!result) {\n return { success: false, message: 'Document not found', code: RESPONSE_STATUS.NOT_FOUND.CODE };\n }\n\n return { success: true, message: 'Document found', result };\n }\n catch (error) {\n return catchError<T_WithId<D>>(error);\n }\n }\n\n /**\n * Finds all documents matching the filter criteria.\n *\n * @param filter - The filter criteria to find documents (defaults to empty object for all documents).\n * @returns A promise that resolves to a standardized response with the found documents.\n */\n async findAll(\n filter: T_Filter<D> = {},\n ): Promise<I_Return<T_WithId<D>[]>> {\n try {\n const result = await this.collection.find(filter).limit(this.defaultLimit).maxTimeMS(30_000).toArray();\n\n const truncated = result.length === this.defaultLimit;\n\n if (truncated) {\n log.warn(`[${this.collectionName}] findAll returned exactly ${this.defaultLimit} documents (the default limit). Results may be truncated. Consider using pagination or setting an explicit limit.`);\n }\n\n return {\n success: true,\n message: 'Documents retrieved successfully',\n result,\n truncated,\n };\n }\n catch (error) {\n return catchError<T_WithId<D>[]>(error);\n }\n }\n\n /**\n * Counts documents matching the filter criteria.\n *\n * @param filter - The filter criteria to count documents (defaults to empty object for all documents).\n * @returns A promise that resolves to a standardized response with the document count.\n */\n async count(\n filter: T_Filter<D> = {},\n ): Promise<I_Return<number>> {\n try {\n const result = await this.collection.countDocuments(filter);\n\n return {\n success: true,\n message: `${result} documents counted successfully`,\n result,\n };\n }\n catch (error) {\n return catchError<number>(error);\n }\n }\n\n /**\n * Updates a single document matching the filter criteria.\n *\n * @param filter - The filter criteria to find the document to update.\n * @param update - The update data to apply to the document.\n * @returns A promise that resolves to a standardized response with the update result.\n */\n async updateOne(\n filter: T_Filter<D>,\n update: Partial<D>,\n ): Promise<I_Return<T_UpdateResult>> {\n try {\n const result = await this.collection.updateOne(filter, {\n $set: update,\n });\n\n if (result.matchedCount === 0) {\n return {\n success: false,\n message: 'No documents matched the filter',\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n return {\n success: true,\n message: 'Document updated successfully',\n result,\n };\n }\n catch (error) {\n return catchError<T_UpdateResult>(error);\n }\n }\n\n /**\n * Updates multiple documents matching the filter criteria.\n *\n * @param filter - The filter criteria to find documents to update.\n * @param update - The update data to apply to the documents.\n * @returns A promise that resolves to a standardized response with the update result.\n */\n async updateMany(\n filter: T_Filter<D>,\n update: Partial<D>,\n ): Promise<I_Return<T_UpdateResult>> {\n try {\n const result = await this.collection.updateMany(filter, {\n $set: update,\n });\n\n if (result.matchedCount === 0) {\n return {\n success: false,\n message: 'No documents matched the filter',\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n\n return {\n success: true,\n message: 'Documents updated successfully',\n result,\n };\n }\n catch (error) {\n return catchError<T_UpdateResult>(error);\n }\n }\n\n /**\n * Deletes a single document matching the filter criteria.\n *\n * @param filter - The filter criteria to find the document to delete.\n * @returns A promise that resolves to a standardized response with the delete result.\n */\n async deleteOne(\n filter: T_Filter<D>,\n ): Promise<I_Return<T_DeleteResult>> {\n try {\n const result = await this.collection.deleteOne(filter);\n\n if (result.deletedCount === 0) {\n return {\n success: false,\n message: 'No documents matched the filter',\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n return {\n success: true,\n message: 'Document deleted successfully',\n result,\n };\n }\n catch (error) {\n return catchError<T_DeleteResult>(error);\n }\n }\n\n /**\n * Deletes multiple documents matching the filter criteria.\n *\n * @param filter - The filter criteria to find documents to delete.\n * @returns A promise that resolves to a standardized response with the delete result.\n */\n async deleteMany(\n filter: T_Filter<D>,\n ): Promise<I_Return<T_DeleteResult>> {\n try {\n const result = await this.collection.deleteMany(filter);\n\n if (result.deletedCount === 0) {\n return {\n success: false,\n message: 'No documents matched the filter',\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n\n return {\n success: true,\n message: 'Documents deleted successfully',\n result,\n };\n }\n catch (error) {\n return catchError<T_DeleteResult>(error);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mongo.controller.native.js","names":[],"sources":["../../../src/node/mongo/mongo.controller.native.ts"],"sourcesContent":["import type { I_Return } from '#typescript/index.js';\n\nimport type { C_Collection, C_Db, C_Document, T_DeleteResult, T_Filter, T_OptionalUnlessRequiredId, T_UpdateResult, T_WithId } from './mongo.type.js';\n\nimport { catchError, log } from '../log/index.js';\nimport { wrapError, wrapNotFound } from './mongo.controller.helpers.js';\nimport { mongo } from './mongo.util.js';\n\n/**\n * MongoDB native driver controller for direct database operations.\n * This class provides a simplified interface for MongoDB operations using the native driver,\n * with automatic generic field generation and standardized response formatting.\n *\n * @see I_MongoController for the shared polymorphic interface (use via type assertion when needed).\n */\nexport class MongoController<D extends Partial<C_Document>> {\n private collection: C_Collection<D>;\n private defaultLimit: number;\n private collectionName: string;\n\n /**\n * Creates a new MongoDB controller instance.\n *\n * @param db - The MongoDB database instance.\n * @param collectionName - The name of the collection to operate on.\n * @param options - Optional configuration for the controller.\n * @param options.defaultLimit - Maximum documents returned by findAll when no limit is specified (default: 1,000).\n */\n constructor(db: C_Db, collectionName: string, options?: { defaultLimit?: number }) {\n this.collection = db.collection<D>(collectionName);\n this.collectionName = collectionName;\n this.defaultLimit = options?.defaultLimit ?? 1_000;\n }\n\n /**\n * Creates a single document in the collection.\n * This method adds generic fields (id, isDel, timestamps) to the document before insertion.\n *\n * @param document - The document to create, with or without generic fields.\n * @returns A promise that resolves to a standardized response with the created document.\n */\n async createOne(document: D | Partial<D>): Promise<I_Return<D | Partial<D>>> {\n try {\n const finalDocument = {\n ...mongo.createGenericFields(),\n ...document,\n };\n\n const result = await this.collection.insertOne(finalDocument as unknown as T_OptionalUnlessRequiredId<D>);\n\n if (!result.acknowledged) {\n return wrapError('Document creation failed');\n }\n\n return {\n success: true,\n message: 'Document created successfully',\n result: finalDocument,\n };\n }\n catch (error) {\n return catchError<(D | Partial<D>)>(error);\n }\n }\n\n /**\n * Creates multiple documents in the collection.\n * This method adds generic fields to each document before bulk insertion.\n *\n * @param documents - An array of documents to create.\n * @returns A promise that resolves to a standardized response with the created documents.\n */\n async createMany(documents: (D | Partial<D>)[]): Promise<I_Return<(D | Partial<D>)[]>> {\n try {\n const finalDocuments = documents.map(document => ({\n ...mongo.createGenericFields(),\n ...document,\n }));\n\n const result = await this.collection.insertMany(finalDocuments as unknown as T_OptionalUnlessRequiredId<D>[]);\n\n if (result.insertedCount === 0) {\n return wrapError('No documents were inserted');\n }\n\n return {\n success: true,\n message: `${result.insertedCount} documents created successfully`,\n result: finalDocuments,\n };\n }\n catch (error) {\n return catchError<(D | Partial<D>)[]>(error);\n }\n }\n\n /**\n * Finds a single document by filter criteria.\n *\n * @param filter - The filter criteria to find the document.\n * @returns A promise that resolves to a standardized response with the found document.\n */\n async findOne(filter: T_Filter<D>): Promise<I_Return<T_WithId<D>>> {\n try {\n const result = await this.collection.findOne(filter, { maxTimeMS: 30_000 });\n\n if (!result) {\n return wrapNotFound('Document');\n }\n\n return { success: true, message: 'Document found', result };\n }\n catch (error) {\n return catchError<T_WithId<D>>(error);\n }\n }\n\n /**\n * Finds all documents matching the filter criteria.\n *\n * @param filter - The filter criteria to find documents (defaults to empty object for all documents).\n * @returns A promise that resolves to a standardized response with the found documents.\n */\n async findAll(\n filter: T_Filter<D> = {},\n ): Promise<I_Return<T_WithId<D>[]>> {\n try {\n const result = await this.collection.find(filter).limit(this.defaultLimit).maxTimeMS(30_000).toArray();\n\n const truncated = result.length === this.defaultLimit;\n\n if (truncated) {\n log.warn(`[${this.collectionName}] findAll returned exactly ${this.defaultLimit} documents (the default limit). Results may be truncated. Consider using pagination or setting an explicit limit.`);\n }\n\n return {\n success: true,\n message: 'Documents retrieved successfully',\n result,\n truncated,\n };\n }\n catch (error) {\n return catchError<T_WithId<D>[]>(error);\n }\n }\n\n /**\n * Counts documents matching the filter criteria.\n *\n * @param filter - The filter criteria to count documents (defaults to empty object for all documents).\n * @returns A promise that resolves to a standardized response with the document count.\n */\n async count(\n filter: T_Filter<D> = {},\n ): Promise<I_Return<number>> {\n try {\n const result = await this.collection.countDocuments(filter);\n\n return {\n success: true,\n message: `${result} documents counted successfully`,\n result,\n };\n }\n catch (error) {\n return catchError<number>(error);\n }\n }\n\n /**\n * Updates a single document matching the filter criteria.\n *\n * @param filter - The filter criteria to find the document to update.\n * @param update - The update data to apply to the document.\n * @returns A promise that resolves to a standardized response with the update result.\n */\n async updateOne(\n filter: T_Filter<D>,\n update: Partial<D>,\n ): Promise<I_Return<T_UpdateResult>> {\n try {\n const result = await this.collection.updateOne(filter, {\n $set: update,\n });\n\n if (result.matchedCount === 0) {\n return wrapNotFound('No documents matched the filter');\n }\n return {\n success: true,\n message: 'Document updated successfully',\n result,\n };\n }\n catch (error) {\n return catchError<T_UpdateResult>(error);\n }\n }\n\n /**\n * Updates multiple documents matching the filter criteria.\n *\n * @param filter - The filter criteria to find documents to update.\n * @param update - The update data to apply to the documents.\n * @returns A promise that resolves to a standardized response with the update result.\n */\n async updateMany(\n filter: T_Filter<D>,\n update: Partial<D>,\n ): Promise<I_Return<T_UpdateResult>> {\n try {\n const result = await this.collection.updateMany(filter, {\n $set: update,\n });\n\n if (result.matchedCount === 0) {\n return wrapNotFound('No documents matched the filter');\n }\n\n return {\n success: true,\n message: 'Documents updated successfully',\n result,\n };\n }\n catch (error) {\n return catchError<T_UpdateResult>(error);\n }\n }\n\n /**\n * Deletes a single document matching the filter criteria.\n *\n * @param filter - The filter criteria to find the document to delete.\n * @returns A promise that resolves to a standardized response with the delete result.\n */\n async deleteOne(\n filter: T_Filter<D>,\n ): Promise<I_Return<T_DeleteResult>> {\n try {\n const result = await this.collection.deleteOne(filter);\n\n if (result.deletedCount === 0) {\n return wrapNotFound('No documents matched the filter');\n }\n return {\n success: true,\n message: 'Document deleted successfully',\n result,\n };\n }\n catch (error) {\n return catchError<T_DeleteResult>(error);\n }\n }\n\n /**\n * Deletes multiple documents matching the filter criteria.\n *\n * @param filter - The filter criteria to find documents to delete.\n * @returns A promise that resolves to a standardized response with the delete result.\n */\n async deleteMany(\n filter: T_Filter<D>,\n ): Promise<I_Return<T_DeleteResult>> {\n try {\n const result = await this.collection.deleteMany(filter);\n\n if (result.deletedCount === 0) {\n return wrapNotFound('No documents matched the filter');\n }\n\n return {\n success: true,\n message: 'Documents deleted successfully',\n result,\n };\n }\n catch (error) {\n return catchError<T_DeleteResult>(error);\n }\n }\n}\n"],"mappings":"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"}
@@ -1,10 +1,6 @@
1
1
  import { default as mongooseRaw } from 'mongoose';
2
2
  import { I_ModelWithSchema } from './mongo.internal-types.js';
3
3
  import { I_DynamicVirtualConfig, I_DynamicVirtualOptions, T_Input_Populate } from './mongo.type.js';
4
- /**
5
- * Checks if value is object-like (e.g., objects, arrays, etc.), not null.
6
- */
7
- export declare function isObject(value: unknown): value is object;
8
4
  /**
9
5
  * Filters out dynamic virtuals from populate options to prevent Mongoose from trying to populate them.
10
6
  * This function creates a new populate configuration that only includes regular virtuals.
@@ -3,10 +3,7 @@ import { catchError as t } from "../log/log.util.js";
3
3
  import { convertEnumToModelName as n } from "./mongo.util.js";
4
4
  import { applyNestedPopulate as r } from "./mongo.populate.js";
5
5
  //#region src/node/mongo/mongo.dynamic-populate.ts
6
- function i(e) {
7
- return typeof e == "object" && !!e;
8
- }
9
- function a(e, t) {
6
+ function i(e, t) {
10
7
  if (!e || !t || t.length === 0) return e;
11
8
  let n = new Set(t.map((e) => e.name));
12
9
  if (Array.isArray(e)) {
@@ -27,7 +24,7 @@ function a(e, t) {
27
24
  }
28
25
  return e;
29
26
  }
30
- function o(e, r, i) {
27
+ function a(e, r, i) {
31
28
  if (!e.length || !r || !i?.ref) return [];
32
29
  let a = /* @__PURE__ */ new Map();
33
30
  return e.forEach((e) => {
@@ -47,13 +44,13 @@ function o(e, r, i) {
47
44
  docs: t
48
45
  }));
49
46
  }
50
- function s(e) {
47
+ function o(e) {
51
48
  return typeof e == "object" && !!e && "toObject" in e && typeof e.toObject == "function";
52
49
  }
53
- async function c(t, n, i, a, c, l) {
54
- if (!n.length || !i.length || !a) return n;
50
+ async function s(t, n, i, s, c, l) {
51
+ if (!n.length || !i.length || !s) return n;
55
52
  let u = i.filter((e) => {
56
- if (Array.isArray(a)) return a.length > 0 && a.some((t) => {
53
+ if (Array.isArray(s)) return s.length > 0 && s.some((t) => {
57
54
  if (typeof t == "string") return t === e.name || t.startsWith(`${e.name}.`);
58
55
  if (t && typeof t == "object") {
59
56
  let n = t, r = n.path || n.populate || "";
@@ -61,15 +58,15 @@ async function c(t, n, i, a, c, l) {
61
58
  }
62
59
  return !1;
63
60
  });
64
- if (typeof a == "string") return a === e.name || a.startsWith(`${e.name}.`);
65
- if (typeof a == "object" && a) {
66
- let t = a, n = t.path || t.populate || "";
61
+ if (typeof s == "string") return s === e.name || s.startsWith(`${e.name}.`);
62
+ if (typeof s == "object" && s) {
63
+ let t = s, n = t.path || t.populate || "";
67
64
  return n === e.name || n.startsWith(`${e.name}.`);
68
65
  }
69
66
  return !1;
70
67
  });
71
68
  if (u.length === 0) return n;
72
- let d = e(n.map((e) => s(e) ? e.toObject() : e));
69
+ let d = e(n.map((e) => o(e) ? e.toObject() : e));
73
70
  d.forEach((e) => {
74
71
  u.forEach(({ name: t, options: n }) => {
75
72
  t in e || (e[t] = n.count ? 0 : n.justOne ? null : []);
@@ -77,7 +74,7 @@ async function c(t, n, i, a, c, l) {
77
74
  });
78
75
  let f = /* @__PURE__ */ new Map();
79
76
  for (let e of u) {
80
- let { name: t, options: n } = e, r = o(d, t, n);
77
+ let { name: t, options: n } = e, r = a(d, t, n);
81
78
  for (let i of r) {
82
79
  f.has(i.model) || f.set(i.model, {
83
80
  virtuals: [],
@@ -139,7 +136,7 @@ async function c(t, n, i, a, c, l) {
139
136
  });
140
137
  }
141
138
  }
142
- })), a && await r(t, d, ((e) => {
139
+ })), s && await r(t, d, ((e) => {
143
140
  let t = Array.isArray(e) ? e : [e], n = /* @__PURE__ */ new Map(), r = [];
144
141
  for (let e of t) if (typeof e == "string") if (e.includes(".")) {
145
142
  let t = e.split("."), r = t[0] || "", i = t.slice(1).join(".");
@@ -161,9 +158,9 @@ async function c(t, n, i, a, c, l) {
161
158
  populate: n
162
159
  } : t);
163
160
  }), i;
164
- })(a), i, l), d;
161
+ })(s), i, l), d;
165
162
  }
166
163
  //#endregion
167
- export { a as filterDynamicVirtualsFromPopulate, s as isMongooseDoc, i as isObject, c as populateDynamicVirtuals, o as remapDynamicPopulate };
164
+ export { i as filterDynamicVirtualsFromPopulate, o as isMongooseDoc, s as populateDynamicVirtuals, a as remapDynamicPopulate };
168
165
 
169
166
  //# sourceMappingURL=mongo.dynamic-populate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mongo.dynamic-populate.js","names":[],"sources":["../../../src/node/mongo/mongo.dynamic-populate.ts"],"sourcesContent":["import type mongooseRaw from 'mongoose';\n\nimport { deepClone } from '#util/index.js';\n\nimport type { I_ModelWithSchema } from './mongo.internal-types.js';\nimport type { I_DynamicVirtualConfig, I_DynamicVirtualOptions, T_Input_Populate } from './mongo.type.js';\n\nimport { catchError } from '../log/index.js';\nimport { applyNestedPopulate } from './mongo.populate.js';\nimport { convertEnumToModelName } from './mongo.util.js';\n\n/**\n * Checks if value is object-like (e.g., objects, arrays, etc.), not null.\n */\nexport function isObject(value: unknown): value is object {\n return value != null && typeof value === 'object';\n}\n\n/**\n * Filters out dynamic virtuals from populate options to prevent Mongoose from trying to populate them.\n * This function creates a new populate configuration that only includes regular virtuals.\n *\n * @template T - The document type\n * @param populate - The original populate options\n * @param dynamicVirtuals - Array of dynamic virtual configurations\n * @returns Filtered populate options excluding dynamic virtuals\n */\nexport function filterDynamicVirtualsFromPopulate<T>(\n populate: T_Input_Populate | undefined,\n dynamicVirtuals: I_DynamicVirtualConfig<T>[] | undefined,\n): T_Input_Populate | undefined {\n if (!populate || !dynamicVirtuals || dynamicVirtuals.length === 0) {\n return populate;\n }\n\n const dynamicVirtualNames = new Set(dynamicVirtuals.map(v => v.name));\n\n if (Array.isArray(populate)) {\n const filtered = populate.filter((p) => {\n if (typeof p === 'string') {\n return ![...dynamicVirtualNames].some(virtualName =>\n p === virtualName || p.startsWith(`${virtualName}.`),\n );\n }\n\n if (typeof p === 'object' && p !== null) {\n const popObj = p as { path?: string; populate?: string };\n const path = popObj.path || popObj.populate || '';\n\n return ![...dynamicVirtualNames].some(virtualName =>\n path === virtualName || path.startsWith(`${virtualName}.`),\n );\n }\n\n return true;\n });\n\n return filtered.length > 0 ? (filtered as T_Input_Populate) : undefined;\n }\n\n if (typeof populate === 'string') {\n return [...dynamicVirtualNames].some(virtualName =>\n populate === virtualName || populate.startsWith(`${virtualName}.`),\n )\n ? undefined\n : populate;\n }\n\n if (typeof populate === 'object' && populate !== null) {\n const popObj = populate as { path?: string; populate?: string };\n const path = popObj.path || popObj.populate || '';\n\n return [...dynamicVirtualNames].some(virtualName =>\n path === virtualName || path.startsWith(`${virtualName}.`),\n )\n ? undefined\n : populate;\n }\n\n return populate;\n}\n\n/**\n * Groups documents by the resolved model name for a dynamic virtual field.\n * Used to batch population queries for dynamic virtuals.\n *\n * @template T - The document type\n * @template R - The model name type (usually string or enum)\n * @param {T[]} documents - The array of documents to process\n * @param {string} virtualName - The name of the dynamic virtual field\n * @param {I_DynamicVirtualOptions<T, R>} virtualOptions - The dynamic virtual options (must include a ref function)\n * @returns {Array<{ model: string; docs: T[] }>} An array of groups, each with a model name and the docs for that model\n */\nexport function remapDynamicPopulate<T, R extends string = string>(\n documents: T[],\n virtualName: string,\n virtualOptions: I_DynamicVirtualOptions<T, R>,\n): Array<{ model: string; docs: T[] }> {\n if (!documents.length || !virtualName || !virtualOptions?.ref) {\n return [];\n }\n\n const modelGroups = new Map<string, T[]>();\n documents.forEach((doc) => {\n try {\n const modelName = virtualOptions.ref(doc);\n\n if (modelName === undefined || modelName === null) {\n return;\n }\n\n const modelNameString = typeof modelName === 'string' ? modelName : String(modelName);\n\n if (modelNameString && modelNameString.trim() !== '') {\n const convertedModelName = convertEnumToModelName(modelNameString);\n\n if (!modelGroups.has(convertedModelName)) {\n modelGroups.set(convertedModelName, []);\n }\n\n modelGroups.get(convertedModelName)!.push(doc);\n }\n }\n catch (error) {\n catchError(new Error(`Dynamic ref function failed for virtual \"${virtualName}\": ${error instanceof Error ? error.message : String(error)}`));\n }\n });\n\n return Array.from(modelGroups.entries(), ([model, docs]) => ({ model, docs }));\n}\n\n/**\n * Type guard to check if an object is a Mongoose Document (has toObject method).\n * @param obj - The object to check\n * @returns True if obj has a toObject function\n */\nexport function isMongooseDoc(obj: unknown): obj is { toObject: () => { [key: string]: unknown } } {\n return obj !== null && typeof obj === 'object' && 'toObject' in obj && typeof (obj as { toObject: unknown }).toObject === 'function';\n}\n\n/**\n * Optimized batch population for dynamic virtuals.\n *\n * - Groups documents by model and batches queries for each model.\n * - Populates all dynamic virtuals in parallel for maximum performance.\n * - Uses direct assignment for plain objects and skips already populated fields.\n * - Supports optional projection for population queries.\n * - Only populates virtuals that are explicitly requested in populate options.\n * - Reminder: Ensure indexes exist on foreignField in referenced collections for best performance.\n *\n * @template T - The document type (must be an object)\n * @template R - The model name type (usually string or enum)\n * @param {typeof mongooseRaw} mongoose - The Mongoose instance\n * @param {T[]} documents - The array of documents to populate\n * @param {I_DynamicVirtualConfig<T, R>[]} virtualConfigs - The dynamic virtual configurations to process\n * @param {T_Input_Populate} [populate] - Population options to determine which virtuals to populate\n * @param {Record<string, 0 | 1>} [projection] - Optional projection for population queries\n * @returns {Promise<object[]>} The array of documents with dynamic virtuals populated\n */\nexport async function populateDynamicVirtuals<T extends object, R extends string = string>(\n mongoose: typeof mongooseRaw,\n documents: T[],\n virtualConfigs: I_DynamicVirtualConfig<T, R>[],\n populate?: T_Input_Populate,\n projection?: Record<string, 0 | 1>,\n startModel?: I_ModelWithSchema,\n): Promise<T[]> {\n if (!documents.length || !virtualConfigs.length) {\n return documents;\n }\n\n if (!populate) {\n return documents;\n }\n\n const requestedVirtuals = virtualConfigs.filter((config) => {\n if (Array.isArray(populate)) {\n return populate.length > 0 && populate.some((p) => {\n if (typeof p === 'string') {\n return p === config.name || p.startsWith(`${config.name}.`);\n }\n if (p && typeof p === 'object') {\n const popObj = p as { path?: string; populate?: string };\n const path = popObj.path || popObj.populate || '';\n\n return path === config.name || path.startsWith(`${config.name}.`);\n }\n\n return false;\n });\n }\n\n if (typeof populate === 'string') {\n return populate === config.name || populate.startsWith(`${config.name}.`);\n }\n\n if (typeof populate === 'object' && populate !== null) {\n const popObj = populate as { path?: string; populate?: string };\n const path = popObj.path || popObj.populate || '';\n\n return (path === config.name) || path.startsWith(`${config.name}.`);\n }\n\n return false;\n });\n\n if (requestedVirtuals.length === 0) {\n return documents;\n }\n\n // toObject() already creates plain copies for Mongoose docs; deepClone the\n // plain array to avoid mutating the caller's objects.\n const plainDocuments = documents.map(doc => isMongooseDoc(doc) ? doc.toObject() : doc);\n const clonedDocuments = deepClone(plainDocuments) as T[];\n\n clonedDocuments.forEach((doc) => {\n requestedVirtuals.forEach(({ name, options }) => {\n if (!(name in doc)) {\n (doc as { [key: string]: unknown })[name as string] = options.count ? 0 : (options.justOne ? null : []);\n }\n });\n });\n\n const modelProcessingMap = new Map<string, {\n virtuals: I_DynamicVirtualConfig<T, R>[];\n localValueSets: Map<string, Set<string>>;\n docsByLocalValue: Map<string, number[]>;\n }>();\n\n for (const virtualConfig of requestedVirtuals) {\n const { name, options } = virtualConfig;\n const populateGroups = remapDynamicPopulate(clonedDocuments, name, options);\n\n for (const group of populateGroups) {\n if (!modelProcessingMap.has(group.model)) {\n modelProcessingMap.set(group.model, {\n virtuals: [],\n localValueSets: new Map(),\n docsByLocalValue: new Map(),\n });\n }\n\n const processing = modelProcessingMap.get(group.model)!;\n\n if (!processing.virtuals.some(v => v.name === name)) {\n processing.virtuals.push(virtualConfig);\n processing.localValueSets.set(name as string, new Set());\n }\n\n const localValueSet = processing.localValueSets.get(name as string)!;\n group.docs.forEach((doc) => {\n const localVal = (doc as { [key: string]: unknown })[options.localField];\n\n if (localVal != null) {\n const strVal = String(localVal);\n localValueSet.add(strVal);\n\n let idx = -1;\n\n const docWithKeys = doc as { [key: string]: unknown };\n\n if (docWithKeys['id'] !== undefined) {\n idx = clonedDocuments.findIndex((d) => {\n const dWithKeys = d as { [key: string]: unknown };\n\n return dWithKeys['id'] === docWithKeys['id'];\n });\n }\n else if (docWithKeys['_id'] !== undefined) {\n idx = clonedDocuments.findIndex((d) => {\n const dWithKeys = d as { [key: string]: unknown };\n\n return dWithKeys['_id']?.toString?.() === docWithKeys['_id']?.toString?.();\n });\n }\n\n if (idx !== -1) {\n if (!processing.docsByLocalValue.has(strVal)) {\n processing.docsByLocalValue.set(strVal, []);\n }\n processing.docsByLocalValue.get(strVal)!.push(idx);\n }\n }\n });\n }\n }\n\n await Promise.all(Array.from(modelProcessingMap.entries(), async ([modelName, processing]) => {\n const Model = mongoose.models[modelName];\n\n if (!Model) {\n return;\n }\n\n const allLocalValues = new Set<string>();\n processing.localValueSets.forEach((localValueSet) => {\n localValueSet.forEach(val => allLocalValues.add(val));\n });\n\n if (allLocalValues.size === 0) {\n return;\n }\n\n const foreignFields = [...new Set(processing.virtuals.map(v => v.options.foreignField))];\n const localValuesArray = [...allLocalValues];\n let query;\n\n if (foreignFields.length === 1) {\n query = { [String(foreignFields[0])]: { $in: localValuesArray } };\n }\n else {\n query = { $or: foreignFields.map(field => ({ [field]: { $in: localValuesArray } })) };\n }\n\n const allPopulatedData = await Model.find(query, projection).lean();\n\n for (const virtualConfig of processing.virtuals) {\n const { name, options } = virtualConfig;\n const relevantData = allPopulatedData.filter((item) => {\n const foreignVal = (item)[options.foreignField];\n\n return foreignVal != null && allLocalValues.has(String(foreignVal));\n });\n\n if (options.count) {\n const countMap = new Map<string, number>();\n\n relevantData.forEach((item) => {\n const key = (item)[options.foreignField]?.toString();\n\n if (key) {\n countMap.set(key, (countMap.get(key) || 0) + 1);\n }\n });\n\n processing.localValueSets.get(name as string)!.forEach((localValue) => {\n const docs = processing.docsByLocalValue.get(localValue) || [];\n const count = countMap.get(localValue) || 0;\n\n docs.forEach((idx) => {\n const docToUpdate = clonedDocuments[idx] as { [key: string]: unknown };\n\n if (docToUpdate[name] === undefined) {\n docToUpdate[name] = count;\n }\n });\n });\n }\n else {\n const resultMap = new Map<string, T[]>();\n\n relevantData.forEach((item) => {\n const key = (item)[options.foreignField]?.toString();\n\n if (key) {\n if (!resultMap.has(key)) {\n resultMap.set(key, []);\n }\n resultMap.get(key)!.push(item);\n }\n });\n\n processing.localValueSets.get(name as string)!.forEach((localVal) => {\n const docs = processing.docsByLocalValue.get(localVal) || [];\n const results = resultMap.get(localVal) || [];\n const value = options.justOne ? (results[0] || null) : results;\n\n docs.forEach((idx) => {\n const docToUpdate = clonedDocuments[idx] as { [key: string]: unknown };\n docToUpdate[name] = value;\n });\n });\n }\n }\n }));\n\n if (populate) {\n const normalizePopulate = (pop: T_Input_Populate): T_Input_Populate => {\n const asArray = Array.isArray(pop) ? pop : [pop];\n const grouped = new Map<string, unknown[]>();\n const passthrough: unknown[] = [];\n\n for (const entry of asArray) {\n if (typeof entry === 'string') {\n if (entry.includes('.')) {\n const parts = entry.split('.');\n const first = parts[0] || '';\n const rest = parts.slice(1).join('.');\n\n if (first) {\n if (!grouped.has(first)) {\n grouped.set(first, []);\n }\n if (rest) {\n grouped.get(first)!.push(rest);\n }\n }\n }\n else {\n passthrough.push(entry);\n }\n }\n else if (entry && typeof entry === 'object') {\n const obj = entry as { path?: string; populate?: T_Input_Populate };\n\n if (obj.path && obj.path.includes('.')) {\n const parts = obj.path.split('.');\n const first = parts[0] || '';\n const rest = parts.slice(1).join('.');\n\n if (first) {\n if (!grouped.has(first)) {\n grouped.set(first, []);\n }\n if (rest) {\n grouped.get(first)!.push(rest);\n }\n if (obj.populate) {\n grouped.get(first)!.push(obj.populate);\n }\n }\n }\n else {\n passthrough.push(entry);\n }\n }\n }\n\n const normalized: unknown[] = [...passthrough];\n grouped.forEach((nested, root) => {\n const flat: unknown[] = [];\n\n for (const n of nested) {\n if (typeof n === 'string') {\n flat.push(n);\n }\n else if (n && typeof n === 'object') {\n flat.push(n);\n }\n }\n if (flat.length > 0) {\n normalized.push({ path: root, populate: flat as unknown as T_Input_Populate });\n }\n else {\n normalized.push(root);\n }\n });\n\n return normalized as unknown as T_Input_Populate;\n };\n\n const normalizedPopulate = normalizePopulate(populate);\n\n await applyNestedPopulate(mongoose, clonedDocuments, normalizedPopulate, virtualConfigs as I_DynamicVirtualConfig<unknown, string>[], startModel);\n }\n\n return clonedDocuments;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mongo.dynamic-populate.js","names":[],"sources":["../../../src/node/mongo/mongo.dynamic-populate.ts"],"sourcesContent":["import type mongooseRaw from 'mongoose';\n\nimport { deepClone } from '#util/index.js';\n\nimport type { I_ModelWithSchema } from './mongo.internal-types.js';\nimport type { I_DynamicVirtualConfig, I_DynamicVirtualOptions, T_Input_Populate } from './mongo.type.js';\n\nimport { catchError } from '../log/index.js';\nimport { applyNestedPopulate } from './mongo.populate.js';\nimport { convertEnumToModelName } from './mongo.util.js';\n\n/**\n * Filters out dynamic virtuals from populate options to prevent Mongoose from trying to populate them.\n * This function creates a new populate configuration that only includes regular virtuals.\n *\n * @template T - The document type\n * @param populate - The original populate options\n * @param dynamicVirtuals - Array of dynamic virtual configurations\n * @returns Filtered populate options excluding dynamic virtuals\n */\nexport function filterDynamicVirtualsFromPopulate<T>(\n populate: T_Input_Populate | undefined,\n dynamicVirtuals: I_DynamicVirtualConfig<T>[] | undefined,\n): T_Input_Populate | undefined {\n if (!populate || !dynamicVirtuals || dynamicVirtuals.length === 0) {\n return populate;\n }\n\n const dynamicVirtualNames = new Set(dynamicVirtuals.map(v => v.name));\n\n if (Array.isArray(populate)) {\n const filtered = populate.filter((p) => {\n if (typeof p === 'string') {\n return ![...dynamicVirtualNames].some(virtualName =>\n p === virtualName || p.startsWith(`${virtualName}.`),\n );\n }\n\n if (typeof p === 'object' && p !== null) {\n const popObj = p as { path?: string; populate?: string };\n const path = popObj.path || popObj.populate || '';\n\n return ![...dynamicVirtualNames].some(virtualName =>\n path === virtualName || path.startsWith(`${virtualName}.`),\n );\n }\n\n return true;\n });\n\n return filtered.length > 0 ? (filtered as T_Input_Populate) : undefined;\n }\n\n if (typeof populate === 'string') {\n return [...dynamicVirtualNames].some(virtualName =>\n populate === virtualName || populate.startsWith(`${virtualName}.`),\n )\n ? undefined\n : populate;\n }\n\n if (typeof populate === 'object' && populate !== null) {\n const popObj = populate as { path?: string; populate?: string };\n const path = popObj.path || popObj.populate || '';\n\n return [...dynamicVirtualNames].some(virtualName =>\n path === virtualName || path.startsWith(`${virtualName}.`),\n )\n ? undefined\n : populate;\n }\n\n return populate;\n}\n\n/**\n * Groups documents by the resolved model name for a dynamic virtual field.\n * Used to batch population queries for dynamic virtuals.\n *\n * @template T - The document type\n * @template R - The model name type (usually string or enum)\n * @param {T[]} documents - The array of documents to process\n * @param {string} virtualName - The name of the dynamic virtual field\n * @param {I_DynamicVirtualOptions<T, R>} virtualOptions - The dynamic virtual options (must include a ref function)\n * @returns {Array<{ model: string; docs: T[] }>} An array of groups, each with a model name and the docs for that model\n */\nexport function remapDynamicPopulate<T, R extends string = string>(\n documents: T[],\n virtualName: string,\n virtualOptions: I_DynamicVirtualOptions<T, R>,\n): Array<{ model: string; docs: T[] }> {\n if (!documents.length || !virtualName || !virtualOptions?.ref) {\n return [];\n }\n\n const modelGroups = new Map<string, T[]>();\n documents.forEach((doc) => {\n try {\n const modelName = virtualOptions.ref(doc);\n\n if (modelName === undefined || modelName === null) {\n return;\n }\n\n const modelNameString = typeof modelName === 'string' ? modelName : String(modelName);\n\n if (modelNameString && modelNameString.trim() !== '') {\n const convertedModelName = convertEnumToModelName(modelNameString);\n\n if (!modelGroups.has(convertedModelName)) {\n modelGroups.set(convertedModelName, []);\n }\n\n modelGroups.get(convertedModelName)!.push(doc);\n }\n }\n catch (error) {\n catchError(new Error(`Dynamic ref function failed for virtual \"${virtualName}\": ${error instanceof Error ? error.message : String(error)}`));\n }\n });\n\n return Array.from(modelGroups.entries(), ([model, docs]) => ({ model, docs }));\n}\n\n/**\n * Type guard to check if an object is a Mongoose Document (has toObject method).\n * @param obj - The object to check\n * @returns True if obj has a toObject function\n */\nexport function isMongooseDoc(obj: unknown): obj is { toObject: () => { [key: string]: unknown } } {\n return obj !== null && typeof obj === 'object' && 'toObject' in obj && typeof (obj as { toObject: unknown }).toObject === 'function';\n}\n\n/**\n * Optimized batch population for dynamic virtuals.\n *\n * - Groups documents by model and batches queries for each model.\n * - Populates all dynamic virtuals in parallel for maximum performance.\n * - Uses direct assignment for plain objects and skips already populated fields.\n * - Supports optional projection for population queries.\n * - Only populates virtuals that are explicitly requested in populate options.\n * - Reminder: Ensure indexes exist on foreignField in referenced collections for best performance.\n *\n * @template T - The document type (must be an object)\n * @template R - The model name type (usually string or enum)\n * @param {typeof mongooseRaw} mongoose - The Mongoose instance\n * @param {T[]} documents - The array of documents to populate\n * @param {I_DynamicVirtualConfig<T, R>[]} virtualConfigs - The dynamic virtual configurations to process\n * @param {T_Input_Populate} [populate] - Population options to determine which virtuals to populate\n * @param {Record<string, 0 | 1>} [projection] - Optional projection for population queries\n * @returns {Promise<object[]>} The array of documents with dynamic virtuals populated\n */\nexport async function populateDynamicVirtuals<T extends object, R extends string = string>(\n mongoose: typeof mongooseRaw,\n documents: T[],\n virtualConfigs: I_DynamicVirtualConfig<T, R>[],\n populate?: T_Input_Populate,\n projection?: Record<string, 0 | 1>,\n startModel?: I_ModelWithSchema,\n): Promise<T[]> {\n if (!documents.length || !virtualConfigs.length) {\n return documents;\n }\n\n if (!populate) {\n return documents;\n }\n\n const requestedVirtuals = virtualConfigs.filter((config) => {\n if (Array.isArray(populate)) {\n return populate.length > 0 && populate.some((p) => {\n if (typeof p === 'string') {\n return p === config.name || p.startsWith(`${config.name}.`);\n }\n if (p && typeof p === 'object') {\n const popObj = p as { path?: string; populate?: string };\n const path = popObj.path || popObj.populate || '';\n\n return path === config.name || path.startsWith(`${config.name}.`);\n }\n\n return false;\n });\n }\n\n if (typeof populate === 'string') {\n return populate === config.name || populate.startsWith(`${config.name}.`);\n }\n\n if (typeof populate === 'object' && populate !== null) {\n const popObj = populate as { path?: string; populate?: string };\n const path = popObj.path || popObj.populate || '';\n\n return (path === config.name) || path.startsWith(`${config.name}.`);\n }\n\n return false;\n });\n\n if (requestedVirtuals.length === 0) {\n return documents;\n }\n\n // toObject() already creates plain copies for Mongoose docs; deepClone the\n // plain array to avoid mutating the caller's objects.\n const plainDocuments = documents.map(doc => isMongooseDoc(doc) ? doc.toObject() : doc);\n const clonedDocuments = deepClone(plainDocuments) as T[];\n\n clonedDocuments.forEach((doc) => {\n requestedVirtuals.forEach(({ name, options }) => {\n if (!(name in doc)) {\n (doc as { [key: string]: unknown })[name as string] = options.count ? 0 : (options.justOne ? null : []);\n }\n });\n });\n\n const modelProcessingMap = new Map<string, {\n virtuals: I_DynamicVirtualConfig<T, R>[];\n localValueSets: Map<string, Set<string>>;\n docsByLocalValue: Map<string, number[]>;\n }>();\n\n for (const virtualConfig of requestedVirtuals) {\n const { name, options } = virtualConfig;\n const populateGroups = remapDynamicPopulate(clonedDocuments, name, options);\n\n for (const group of populateGroups) {\n if (!modelProcessingMap.has(group.model)) {\n modelProcessingMap.set(group.model, {\n virtuals: [],\n localValueSets: new Map(),\n docsByLocalValue: new Map(),\n });\n }\n\n const processing = modelProcessingMap.get(group.model)!;\n\n if (!processing.virtuals.some(v => v.name === name)) {\n processing.virtuals.push(virtualConfig);\n processing.localValueSets.set(name as string, new Set());\n }\n\n const localValueSet = processing.localValueSets.get(name as string)!;\n group.docs.forEach((doc) => {\n const localVal = (doc as { [key: string]: unknown })[options.localField];\n\n if (localVal != null) {\n const strVal = String(localVal);\n localValueSet.add(strVal);\n\n let idx = -1;\n\n const docWithKeys = doc as { [key: string]: unknown };\n\n if (docWithKeys['id'] !== undefined) {\n idx = clonedDocuments.findIndex((d) => {\n const dWithKeys = d as { [key: string]: unknown };\n\n return dWithKeys['id'] === docWithKeys['id'];\n });\n }\n else if (docWithKeys['_id'] !== undefined) {\n idx = clonedDocuments.findIndex((d) => {\n const dWithKeys = d as { [key: string]: unknown };\n\n return dWithKeys['_id']?.toString?.() === docWithKeys['_id']?.toString?.();\n });\n }\n\n if (idx !== -1) {\n if (!processing.docsByLocalValue.has(strVal)) {\n processing.docsByLocalValue.set(strVal, []);\n }\n processing.docsByLocalValue.get(strVal)!.push(idx);\n }\n }\n });\n }\n }\n\n await Promise.all(Array.from(modelProcessingMap.entries(), async ([modelName, processing]) => {\n const Model = mongoose.models[modelName];\n\n if (!Model) {\n return;\n }\n\n const allLocalValues = new Set<string>();\n processing.localValueSets.forEach((localValueSet) => {\n localValueSet.forEach(val => allLocalValues.add(val));\n });\n\n if (allLocalValues.size === 0) {\n return;\n }\n\n const foreignFields = [...new Set(processing.virtuals.map(v => v.options.foreignField))];\n const localValuesArray = [...allLocalValues];\n let query;\n\n if (foreignFields.length === 1) {\n query = { [String(foreignFields[0])]: { $in: localValuesArray } };\n }\n else {\n query = { $or: foreignFields.map(field => ({ [field]: { $in: localValuesArray } })) };\n }\n\n const allPopulatedData = await Model.find(query, projection).lean();\n\n for (const virtualConfig of processing.virtuals) {\n const { name, options } = virtualConfig;\n const relevantData = allPopulatedData.filter((item) => {\n const foreignVal = (item)[options.foreignField];\n\n return foreignVal != null && allLocalValues.has(String(foreignVal));\n });\n\n if (options.count) {\n const countMap = new Map<string, number>();\n\n relevantData.forEach((item) => {\n const key = (item)[options.foreignField]?.toString();\n\n if (key) {\n countMap.set(key, (countMap.get(key) || 0) + 1);\n }\n });\n\n processing.localValueSets.get(name as string)!.forEach((localValue) => {\n const docs = processing.docsByLocalValue.get(localValue) || [];\n const count = countMap.get(localValue) || 0;\n\n docs.forEach((idx) => {\n const docToUpdate = clonedDocuments[idx] as { [key: string]: unknown };\n\n if (docToUpdate[name] === undefined) {\n docToUpdate[name] = count;\n }\n });\n });\n }\n else {\n const resultMap = new Map<string, T[]>();\n\n relevantData.forEach((item) => {\n const key = (item)[options.foreignField]?.toString();\n\n if (key) {\n if (!resultMap.has(key)) {\n resultMap.set(key, []);\n }\n resultMap.get(key)!.push(item);\n }\n });\n\n processing.localValueSets.get(name as string)!.forEach((localVal) => {\n const docs = processing.docsByLocalValue.get(localVal) || [];\n const results = resultMap.get(localVal) || [];\n const value = options.justOne ? (results[0] || null) : results;\n\n docs.forEach((idx) => {\n const docToUpdate = clonedDocuments[idx] as { [key: string]: unknown };\n docToUpdate[name] = value;\n });\n });\n }\n }\n }));\n\n if (populate) {\n const normalizePopulate = (pop: T_Input_Populate): T_Input_Populate => {\n const asArray = Array.isArray(pop) ? pop : [pop];\n const grouped = new Map<string, unknown[]>();\n const passthrough: unknown[] = [];\n\n for (const entry of asArray) {\n if (typeof entry === 'string') {\n if (entry.includes('.')) {\n const parts = entry.split('.');\n const first = parts[0] || '';\n const rest = parts.slice(1).join('.');\n\n if (first) {\n if (!grouped.has(first)) {\n grouped.set(first, []);\n }\n if (rest) {\n grouped.get(first)!.push(rest);\n }\n }\n }\n else {\n passthrough.push(entry);\n }\n }\n else if (entry && typeof entry === 'object') {\n const obj = entry as { path?: string; populate?: T_Input_Populate };\n\n if (obj.path && obj.path.includes('.')) {\n const parts = obj.path.split('.');\n const first = parts[0] || '';\n const rest = parts.slice(1).join('.');\n\n if (first) {\n if (!grouped.has(first)) {\n grouped.set(first, []);\n }\n if (rest) {\n grouped.get(first)!.push(rest);\n }\n if (obj.populate) {\n grouped.get(first)!.push(obj.populate);\n }\n }\n }\n else {\n passthrough.push(entry);\n }\n }\n }\n\n const normalized: unknown[] = [...passthrough];\n grouped.forEach((nested, root) => {\n const flat: unknown[] = [];\n\n for (const n of nested) {\n if (typeof n === 'string') {\n flat.push(n);\n }\n else if (n && typeof n === 'object') {\n flat.push(n);\n }\n }\n if (flat.length > 0) {\n normalized.push({ path: root, populate: flat as unknown as T_Input_Populate });\n }\n else {\n normalized.push(root);\n }\n });\n\n return normalized as unknown as T_Input_Populate;\n };\n\n const normalizedPopulate = normalizePopulate(populate);\n\n await applyNestedPopulate(mongoose, clonedDocuments, normalizedPopulate, virtualConfigs as I_DynamicVirtualConfig<unknown, string>[], startModel);\n }\n\n return clonedDocuments;\n}\n"],"mappings":"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"}
@@ -124,11 +124,13 @@ var f = {
124
124
  async getNewRecords(e, t, n, r = {}) {
125
125
  let i = await e.findAll(r);
126
126
  if (!i.success) throw Error(`Failed to query existing records: ${i.message}`);
127
+ if ("truncated" in i && i.truncated) throw Error("getNewRecords: Results were truncated by the default limit. Use pagination or set an explicit limit to ensure complete data.");
127
128
  return t.filter((e) => !i.result.some((t) => n(t, e)));
128
129
  },
129
130
  async getExistingRecords(e, t, n, r = {}) {
130
131
  let i = await e.findAll(r);
131
132
  if (!i.success) throw Error(`Failed to query existing records: ${i.message}`);
133
+ if ("truncated" in i && i.truncated) throw Error("getExistingRecords: Results were truncated by the default limit. Use pagination or set an explicit limit to ensure complete data.");
132
134
  return i.result.filter((e) => t.some((t) => n(e, t)));
133
135
  }
134
136
  };