@cyberskill/shared 3.8.0 → 3.10.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 (29) hide show
  1. package/dist/config/graphql-codegen/graphql-codegen.util.js +1 -1
  2. package/dist/config/graphql-codegen/graphql-codegen.util.js.map +1 -1
  3. package/dist/config/lint-staged/index.js +1 -1
  4. package/dist/config/lint-staged/index.js.map +1 -1
  5. package/dist/config/vitest/vitest.e2e.js +1 -1
  6. package/dist/config/vitest/vitest.unit.js +1 -1
  7. package/dist/node/cli/index.js +5 -1
  8. package/dist/node/cli/index.js.map +1 -1
  9. package/dist/node/express/express.util.js +2 -2
  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.mongoose.js +86 -85
  14. package/dist/node/mongo/mongo.controller.mongoose.js.map +1 -1
  15. package/dist/node/mongo/mongo.dynamic-populate.d.ts +0 -4
  16. package/dist/node/mongo/mongo.dynamic-populate.js +14 -17
  17. package/dist/node/mongo/mongo.dynamic-populate.js.map +1 -1
  18. package/dist/node/mongo/mongo.util.js +2 -0
  19. package/dist/node/mongo/mongo.util.js.map +1 -1
  20. package/dist/node/path/path.constant.js +1 -1
  21. package/dist/node/path/path.constant.js.map +1 -1
  22. package/dist/node/storage/storage.util.js +41 -35
  23. package/dist/node/storage/storage.util.js.map +1 -1
  24. package/dist/node/upload/upload.util.js +34 -28
  25. package/dist/node/upload/upload.util.js.map +1 -1
  26. 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.1_@types_nod_36acd00c2670b611b011192023dc5bd9/node_modules/vitest/dist/config.js +8 -0
  27. 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.0_@noble_hashes@1.8.0__vite@8.0.1_@types_nod_36acd00c2670b611b011192023dc5bd9}/node_modules/vitest/dist/config.js.map +1 -1
  28. package/package.json +8 -8
  29. 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,9 +1,10 @@
1
- import { RESPONSE_STATUS as e } from "../../constant/response-status.js";
2
- import { normalizeMongoFilter as t } from "../../util/object/object.util.js";
3
- import { generateRandomString as n, generateShortId as r, generateSlug as i } from "../../util/string/string.util.js";
4
- import { catchError as a, log as o } from "../log/log.util.js";
1
+ import { isObject as e } from "../../util/common/common.util.js";
2
+ import { RESPONSE_STATUS as t } from "../../constant/response-status.js";
3
+ import { normalizeMongoFilter as n } from "../../util/object/object.util.js";
4
+ import { generateRandomString as r, generateShortId as i, generateSlug as a } from "../../util/string/string.util.js";
5
+ import { catchError as o, log as s } from "../log/log.util.js";
5
6
  import "./mongo.constant.js";
6
- import { filterDynamicVirtualsFromPopulate as s, isObject as c, populateDynamicVirtuals as l } from "./mongo.dynamic-populate.js";
7
+ import { filterDynamicVirtualsFromPopulate as c, populateDynamicVirtuals as l } from "./mongo.dynamic-populate.js";
7
8
  //#region src/node/mongo/mongo.controller.mongoose.ts
8
9
  function u(e) {
9
10
  return e?.toObject?.() ?? e;
@@ -34,46 +35,46 @@ var d = class {
34
35
  let n = this.getDynamicVirtuals();
35
36
  return n && n.length > 0 && e.length > 0 ? await l(this.model.base, e, n, t, void 0, this.model) : e;
36
37
  }
37
- async findOne(n = {}, r = {}, i = {}, o) {
38
+ async findOne(e = {}, r = {}, i = {}, a) {
38
39
  try {
39
- let a = t(n), c = this.model.findOne(a, r, i).maxTimeMS(3e4).lean(), l = s(o, this.getDynamicVirtuals());
40
- l && c.populate(l);
41
- let d = await c.exec();
40
+ let o = n(e), s = this.model.findOne(o, r, i).maxTimeMS(3e4).lean(), l = c(a, this.getDynamicVirtuals());
41
+ l && s.populate(l);
42
+ let d = await s.exec();
42
43
  return d ? {
43
44
  success: !0,
44
- result: u(await this.populateDynamicVirtualsForDocument(d, o))
45
+ result: u(await this.populateDynamicVirtualsForDocument(d, a))
45
46
  } : {
46
47
  success: !1,
47
48
  message: `No ${this.getModelName()} found.`,
48
- code: e.NOT_FOUND.CODE
49
+ code: t.NOT_FOUND.CODE
49
50
  };
50
51
  } catch (e) {
51
- return a(e);
52
+ return o(e);
52
53
  }
53
54
  }
54
- async findAll(e = {}, n = {}, r = {}, i) {
55
+ async findAll(e = {}, t = {}, r = {}, i) {
55
56
  try {
56
- let a = t(e), c = this.model.find(a, n, r).maxTimeMS(3e4).lean();
57
- r.limit || c.limit(this.defaultLimit);
58
- let l = s(i, this.getDynamicVirtuals());
59
- l && c.populate(l);
60
- let d = await c.exec(), f = await this.populateDynamicVirtualsForDocuments(d, i), p = f.length === this.defaultLimit && !r.limit;
61
- return p && o.warn(`[${this.getModelName()}] findAll returned exactly ${this.defaultLimit} documents (the default limit). Results may be truncated. Consider using pagination or setting an explicit limit.`), {
57
+ let a = n(e), o = this.model.find(a, t, r).maxTimeMS(3e4).lean();
58
+ r.limit || o.limit(this.defaultLimit);
59
+ let l = c(i, this.getDynamicVirtuals());
60
+ l && o.populate(l);
61
+ let d = await o.exec(), f = await this.populateDynamicVirtualsForDocuments(d, i), p = f.length === this.defaultLimit && !r.limit;
62
+ return p && s.warn(`[${this.getModelName()}] findAll returned exactly ${this.defaultLimit} documents (the default limit). Results may be truncated. Consider using pagination or setting an explicit limit.`), {
62
63
  success: !0,
63
64
  result: f.map((e) => u(e)),
64
65
  truncated: p
65
66
  };
66
67
  } catch (e) {
67
- return a(e);
68
+ return o(e);
68
69
  }
69
70
  }
70
- async findPaging(e = {}, n = {}) {
71
+ async findPaging(e = {}, t = {}) {
71
72
  try {
72
- let r = t(e), i = this.getDynamicVirtuals(), a = { ...n };
73
- n.populate && (a.populate = s(n.populate, i));
73
+ let r = n(e), i = this.getDynamicVirtuals(), a = { ...t };
74
+ t.populate && (a.populate = c(t.populate, i));
74
75
  let o = await this.model.paginate(r, a);
75
76
  if (i && i.length > 0) {
76
- let e = await this.populateDynamicVirtualsForDocuments(o.docs, n.populate);
77
+ let e = await this.populateDynamicVirtualsForDocuments(o.docs, t.populate);
77
78
  return {
78
79
  success: !0,
79
80
  result: {
@@ -90,13 +91,13 @@ var d = class {
90
91
  }
91
92
  };
92
93
  } catch (e) {
93
- return a(e);
94
+ return o(e);
94
95
  }
95
96
  }
96
97
  async findPagingAggregate(e, t = {}) {
97
98
  try {
98
99
  let n = this.getDynamicVirtuals(), r = { ...t };
99
- t.populate && (r.populate = s(t.populate, n));
100
+ t.populate && (r.populate = c(t.populate, n));
100
101
  let i = await this.model.aggregatePaginate(this.model.aggregate(e), r), a = await this.populateDynamicVirtualsForDocuments(i.docs, t.populate);
101
102
  return {
102
103
  success: !0,
@@ -106,18 +107,18 @@ var d = class {
106
107
  }
107
108
  };
108
109
  } catch (e) {
109
- return a(e);
110
+ return o(e);
110
111
  }
111
112
  }
112
113
  async count(e = {}) {
113
114
  try {
114
- let n = t(e);
115
+ let t = n(e);
115
116
  return {
116
117
  success: !0,
117
- result: await this.model.countDocuments(n)
118
+ result: await this.model.countDocuments(t)
118
119
  };
119
120
  } catch (e) {
120
- return a(e);
121
+ return o(e);
121
122
  }
122
123
  }
123
124
  async createOne(e) {
@@ -128,7 +129,7 @@ var d = class {
128
129
  result: t?.toObject?.() ?? t
129
130
  };
130
131
  } catch (e) {
131
- return a(e);
132
+ return o(e);
132
133
  }
133
134
  }
134
135
  async createMany(e, t = {}) {
@@ -138,12 +139,12 @@ var d = class {
138
139
  result: (await this.model.insertMany(e, t)).map((e) => e?.toObject?.() ?? e)
139
140
  };
140
141
  } catch (e) {
141
- return a(e);
142
+ return o(e);
142
143
  }
143
144
  }
144
- async updateOne(n = {}, r = {}, i = {}) {
145
+ async updateOne(e = {}, r = {}, i = {}) {
145
146
  try {
146
- let a = t(n), o = await this.model.findOneAndUpdate(a, r, {
147
+ let a = n(e), o = await this.model.findOneAndUpdate(a, r, {
147
148
  new: !0,
148
149
  ...i
149
150
  }).exec();
@@ -153,66 +154,66 @@ var d = class {
153
154
  } : {
154
155
  success: !1,
155
156
  message: `Failed to update ${this.getModelName()}.`,
156
- code: e.NOT_FOUND.CODE
157
+ code: t.NOT_FOUND.CODE
157
158
  };
158
159
  } catch (e) {
159
- return a(e);
160
+ return o(e);
160
161
  }
161
162
  }
162
- async updateMany(e = {}, n = {}, r = {}) {
163
+ async updateMany(e = {}, t = {}, r = {}) {
163
164
  try {
164
- let i = t(e);
165
+ let i = n(e);
165
166
  return {
166
167
  success: !0,
167
- result: await this.model.updateMany(i, n, r).exec()
168
+ result: await this.model.updateMany(i, t, r).exec()
168
169
  };
169
170
  } catch (e) {
170
- return a(e);
171
+ return o(e);
171
172
  }
172
173
  }
173
- async deleteOne(n = {}, r = {}) {
174
+ async deleteOne(e = {}, r = {}) {
174
175
  try {
175
- let i = t(n), a = await this.model.findOneAndDelete(i, r).exec();
176
+ let i = n(e), a = await this.model.findOneAndDelete(i, r).exec();
176
177
  return a ? {
177
178
  success: !0,
178
179
  result: a?.toObject?.() ?? a
179
180
  } : {
180
181
  success: !1,
181
182
  message: `No ${this.getModelName()} found to delete.`,
182
- code: e.NOT_FOUND.CODE
183
+ code: t.NOT_FOUND.CODE
183
184
  };
184
185
  } catch (e) {
185
- return a(e);
186
+ return o(e);
186
187
  }
187
188
  }
188
- async deleteMany(n = {}, r = {}) {
189
+ async deleteMany(e = {}, r = {}) {
189
190
  try {
190
- let i = t(n), a = await this.model.deleteMany(i, r).exec();
191
+ let i = n(e), a = await this.model.deleteMany(i, r).exec();
191
192
  return a.deletedCount === 0 ? {
192
193
  success: !1,
193
194
  message: "No documents found to delete.",
194
- code: e.NOT_FOUND.CODE
195
+ code: t.NOT_FOUND.CODE
195
196
  } : {
196
197
  success: !0,
197
198
  result: a
198
199
  };
199
200
  } catch (e) {
200
- return a(e);
201
+ return o(e);
201
202
  }
202
203
  }
203
- async createShortId(t, n = 4) {
204
+ async createShortId(e, n = 4) {
204
205
  try {
205
- let i = Array.from({ length: 10 }, (e, i) => r(t, i + n)), a = await this.model.find({ shortId: { $in: i } }).select("shortId").lean(), o = new Set(a.map((e) => e.shortId)), s = i.find((e) => !o.has(e));
206
+ let r = Array.from({ length: 10 }, (t, r) => i(e, r + n)), a = await this.model.find({ shortId: { $in: r } }).select("shortId").lean(), o = new Set(a.map((e) => e.shortId)), s = r.find((e) => !o.has(e));
206
207
  return s ? {
207
208
  success: !0,
208
209
  result: s
209
210
  } : {
210
211
  success: !1,
211
212
  message: "Failed to create a unique shortId",
212
- code: e.INTERNAL_SERVER_ERROR.CODE
213
+ code: t.INTERNAL_SERVER_ERROR.CODE
213
214
  };
214
215
  } catch (e) {
215
- return a(e);
216
+ return o(e);
216
217
  }
217
218
  }
218
219
  createSlugQuery({ slug: e, field: t, isObject: n, haveHistory: r = !1, filter: i }) {
@@ -225,62 +226,62 @@ var d = class {
225
226
  $or: [{ slug: e }, ...r ? [{ slugHistory: e }] : []]
226
227
  };
227
228
  }
228
- async createUniqueSlug({ slug: e, field: t, isObject: r, haveHistory: a, filter: o }) {
229
+ async createUniqueSlug({ slug: e, field: t, isObject: n, haveHistory: i, filter: o }) {
229
230
  if (!e || typeof e != "string") throw Error("Invalid slug provided: must be a non-empty string");
230
- let s = i(e);
231
+ let s = a(e);
231
232
  if (!await this.model.exists(this.createSlugQuery({
232
233
  slug: s,
233
234
  field: t,
234
- isObject: r,
235
- haveHistory: a,
235
+ isObject: n,
236
+ haveHistory: i,
236
237
  filter: o
237
238
  }))) return s;
238
239
  let c = Array.from({ length: 100 }, (e, t) => `${s}-${t + 1}`), l = c.map((e) => this.createSlugQuery({
239
240
  slug: e,
240
241
  field: t,
241
- isObject: r,
242
- haveHistory: a,
242
+ isObject: n,
243
+ haveHistory: i,
243
244
  filter: o
244
- })), u = r ? `slug.${t}` : "slug", d = await this.model.find({ $or: l.map((e) => e.$or).flat() }).select(u).lean(), f = new Set(d.map((e) => r ? e.slug?.[t] : e.slug));
245
- return c.find((e) => !f.has(e)) || `${s}-${Date.now()}-${n(6)}`;
245
+ })), u = n ? `slug.${t}` : "slug", d = await this.model.find({ $or: l.map((e) => e.$or).flat() }).select(u).lean(), f = new Set(d.map((e) => n ? e.slug?.[t] : e.slug));
246
+ return c.find((e) => !f.has(e)) || `${s}-${Date.now()}-${r(6)}`;
246
247
  }
247
- async createSlug({ field: e, from: t, filter: n, haveHistory: r }) {
248
+ async createSlug({ field: t, from: n, filter: r, haveHistory: i }) {
248
249
  try {
249
- let i = t[e];
250
- return c(i) ? {
250
+ let a = n[t];
251
+ return e(a) ? {
251
252
  success: !0,
252
- result: Object.fromEntries(await Promise.all(Object.entries(i).map(async ([e, t]) => [e, await this.createUniqueSlug({
253
+ result: Object.fromEntries(await Promise.all(Object.entries(a).map(async ([e, t]) => [e, await this.createUniqueSlug({
253
254
  slug: t,
254
255
  field: e,
255
256
  isObject: !0,
256
- haveHistory: r,
257
- filter: n
257
+ haveHistory: i,
258
+ filter: r
258
259
  })])))
259
260
  } : {
260
261
  success: !0,
261
262
  result: await this.createUniqueSlug({
262
- slug: i,
263
- field: e,
263
+ slug: a,
264
+ field: t,
264
265
  isObject: !1,
265
- haveHistory: r,
266
- filter: n
266
+ haveHistory: i,
267
+ filter: r
267
268
  })
268
269
  };
269
270
  } catch (e) {
270
- return a(e);
271
+ return o(e);
271
272
  }
272
273
  }
273
- async checkSlug({ slug: e, field: t, from: n, filter: r, haveHistory: o }) {
274
+ async checkSlug({ slug: t, field: n, from: r, filter: i, haveHistory: s }) {
274
275
  try {
275
- let a = n[t];
276
- if (c(a)) {
277
- let e = Object.values(a).map((e) => i(e));
276
+ let o = r[n];
277
+ if (e(o)) {
278
+ let e = Object.values(o).map((e) => a(e));
278
279
  return (await Promise.all(e.map((e) => this.model.exists(this.createSlugQuery({
279
280
  slug: e,
280
- field: t,
281
+ field: n,
281
282
  isObject: !0,
282
- haveHistory: o,
283
- filter: r
283
+ haveHistory: s,
284
+ filter: i
284
285
  }))))).some((e) => e) ? {
285
286
  success: !0,
286
287
  result: !0
@@ -289,18 +290,18 @@ var d = class {
289
290
  result: !1
290
291
  };
291
292
  }
292
- let s = i(e);
293
+ let c = a(t);
293
294
  return {
294
295
  success: !0,
295
296
  result: await this.model.exists(this.createSlugQuery({
296
- slug: s,
297
- field: t,
297
+ slug: c,
298
+ field: n,
298
299
  isObject: !1,
299
- filter: r
300
+ filter: i
300
301
  })) !== null
301
302
  };
302
303
  } catch (e) {
303
- return a(e);
304
+ return o(e);
304
305
  }
305
306
  }
306
307
  async aggregate(e) {
@@ -310,7 +311,7 @@ var d = class {
310
311
  result: await this.model.aggregate(e)
311
312
  };
312
313
  } catch (e) {
313
- return a(e);
314
+ return o(e);
314
315
  }
315
316
  }
316
317
  async distinct(e, t = {}, n = {}) {
@@ -320,7 +321,7 @@ var d = class {
320
321
  result: await this.model.distinct(e, t, n)
321
322
  };
322
323
  } catch (e) {
323
- return a(e);
324
+ return o(e);
324
325
  }
325
326
  }
326
327
  };
@@ -1 +1 @@
1
- {"version":3,"file":"mongo.controller.mongoose.js","names":[],"sources":["../../../src/node/mongo/mongo.controller.mongoose.ts"],"sourcesContent":["import type { I_Return } from '#typescript/index.js';\n\nimport { RESPONSE_STATUS } from '#constant/index.js';\nimport { normalizeMongoFilter } from '#util/index.js';\nimport { generateRandomString, generateShortId, generateSlug } from '#util/string/index.js';\n\nimport type { C_Document, I_DeleteOptionsExtended, I_DynamicVirtualConfig, I_ExtendedModel, I_Input_CheckSlug, I_Input_CreateSlug, I_Input_GenerateSlug, I_PaginateOptionsWithPopulate, I_UpdateOptionsExtended, T_AggregatePaginateResult, T_DeleteResult, T_Input_Populate, T_InsertManyOptions, T_PaginateResult, T_PipelineStage, T_PopulateOptions, T_ProjectionType, T_QueryFilter, T_QueryOptions, T_UpdateQuery, T_UpdateResult } from './mongo.type.js';\n\nimport { catchError, log } from '../log/index.js';\nimport { MONGO_SLUG_MAX_ATTEMPTS } from './mongo.constant.js';\nimport { filterDynamicVirtualsFromPopulate, isObject, populateDynamicVirtuals } from './mongo.dynamic-populate.js';\n\n/**\n * Converts a Mongoose document to a plain object, handling the case where\n * the document may already be a plain object (e.g., from `.lean()`).\n *\n * @param doc - The document or plain object.\n * @returns The plain object representation.\n */\nfunction toPlainObject<T>(doc: T): T {\n return (doc as T & { toObject?: () => T })?.toObject?.() ?? doc;\n}\n\n/** Internal shape of a single virtual config stored on the model. */\ninterface I_VirtualConfig {\n name: string;\n options?: { ref?: unknown };\n}\n\n/**\n * Mongoose controller for database operations with advanced features.\n * This class provides a comprehensive interface for Mongoose operations including\n * pagination, aggregation, slug generation, and short ID creation.\n */\nexport class MongooseController<T extends Partial<C_Document>> {\n private defaultLimit: number;\n\n /**\n * Creates a new Mongoose controller instance.\n *\n * @param model - The Mongoose model 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(private model: I_ExtendedModel<T>, options?: { defaultLimit?: number }) {\n this.defaultLimit = options?.defaultLimit ?? 1_000;\n }\n\n /**\n * Gets the model name for logging and error messages.\n *\n * @returns The name of the model.\n */\n private getModelName(): string {\n return this.model.modelName;\n }\n\n /**\n * Gets the dynamic virtuals configuration from the model instance.\n *\n * @returns Array of dynamic virtual configurations or undefined if none exist.\n */\n private getDynamicVirtuals(): I_DynamicVirtualConfig<T>[] | undefined {\n const model = this.model as I_ExtendedModel<T> & { _virtualConfigs?: I_VirtualConfig[] };\n\n if (model._virtualConfigs) {\n const dynamicOnly = model._virtualConfigs.filter(\n v => typeof v.options?.ref === 'function',\n ) as unknown as I_DynamicVirtualConfig<T>[];\n\n if (dynamicOnly.length > 0) {\n return dynamicOnly;\n }\n }\n\n const schemaStatics = this.model.schema.statics as { [key: string]: unknown };\n\n return schemaStatics['_dynamicVirtuals'] as I_DynamicVirtualConfig<T>[] | undefined;\n }\n\n /**\n * Populates dynamic virtuals for a single document.\n *\n * @param result - The document to populate dynamic virtuals for.\n * @param populate - The populate options to determine which virtuals to populate.\n * @returns The document with dynamic virtuals populated.\n */\n private async populateDynamicVirtualsForDocument(result: T, populate?: T_Input_Populate): Promise<T> {\n const populated = await this.populateDynamic([result], populate);\n return populated[0] ?? result;\n }\n\n /**\n * Populates dynamic virtuals for an array of documents.\n *\n * @param results - The documents to populate dynamic virtuals for.\n * @param populate - The populate options to determine which virtuals to populate.\n * @returns The documents with dynamic virtuals populated.\n */\n private async populateDynamicVirtualsForDocuments(results: T[], populate?: T_Input_Populate): Promise<T[]> {\n return this.populateDynamic(results, populate);\n }\n\n /**\n * Internal helper that populates dynamic virtuals for an array of documents.\n * Shared implementation used by both single-document and multi-document methods.\n */\n private async populateDynamic(results: T[], populate?: T_Input_Populate): Promise<T[]> {\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n if (dynamicVirtuals && dynamicVirtuals.length > 0 && results.length > 0) {\n return await populateDynamicVirtuals(this.model.base, results, dynamicVirtuals, populate, undefined, this.model) as T[];\n }\n\n return results;\n }\n\n /**\n * Finds a single document with optional population and projection.\n * Automatically handles dynamic virtual population if configured.\n *\n * @param filter - The filter criteria to find the document.\n * @param projection - The fields to include/exclude in the result.\n * @param options - Query options for the operation.\n * @param populate - Population configuration for related documents.\n * @returns A promise that resolves to a standardized response with the found document.\n */\n async findOne(\n filter: T_QueryFilter<T> = {},\n projection: T_ProjectionType<T> = {},\n options: T_QueryOptions<T> = {},\n populate?: T_Input_Populate,\n ): Promise<I_Return<T>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const query = this.model.findOne(normalizedFilter, projection, options).maxTimeMS(30_000).lean();\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const regularPopulate = filterDynamicVirtualsFromPopulate(populate, dynamicVirtuals);\n\n if (regularPopulate) {\n query.populate(regularPopulate as T_PopulateOptions);\n }\n\n const result = await query.exec();\n\n if (!result) {\n return {\n success: false,\n message: `No ${this.getModelName()} found.`,\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n\n const finalResult = await this.populateDynamicVirtualsForDocument(result, populate);\n\n return { success: true, result: toPlainObject(finalResult) };\n }\n catch (error) {\n return catchError<T>(error);\n }\n }\n\n /**\n * Finds all documents with optional population and projection.\n * Automatically handles dynamic virtual population if configured.\n *\n * @param filter - The filter criteria to find documents.\n * @param projection - The fields to include/exclude in the result.\n * @param options - Query options for the operation.\n * @param populate - Population configuration for related documents.\n * @returns A promise that resolves to a standardized response with the found documents.\n */\n async findAll(\n filter: T_QueryFilter<T> = {},\n projection: T_ProjectionType<T> = {},\n options: T_QueryOptions<T> = {},\n populate?: T_Input_Populate,\n ): Promise<I_Return<T[]>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const query = this.model.find(normalizedFilter, projection, options).maxTimeMS(30_000).lean();\n\n if (!options.limit) {\n query.limit(this.defaultLimit);\n }\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const regularPopulate = filterDynamicVirtualsFromPopulate(populate, dynamicVirtuals);\n\n if (regularPopulate) {\n query.populate(regularPopulate as T_PopulateOptions);\n }\n\n const result = await query.exec();\n\n const finalResult = await this.populateDynamicVirtualsForDocuments(result, populate);\n\n const truncated = finalResult.length === this.defaultLimit && !options.limit;\n\n if (truncated) {\n log.warn(`[${this.getModelName()}] 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 { success: true, result: finalResult.map(item => toPlainObject(item)), truncated };\n }\n catch (error) {\n return catchError<T[]>(error);\n }\n }\n\n /**\n * Finds documents with pagination support.\n * Automatically handles dynamic virtual population if configured.\n *\n * @param filter - The filter criteria to find documents.\n * @param options - Pagination options including page, limit, and population.\n * @returns A promise that resolves to a standardized response with paginated results.\n */\n async findPaging(\n filter: T_QueryFilter<T> = {},\n options: I_PaginateOptionsWithPopulate = {},\n ): Promise<I_Return<T_PaginateResult<T>>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const filteredOptions = { ...options };\n\n if (options.populate) {\n filteredOptions.populate = filterDynamicVirtualsFromPopulate(options.populate, dynamicVirtuals);\n }\n\n const result = await this.model.paginate(normalizedFilter, filteredOptions);\n\n if (dynamicVirtuals && dynamicVirtuals.length > 0) {\n const populatedDocs = await this.populateDynamicVirtualsForDocuments(result.docs, options.populate);\n\n return { success: true, result: { ...result, docs: populatedDocs.map(item => toPlainObject(item)) } };\n }\n\n return { success: true, result: { ...result, docs: result.docs.map(item => toPlainObject(item)) } };\n }\n catch (error) {\n return catchError<T_PaginateResult<T>>(error);\n }\n }\n\n /**\n * Performs aggregation with pagination support.\n *\n * @param pipeline - The aggregation pipeline stages.\n * @param options - Pagination options for the aggregation result.\n * @returns A promise that resolves to a standardized response with paginated aggregation results.\n */\n async findPagingAggregate(\n pipeline: T_PipelineStage[],\n options: I_PaginateOptionsWithPopulate = {},\n ): Promise<I_Return<T_AggregatePaginateResult<T>>> {\n try {\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const filteredOptions = { ...options };\n\n if (options.populate) {\n filteredOptions.populate = filterDynamicVirtualsFromPopulate(options.populate, dynamicVirtuals);\n }\n\n const result = await this.model.aggregatePaginate(\n this.model.aggregate(pipeline),\n filteredOptions,\n );\n\n const finalDocs = await this.populateDynamicVirtualsForDocuments(result.docs, options.populate);\n\n return { success: true, result: { ...result, docs: finalDocs.map(item => toPlainObject(item)) } };\n }\n catch (error) {\n return catchError<T_AggregatePaginateResult<T>>(error);\n }\n }\n\n /**\n * Counts documents matching the filter criteria.\n *\n * @param filter - The filter criteria to count documents.\n * @returns A promise that resolves to a standardized response with the document count.\n */\n async count(filter: T_QueryFilter<T> = {}): Promise<I_Return<number>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model.countDocuments(normalizedFilter);\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<number>(error);\n }\n }\n\n /**\n * Creates a single document.\n *\n * @param doc - The document to create.\n * @returns A promise that resolves to a standardized response with the created document.\n */\n async createOne(doc: T | Partial<T>): Promise<I_Return<T>> {\n try {\n const result = await this.model.create(doc as unknown as Parameters<typeof this.model.create>[0]);\n\n return { success: true, result: (result as T)?.toObject?.() ?? result };\n }\n catch (error) {\n return catchError<T>(error);\n }\n }\n\n /**\n * Creates multiple documents with bulk insertion.\n *\n * @param docs - An array of documents to create.\n * @param options - Options for the bulk insertion operation.\n * @returns A promise that resolves to a standardized response with the created documents.\n */\n async createMany(\n docs: (T | Partial<T>)[],\n options: T_InsertManyOptions = {},\n ): Promise<I_Return<T[]>> {\n try {\n const createdDocuments = await this.model.insertMany(docs, options);\n\n return { success: true, result: createdDocuments.map(item => item?.toObject?.() ?? item) as T[] };\n }\n catch (error) {\n return catchError<T[]>(error);\n }\n }\n\n /**\n * Updates a single document and returns the updated version.\n *\n * @param filter - The filter criteria to find the document to update.\n * @param update - The update data to apply.\n * @param options - Options for the update operation.\n * @returns A promise that resolves to a standardized response with the updated document.\n */\n async updateOne(\n filter: T_QueryFilter<T> = {},\n update: T_UpdateQuery<T> = {},\n options: I_UpdateOptionsExtended = {},\n ): Promise<I_Return<T>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model\n .findOneAndUpdate(normalizedFilter, update, {\n new: true,\n ...options,\n })\n .exec();\n\n if (!result) {\n return {\n success: false,\n message: `Failed to update ${this.getModelName()}.`,\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n\n return { success: true, result: result?.toObject?.() ?? result };\n }\n catch (error) {\n return catchError<T>(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.\n * @param options - Options for the update operation.\n * @returns A promise that resolves to a standardized response with the update result.\n */\n async updateMany(\n filter: T_QueryFilter<T> = {},\n update: T_UpdateQuery<T> = {},\n options: I_UpdateOptionsExtended = {},\n ): Promise<I_Return<T_UpdateResult>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model\n .updateMany(normalizedFilter, update, options)\n .exec();\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<T_UpdateResult>(error);\n }\n }\n\n /**\n * Deletes a single document and returns the deleted version.\n *\n * @param filter - The filter criteria to find the document to delete.\n * @param options - Options for the delete operation.\n * @returns A promise that resolves to a standardized response with the deleted document.\n */\n async deleteOne(\n filter: T_QueryFilter<T> = {},\n options: I_DeleteOptionsExtended = {},\n ): Promise<I_Return<T>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model\n .findOneAndDelete(normalizedFilter, options)\n .exec();\n\n if (!result) {\n return {\n success: false,\n message: `No ${this.getModelName()} found to delete.`,\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n\n return { success: true, result: result?.toObject?.() ?? result };\n }\n catch (error) {\n return catchError<T>(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 * @param options - Options for the delete operation.\n * @returns A promise that resolves to a standardized response with the delete result.\n */\n async deleteMany(\n filter: T_QueryFilter<T> = {},\n options: I_DeleteOptionsExtended = {},\n ): Promise<I_Return<T_DeleteResult>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model.deleteMany(normalizedFilter, options).exec();\n\n if (result.deletedCount === 0) {\n return {\n success: false,\n message: `No documents found to delete.`,\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<T_DeleteResult>(error);\n }\n }\n\n /**\n * Creates a unique short ID based on a given ID.\n * This method generates multiple short IDs with increasing lengths and finds the first available one.\n *\n * @param id - The base ID to generate short IDs from.\n * @param length - The initial length for short ID generation (default: 4).\n * @returns A promise that resolves to a standardized response with the unique short ID.\n */\n async createShortId(id: string, length = 4): Promise<I_Return<string>> {\n try {\n const maxRetries = 10;\n const shortIds = Array.from({ length: maxRetries }, (_, index) =>\n generateShortId(id, index + length));\n\n // Use a single $in query instead of 10 parallel exists() calls\n const existingDocs = await this.model\n .find({ shortId: { $in: shortIds } })\n .select('shortId')\n .lean();\n\n const existingShortIds = new Set(\n existingDocs.map((d: Record<string, unknown>) => d['shortId'] as string),\n );\n\n const availableShortId = shortIds.find(s => !existingShortIds.has(s));\n\n if (availableShortId) {\n return { success: true, result: availableShortId };\n }\n\n return {\n success: false,\n message: 'Failed to create a unique shortId',\n code: RESPONSE_STATUS.INTERNAL_SERVER_ERROR.CODE,\n };\n }\n catch (error) {\n return catchError<string>(error);\n }\n }\n\n /**\n * Creates a query for slug existence checking.\n * This method generates a query that checks for slug existence in both current and historical slug fields.\n *\n * @param options - Configuration for slug query generation including slug, field, and filter.\n * @param options.slug - The slug string to check for existence.\n * @param options.field - The field name for object-based slug checking.\n * @param options.isObject - Whether the slug is stored as an object with nested fields.\n * @param options.haveHistory - Whether to check historical slug fields for existence.\n * @param options.filter - Additional filter conditions to apply to the query.\n * @returns A MongoDB query object for checking slug existence.\n */\n createSlugQuery({ slug, field, isObject, haveHistory = false, filter }: I_Input_GenerateSlug<T>) {\n const baseFilter = { ...(filter ?? {}) };\n\n return isObject\n ? {\n ...baseFilter,\n $or: [\n { [`slug.${field}`]: slug },\n ...(haveHistory ? [{ slugHistory: { $elemMatch: { [`slug.${field}`]: slug } } }] : []),\n ],\n }\n : {\n ...baseFilter,\n $or: [\n { slug },\n ...(haveHistory ? [{ slugHistory: slug }] : []),\n ],\n };\n }\n\n /**\n * Creates a unique slug based on a given string.\n * This method generates multiple slug variations and finds the first available one.\n *\n * @param options - Configuration for slug generation including slug, field, and filter.\n * @param options.slug - The base slug string to make unique.\n * @param options.field - The field name for object-based slug checking.\n * @param options.isObject - Whether the slug is stored as an object with nested fields.\n * @param options.haveHistory - Whether to check historical slug fields for uniqueness.\n * @param options.filter - Additional filter conditions to apply when checking slug existence.\n * @returns A promise that resolves to a unique slug string.\n */\n async createUniqueSlug({ slug, field, isObject, haveHistory, filter }: I_Input_GenerateSlug<T>): Promise<string> {\n if (!slug || typeof slug !== 'string') {\n throw new Error('Invalid slug provided: must be a non-empty string');\n }\n\n const baseSlug = generateSlug(slug);\n\n const baseExists = await this.model.exists(\n this.createSlugQuery({ slug: baseSlug, field, isObject, haveHistory, filter }),\n );\n\n if (!baseExists) {\n return baseSlug;\n }\n\n // Batch query: check all slug variations in a single database call instead of N+1 sequential queries\n const variants = Array.from(\n { length: MONGO_SLUG_MAX_ATTEMPTS },\n (_, i) => `${baseSlug}-${i + 1}`,\n );\n\n const slugQueries = variants.map(s =>\n this.createSlugQuery({ slug: s, field, isObject, haveHistory, filter }),\n );\n\n const slugField = isObject ? `slug.${field as string}` : 'slug';\n const existingDocs = await this.model\n .find({ $or: slugQueries.map(q => q.$or).flat() })\n .select(slugField)\n .lean();\n\n const existingSlugs = new Set(\n existingDocs.map((d: Record<string, unknown>) => {\n if (isObject) {\n const slug = d['slug'] as Record<string, unknown> | undefined;\n return slug?.[field as string];\n }\n return d['slug'];\n }),\n );\n\n const available = variants.find(s => !existingSlugs.has(s));\n\n if (available) {\n return available;\n }\n\n const timestamp = Date.now();\n const randomSuffix = generateRandomString(6);\n\n return `${baseSlug}-${timestamp}-${randomSuffix}`;\n }\n\n /**\n * Creates a slug for a document field.\n * This method handles both simple string fields and object fields with nested slug generation.\n *\n * @param options - Configuration for slug creation including field, source document, and filter.\n * @param options.field - The field name to create a slug for.\n * @param options.from - The source document containing the field value.\n * @param options.haveHistory - Whether to check historical slug fields for uniqueness.\n * @param options.filter - Additional filter conditions to apply when checking slug existence.\n * @returns A promise that resolves to a standardized response with the created slug(s).\n */\n async createSlug<R = string>({ field, from, filter, haveHistory }: I_Input_CreateSlug<T>): Promise<I_Return<R>> {\n try {\n const fieldValue = from[field as keyof T];\n const isObjectValue = isObject(fieldValue);\n\n if (isObjectValue) {\n const uniqueSlug = Object.fromEntries(\n await Promise.all(\n Object.entries(fieldValue).map(async ([key, value]) => {\n const uniqueSlugForKey = await this.createUniqueSlug({\n slug: value as string,\n field: key,\n isObject: true,\n haveHistory,\n filter,\n });\n return [key, uniqueSlugForKey];\n }),\n ),\n );\n\n return { success: true, result: uniqueSlug as R };\n }\n\n const uniqueSlug = await this.createUniqueSlug({\n slug: fieldValue as string,\n field,\n isObject: false,\n haveHistory,\n filter,\n });\n\n return { success: true, result: uniqueSlug as R };\n }\n catch (error) {\n return catchError<R>(error);\n }\n }\n\n /**\n * Checks if a slug already exists in the collection.\n * This method verifies slug existence in both current and historical slug fields.\n *\n * @param options - Configuration for slug checking including slug, field, source document, and filter.\n * @param options.slug - The slug string to check for existence.\n * @param options.field - The field name for object-based slug checking.\n * @param options.from - The source document containing the field value.\n * @param options.haveHistory - Whether to check historical slug fields for existence.\n * @param options.filter - Additional filter conditions to apply to the query.\n * @returns A promise that resolves to a standardized response indicating whether the slug exists.\n */\n async checkSlug({ slug, field, from, filter, haveHistory }: I_Input_CheckSlug<T>): Promise<I_Return<boolean>> {\n try {\n const fieldValue = from[field as keyof T];\n const isObjectValue = isObject(fieldValue);\n\n if (isObjectValue) {\n const values = Object.values(fieldValue);\n const nestedSlugs = values.map(value => generateSlug(value as string));\n\n const existenceChecks = await Promise.all(\n nestedSlugs.map(nestedSlug =>\n this.model.exists(this.createSlugQuery({\n slug: nestedSlug,\n field,\n isObject: true,\n haveHistory,\n filter,\n })),\n ),\n );\n\n if (existenceChecks.some(exists => exists)) {\n return { success: true, result: true };\n }\n\n return { success: true, result: false };\n }\n\n const baseSlug = generateSlug(slug);\n const exists = await this.model.exists(this.createSlugQuery({\n slug: baseSlug,\n field,\n isObject: false,\n filter,\n }));\n\n return { success: true, result: exists !== null };\n }\n catch (error) {\n return catchError<boolean>(error);\n }\n }\n\n /**\n * Performs aggregation operations on the collection.\n *\n * @param pipeline - The aggregation pipeline stages to execute.\n * @returns A promise that resolves to a standardized response with the aggregation results.\n */\n async aggregate(pipeline: T_PipelineStage[]): Promise<I_Return<T[]>> {\n try {\n const result = await this.model.aggregate<T>(pipeline);\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<T[]>(error);\n }\n }\n\n /**\n * Retrieves distinct values for the specified key from the collection.\n *\n * @param key - The field for which to return distinct values.\n * @param filter - The filter query to apply (optional).\n * @param options - Additional options for the distinct operation (optional).\n * @returns A promise that resolves to a standardized response with the array of distinct values.\n */\n async distinct(\n key: string,\n filter: T_QueryFilter<T> = {},\n options: T_QueryOptions<T> = {},\n ): Promise<I_Return<unknown[]>> {\n try {\n const result = await this.model.distinct(key, filter, options);\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<unknown[]>(error);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mongo.controller.mongoose.js","names":[],"sources":["../../../src/node/mongo/mongo.controller.mongoose.ts"],"sourcesContent":["import type { I_Return } from '#typescript/index.js';\n\nimport { RESPONSE_STATUS } from '#constant/index.js';\nimport { isObject } from '#util/common/index.js';\nimport { normalizeMongoFilter } from '#util/index.js';\nimport { generateRandomString, generateShortId, generateSlug } from '#util/string/index.js';\n\nimport type { C_Document, I_DeleteOptionsExtended, I_DynamicVirtualConfig, I_ExtendedModel, I_Input_CheckSlug, I_Input_CreateSlug, I_Input_GenerateSlug, I_PaginateOptionsWithPopulate, I_UpdateOptionsExtended, T_AggregatePaginateResult, T_DeleteResult, T_Input_Populate, T_InsertManyOptions, T_PaginateResult, T_PipelineStage, T_PopulateOptions, T_ProjectionType, T_QueryFilter, T_QueryOptions, T_UpdateQuery, T_UpdateResult } from './mongo.type.js';\n\nimport { catchError, log } from '../log/index.js';\nimport { MONGO_SLUG_MAX_ATTEMPTS } from './mongo.constant.js';\nimport { filterDynamicVirtualsFromPopulate, populateDynamicVirtuals } from './mongo.dynamic-populate.js';\n/**\n * Converts a Mongoose document to a plain object, handling the case where\n * the document may already be a plain object (e.g., from `.lean()`).\n *\n * @param doc - The document or plain object.\n * @returns The plain object representation.\n */\nfunction toPlainObject<T>(doc: T): T {\n return (doc as T & { toObject?: () => T })?.toObject?.() ?? doc;\n}\n\n/** Internal shape of a single virtual config stored on the model. */\ninterface I_VirtualConfig {\n name: string;\n options?: { ref?: unknown };\n}\n\n/**\n * Mongoose controller for database operations with advanced features.\n * This class provides a comprehensive interface for Mongoose operations including\n * pagination, aggregation, slug generation, and short ID creation.\n */\nexport class MongooseController<T extends Partial<C_Document>> {\n private defaultLimit: number;\n\n /**\n * Creates a new Mongoose controller instance.\n *\n * @param model - The Mongoose model 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(private model: I_ExtendedModel<T>, options?: { defaultLimit?: number }) {\n this.defaultLimit = options?.defaultLimit ?? 1_000;\n }\n\n /**\n * Gets the model name for logging and error messages.\n *\n * @returns The name of the model.\n */\n private getModelName(): string {\n return this.model.modelName;\n }\n\n /**\n * Gets the dynamic virtuals configuration from the model instance.\n *\n * @returns Array of dynamic virtual configurations or undefined if none exist.\n */\n private getDynamicVirtuals(): I_DynamicVirtualConfig<T>[] | undefined {\n const model = this.model as I_ExtendedModel<T> & { _virtualConfigs?: I_VirtualConfig[] };\n\n if (model._virtualConfigs) {\n const dynamicOnly = model._virtualConfigs.filter(\n v => typeof v.options?.ref === 'function',\n ) as unknown as I_DynamicVirtualConfig<T>[];\n\n if (dynamicOnly.length > 0) {\n return dynamicOnly;\n }\n }\n\n const schemaStatics = this.model.schema.statics as { [key: string]: unknown };\n\n return schemaStatics['_dynamicVirtuals'] as I_DynamicVirtualConfig<T>[] | undefined;\n }\n\n /**\n * Populates dynamic virtuals for a single document.\n *\n * @param result - The document to populate dynamic virtuals for.\n * @param populate - The populate options to determine which virtuals to populate.\n * @returns The document with dynamic virtuals populated.\n */\n private async populateDynamicVirtualsForDocument(result: T, populate?: T_Input_Populate): Promise<T> {\n const populated = await this.populateDynamic([result], populate);\n return populated[0] ?? result;\n }\n\n /**\n * Populates dynamic virtuals for an array of documents.\n *\n * @param results - The documents to populate dynamic virtuals for.\n * @param populate - The populate options to determine which virtuals to populate.\n * @returns The documents with dynamic virtuals populated.\n */\n private async populateDynamicVirtualsForDocuments(results: T[], populate?: T_Input_Populate): Promise<T[]> {\n return this.populateDynamic(results, populate);\n }\n\n /**\n * Internal helper that populates dynamic virtuals for an array of documents.\n * Shared implementation used by both single-document and multi-document methods.\n */\n private async populateDynamic(results: T[], populate?: T_Input_Populate): Promise<T[]> {\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n if (dynamicVirtuals && dynamicVirtuals.length > 0 && results.length > 0) {\n return await populateDynamicVirtuals(this.model.base, results, dynamicVirtuals, populate, undefined, this.model) as T[];\n }\n\n return results;\n }\n\n /**\n * Finds a single document with optional population and projection.\n * Automatically handles dynamic virtual population if configured.\n *\n * @param filter - The filter criteria to find the document.\n * @param projection - The fields to include/exclude in the result.\n * @param options - Query options for the operation.\n * @param populate - Population configuration for related documents.\n * @returns A promise that resolves to a standardized response with the found document.\n */\n async findOne(\n filter: T_QueryFilter<T> = {},\n projection: T_ProjectionType<T> = {},\n options: T_QueryOptions<T> = {},\n populate?: T_Input_Populate,\n ): Promise<I_Return<T>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const query = this.model.findOne(normalizedFilter, projection, options).maxTimeMS(30_000).lean();\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const regularPopulate = filterDynamicVirtualsFromPopulate(populate, dynamicVirtuals);\n\n if (regularPopulate) {\n query.populate(regularPopulate as T_PopulateOptions);\n }\n\n const result = await query.exec();\n\n if (!result) {\n return {\n success: false,\n message: `No ${this.getModelName()} found.`,\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n\n const finalResult = await this.populateDynamicVirtualsForDocument(result, populate);\n\n return { success: true, result: toPlainObject(finalResult) };\n }\n catch (error) {\n return catchError<T>(error);\n }\n }\n\n /**\n * Finds all documents with optional population and projection.\n * Automatically handles dynamic virtual population if configured.\n *\n * @param filter - The filter criteria to find documents.\n * @param projection - The fields to include/exclude in the result.\n * @param options - Query options for the operation.\n * @param populate - Population configuration for related documents.\n * @returns A promise that resolves to a standardized response with the found documents.\n */\n async findAll(\n filter: T_QueryFilter<T> = {},\n projection: T_ProjectionType<T> = {},\n options: T_QueryOptions<T> = {},\n populate?: T_Input_Populate,\n ): Promise<I_Return<T[]>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const query = this.model.find(normalizedFilter, projection, options).maxTimeMS(30_000).lean();\n\n if (!options.limit) {\n query.limit(this.defaultLimit);\n }\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const regularPopulate = filterDynamicVirtualsFromPopulate(populate, dynamicVirtuals);\n\n if (regularPopulate) {\n query.populate(regularPopulate as T_PopulateOptions);\n }\n\n const result = await query.exec();\n\n const finalResult = await this.populateDynamicVirtualsForDocuments(result, populate);\n\n const truncated = finalResult.length === this.defaultLimit && !options.limit;\n\n if (truncated) {\n log.warn(`[${this.getModelName()}] 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 { success: true, result: finalResult.map(item => toPlainObject(item)), truncated };\n }\n catch (error) {\n return catchError<T[]>(error);\n }\n }\n\n /**\n * Finds documents with pagination support.\n * Automatically handles dynamic virtual population if configured.\n *\n * @param filter - The filter criteria to find documents.\n * @param options - Pagination options including page, limit, and population.\n * @returns A promise that resolves to a standardized response with paginated results.\n */\n async findPaging(\n filter: T_QueryFilter<T> = {},\n options: I_PaginateOptionsWithPopulate = {},\n ): Promise<I_Return<T_PaginateResult<T>>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const filteredOptions = { ...options };\n\n if (options.populate) {\n filteredOptions.populate = filterDynamicVirtualsFromPopulate(options.populate, dynamicVirtuals);\n }\n\n const result = await this.model.paginate(normalizedFilter, filteredOptions);\n\n if (dynamicVirtuals && dynamicVirtuals.length > 0) {\n const populatedDocs = await this.populateDynamicVirtualsForDocuments(result.docs, options.populate);\n\n return { success: true, result: { ...result, docs: populatedDocs.map(item => toPlainObject(item)) } };\n }\n\n return { success: true, result: { ...result, docs: result.docs.map(item => toPlainObject(item)) } };\n }\n catch (error) {\n return catchError<T_PaginateResult<T>>(error);\n }\n }\n\n /**\n * Performs aggregation with pagination support.\n *\n * @param pipeline - The aggregation pipeline stages.\n * @param options - Pagination options for the aggregation result.\n * @returns A promise that resolves to a standardized response with paginated aggregation results.\n */\n async findPagingAggregate(\n pipeline: T_PipelineStage[],\n options: I_PaginateOptionsWithPopulate = {},\n ): Promise<I_Return<T_AggregatePaginateResult<T>>> {\n try {\n const dynamicVirtuals = this.getDynamicVirtuals();\n\n const filteredOptions = { ...options };\n\n if (options.populate) {\n filteredOptions.populate = filterDynamicVirtualsFromPopulate(options.populate, dynamicVirtuals);\n }\n\n const result = await this.model.aggregatePaginate(\n this.model.aggregate(pipeline),\n filteredOptions,\n );\n\n const finalDocs = await this.populateDynamicVirtualsForDocuments(result.docs, options.populate);\n\n return { success: true, result: { ...result, docs: finalDocs.map(item => toPlainObject(item)) } };\n }\n catch (error) {\n return catchError<T_AggregatePaginateResult<T>>(error);\n }\n }\n\n /**\n * Counts documents matching the filter criteria.\n *\n * @param filter - The filter criteria to count documents.\n * @returns A promise that resolves to a standardized response with the document count.\n */\n async count(filter: T_QueryFilter<T> = {}): Promise<I_Return<number>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model.countDocuments(normalizedFilter);\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<number>(error);\n }\n }\n\n /**\n * Creates a single document.\n *\n * @param doc - The document to create.\n * @returns A promise that resolves to a standardized response with the created document.\n */\n async createOne(doc: T | Partial<T>): Promise<I_Return<T>> {\n try {\n const result = await this.model.create(doc as unknown as Parameters<typeof this.model.create>[0]);\n\n return { success: true, result: (result as T)?.toObject?.() ?? result };\n }\n catch (error) {\n return catchError<T>(error);\n }\n }\n\n /**\n * Creates multiple documents with bulk insertion.\n *\n * @param docs - An array of documents to create.\n * @param options - Options for the bulk insertion operation.\n * @returns A promise that resolves to a standardized response with the created documents.\n */\n async createMany(\n docs: (T | Partial<T>)[],\n options: T_InsertManyOptions = {},\n ): Promise<I_Return<T[]>> {\n try {\n const createdDocuments = await this.model.insertMany(docs, options);\n\n return { success: true, result: createdDocuments.map(item => item?.toObject?.() ?? item) as T[] };\n }\n catch (error) {\n return catchError<T[]>(error);\n }\n }\n\n /**\n * Updates a single document and returns the updated version.\n *\n * @param filter - The filter criteria to find the document to update.\n * @param update - The update data to apply.\n * @param options - Options for the update operation.\n * @returns A promise that resolves to a standardized response with the updated document.\n */\n async updateOne(\n filter: T_QueryFilter<T> = {},\n update: T_UpdateQuery<T> = {},\n options: I_UpdateOptionsExtended = {},\n ): Promise<I_Return<T>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model\n .findOneAndUpdate(normalizedFilter, update, {\n new: true,\n ...options,\n })\n .exec();\n\n if (!result) {\n return {\n success: false,\n message: `Failed to update ${this.getModelName()}.`,\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n\n return { success: true, result: result?.toObject?.() ?? result };\n }\n catch (error) {\n return catchError<T>(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.\n * @param options - Options for the update operation.\n * @returns A promise that resolves to a standardized response with the update result.\n */\n async updateMany(\n filter: T_QueryFilter<T> = {},\n update: T_UpdateQuery<T> = {},\n options: I_UpdateOptionsExtended = {},\n ): Promise<I_Return<T_UpdateResult>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model\n .updateMany(normalizedFilter, update, options)\n .exec();\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<T_UpdateResult>(error);\n }\n }\n\n /**\n * Deletes a single document and returns the deleted version.\n *\n * @param filter - The filter criteria to find the document to delete.\n * @param options - Options for the delete operation.\n * @returns A promise that resolves to a standardized response with the deleted document.\n */\n async deleteOne(\n filter: T_QueryFilter<T> = {},\n options: I_DeleteOptionsExtended = {},\n ): Promise<I_Return<T>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model\n .findOneAndDelete(normalizedFilter, options)\n .exec();\n\n if (!result) {\n return {\n success: false,\n message: `No ${this.getModelName()} found to delete.`,\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n\n return { success: true, result: result?.toObject?.() ?? result };\n }\n catch (error) {\n return catchError<T>(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 * @param options - Options for the delete operation.\n * @returns A promise that resolves to a standardized response with the delete result.\n */\n async deleteMany(\n filter: T_QueryFilter<T> = {},\n options: I_DeleteOptionsExtended = {},\n ): Promise<I_Return<T_DeleteResult>> {\n try {\n const normalizedFilter = normalizeMongoFilter(filter);\n const result = await this.model.deleteMany(normalizedFilter, options).exec();\n\n if (result.deletedCount === 0) {\n return {\n success: false,\n message: `No documents found to delete.`,\n code: RESPONSE_STATUS.NOT_FOUND.CODE,\n };\n }\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<T_DeleteResult>(error);\n }\n }\n\n /**\n * Creates a unique short ID based on a given ID.\n * This method generates multiple short IDs with increasing lengths and finds the first available one.\n *\n * @param id - The base ID to generate short IDs from.\n * @param length - The initial length for short ID generation (default: 4).\n * @returns A promise that resolves to a standardized response with the unique short ID.\n */\n async createShortId(id: string, length = 4): Promise<I_Return<string>> {\n try {\n const maxRetries = 10;\n const shortIds = Array.from({ length: maxRetries }, (_, index) =>\n generateShortId(id, index + length));\n\n // Use a single $in query instead of 10 parallel exists() calls\n const existingDocs = await this.model\n .find({ shortId: { $in: shortIds } })\n .select('shortId')\n .lean();\n\n const existingShortIds = new Set(\n existingDocs.map((d: Record<string, unknown>) => d['shortId'] as string),\n );\n\n const availableShortId = shortIds.find(s => !existingShortIds.has(s));\n\n if (availableShortId) {\n return { success: true, result: availableShortId };\n }\n\n return {\n success: false,\n message: 'Failed to create a unique shortId',\n code: RESPONSE_STATUS.INTERNAL_SERVER_ERROR.CODE,\n };\n }\n catch (error) {\n return catchError<string>(error);\n }\n }\n\n /**\n * Creates a query for slug existence checking.\n * This method generates a query that checks for slug existence in both current and historical slug fields.\n *\n * @param options - Configuration for slug query generation including slug, field, and filter.\n * @param options.slug - The slug string to check for existence.\n * @param options.field - The field name for object-based slug checking.\n * @param options.isObject - Whether the slug is stored as an object with nested fields.\n * @param options.haveHistory - Whether to check historical slug fields for existence.\n * @param options.filter - Additional filter conditions to apply to the query.\n * @returns A MongoDB query object for checking slug existence.\n */\n createSlugQuery({ slug, field, isObject, haveHistory = false, filter }: I_Input_GenerateSlug<T>) {\n const baseFilter = { ...(filter ?? {}) };\n\n return isObject\n ? {\n ...baseFilter,\n $or: [\n { [`slug.${field}`]: slug },\n ...(haveHistory ? [{ slugHistory: { $elemMatch: { [`slug.${field}`]: slug } } }] : []),\n ],\n }\n : {\n ...baseFilter,\n $or: [\n { slug },\n ...(haveHistory ? [{ slugHistory: slug }] : []),\n ],\n };\n }\n\n /**\n * Creates a unique slug based on a given string.\n * This method generates multiple slug variations and finds the first available one.\n *\n * @param options - Configuration for slug generation including slug, field, and filter.\n * @param options.slug - The base slug string to make unique.\n * @param options.field - The field name for object-based slug checking.\n * @param options.isObject - Whether the slug is stored as an object with nested fields.\n * @param options.haveHistory - Whether to check historical slug fields for uniqueness.\n * @param options.filter - Additional filter conditions to apply when checking slug existence.\n * @returns A promise that resolves to a unique slug string.\n */\n async createUniqueSlug({ slug, field, isObject, haveHistory, filter }: I_Input_GenerateSlug<T>): Promise<string> {\n if (!slug || typeof slug !== 'string') {\n throw new Error('Invalid slug provided: must be a non-empty string');\n }\n\n const baseSlug = generateSlug(slug);\n\n const baseExists = await this.model.exists(\n this.createSlugQuery({ slug: baseSlug, field, isObject, haveHistory, filter }),\n );\n\n if (!baseExists) {\n return baseSlug;\n }\n\n // Batch query: check all slug variations in a single database call instead of N+1 sequential queries\n const variants = Array.from(\n { length: MONGO_SLUG_MAX_ATTEMPTS },\n (_, i) => `${baseSlug}-${i + 1}`,\n );\n\n const slugQueries = variants.map(s =>\n this.createSlugQuery({ slug: s, field, isObject, haveHistory, filter }),\n );\n\n const slugField = isObject ? `slug.${field as string}` : 'slug';\n const existingDocs = await this.model\n .find({ $or: slugQueries.map(q => q.$or).flat() })\n .select(slugField)\n .lean();\n\n const existingSlugs = new Set(\n existingDocs.map((d: Record<string, unknown>) => {\n if (isObject) {\n const slug = d['slug'] as Record<string, unknown> | undefined;\n return slug?.[field as string];\n }\n return d['slug'];\n }),\n );\n\n const available = variants.find(s => !existingSlugs.has(s));\n\n if (available) {\n return available;\n }\n\n const timestamp = Date.now();\n const randomSuffix = generateRandomString(6);\n\n return `${baseSlug}-${timestamp}-${randomSuffix}`;\n }\n\n /**\n * Creates a slug for a document field.\n * This method handles both simple string fields and object fields with nested slug generation.\n *\n * @param options - Configuration for slug creation including field, source document, and filter.\n * @param options.field - The field name to create a slug for.\n * @param options.from - The source document containing the field value.\n * @param options.haveHistory - Whether to check historical slug fields for uniqueness.\n * @param options.filter - Additional filter conditions to apply when checking slug existence.\n * @returns A promise that resolves to a standardized response with the created slug(s).\n */\n async createSlug<R = string>({ field, from, filter, haveHistory }: I_Input_CreateSlug<T>): Promise<I_Return<R>> {\n try {\n const fieldValue = from[field as keyof T];\n const isObjectValue = isObject(fieldValue);\n\n if (isObjectValue) {\n const uniqueSlug = Object.fromEntries(\n await Promise.all(\n Object.entries(fieldValue).map(async ([key, value]) => {\n const uniqueSlugForKey = await this.createUniqueSlug({\n slug: value as string,\n field: key,\n isObject: true,\n haveHistory,\n filter,\n });\n return [key, uniqueSlugForKey];\n }),\n ),\n );\n\n return { success: true, result: uniqueSlug as R };\n }\n\n const uniqueSlug = await this.createUniqueSlug({\n slug: fieldValue as string,\n field,\n isObject: false,\n haveHistory,\n filter,\n });\n\n return { success: true, result: uniqueSlug as R };\n }\n catch (error) {\n return catchError<R>(error);\n }\n }\n\n /**\n * Checks if a slug already exists in the collection.\n * This method verifies slug existence in both current and historical slug fields.\n *\n * @param options - Configuration for slug checking including slug, field, source document, and filter.\n * @param options.slug - The slug string to check for existence.\n * @param options.field - The field name for object-based slug checking.\n * @param options.from - The source document containing the field value.\n * @param options.haveHistory - Whether to check historical slug fields for existence.\n * @param options.filter - Additional filter conditions to apply to the query.\n * @returns A promise that resolves to a standardized response indicating whether the slug exists.\n */\n async checkSlug({ slug, field, from, filter, haveHistory }: I_Input_CheckSlug<T>): Promise<I_Return<boolean>> {\n try {\n const fieldValue = from[field as keyof T];\n const isObjectValue = isObject(fieldValue);\n\n if (isObjectValue) {\n const values = Object.values(fieldValue);\n const nestedSlugs = values.map(value => generateSlug(value as string));\n\n const existenceChecks = await Promise.all(\n nestedSlugs.map(nestedSlug =>\n this.model.exists(this.createSlugQuery({\n slug: nestedSlug,\n field,\n isObject: true,\n haveHistory,\n filter,\n })),\n ),\n );\n\n if (existenceChecks.some(exists => exists)) {\n return { success: true, result: true };\n }\n\n return { success: true, result: false };\n }\n\n const baseSlug = generateSlug(slug);\n const exists = await this.model.exists(this.createSlugQuery({\n slug: baseSlug,\n field,\n isObject: false,\n filter,\n }));\n\n return { success: true, result: exists !== null };\n }\n catch (error) {\n return catchError<boolean>(error);\n }\n }\n\n /**\n * Performs aggregation operations on the collection.\n *\n * @param pipeline - The aggregation pipeline stages to execute.\n * @returns A promise that resolves to a standardized response with the aggregation results.\n */\n async aggregate(pipeline: T_PipelineStage[]): Promise<I_Return<T[]>> {\n try {\n const result = await this.model.aggregate<T>(pipeline);\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<T[]>(error);\n }\n }\n\n /**\n * Retrieves distinct values for the specified key from the collection.\n *\n * @param key - The field for which to return distinct values.\n * @param filter - The filter query to apply (optional).\n * @param options - Additional options for the distinct operation (optional).\n * @returns A promise that resolves to a standardized response with the array of distinct values.\n */\n async distinct(\n key: string,\n filter: T_QueryFilter<T> = {},\n options: T_QueryOptions<T> = {},\n ): Promise<I_Return<unknown[]>> {\n try {\n const result = await this.model.distinct(key, filter, options);\n\n return { success: true, result };\n }\n catch (error) {\n return catchError<unknown[]>(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