@classytic/mongokit 3.38.1 → 3.40.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 (51) hide show
  1. package/dist/{PaginationEngine-CBS1XGzp.d.mts → PaginationEngine-D-P19Y9m.d.mts} +34 -9
  2. package/dist/PaginationEngine-Dvl8jcRY.mjs +1198 -0
  3. package/dist/{Repository-Ck5x43wF.mjs → Repository-BMgPSkqZ.mjs} +672 -655
  4. package/dist/{Repository-BdSkQ8vc.d.mts → Repository-CR8Y9g2E.d.mts} +106 -34
  5. package/dist/actions/index.d.mts +1 -1
  6. package/dist/actions/index.mjs +1 -1
  7. package/dist/adapter/index.d.mts +21 -0
  8. package/dist/adapter/index.mjs +1 -1
  9. package/dist/{adapter-Bfqz8yHE.mjs → adapter-BrVfPFSW.mjs} +45 -1
  10. package/dist/ai/index.d.mts +1 -1
  11. package/dist/better-auth/index.mjs +2 -2
  12. package/dist/{create-repository-B5EulQ31.mjs → create-repository-BzBUMvd1.mjs} +3 -3
  13. package/dist/{create-repository-BU4x9Kb0.d.mts → create-repository-CAle1MSU.d.mts} +5 -5
  14. package/dist/idempotency/index.d.mts +23 -0
  15. package/dist/idempotency/index.mjs +134 -0
  16. package/dist/{index-DKEql4cL.d.mts → index-CmjNyulu.d.mts} +67 -8
  17. package/dist/index.d.mts +125 -35
  18. package/dist/index.mjs +286 -676
  19. package/dist/indexes/verify-indexes.d.mts +14 -1
  20. package/dist/indexes/verify-indexes.mjs +54 -7
  21. package/dist/{method-registry.plugin-DblM7V6j.mjs → method-registry.plugin-C63pGn1d.mjs} +54 -4
  22. package/dist/{multi-tenant.plugin-BwSvTirB.d.mts → multi-tenant.plugin-CBgCo9im.d.mts} +77 -5
  23. package/dist/{operations-DZodvjC-.d.mts → operations-CrRIoc8Z.d.mts} +22 -7
  24. package/dist/outbox/index.d.mts +1 -1
  25. package/dist/outbox/index.mjs +7 -5
  26. package/dist/pagination/PaginationEngine.d.mts +1 -1
  27. package/dist/pagination/PaginationEngine.mjs +1 -1
  28. package/dist/pagination/utils/limits.d.mts +1 -1
  29. package/dist/pagination/utils/limits.mjs +22 -1
  30. package/dist/pagination-BpIv2bdS.d.mts +364 -0
  31. package/dist/{plugin-options-DXnlKM3B.d.mts → plugin-options-Zk46lD6F.d.mts} +16 -2
  32. package/dist/plugins/index.d.mts +8 -3
  33. package/dist/plugins/index.mjs +99 -26
  34. package/dist/{repository-H_ffGgpE.d.mts → repository-odl03582.d.mts} +50 -6
  35. package/dist/sync/index.d.mts +40 -0
  36. package/dist/sync/index.mjs +334 -0
  37. package/dist/tenant/index.d.mts +89 -0
  38. package/dist/tenant/index.mjs +96 -0
  39. package/dist/testkit/index.d.mts +2 -2
  40. package/dist/testkit/index.mjs +1 -1
  41. package/dist/{timestamp.plugin-CBQukQzV.mjs → timestamp.plugin-DF0gJB6p.mjs} +116 -9
  42. package/dist/{to-plain-Dyz_qvuo.d.mts → to-plain-k7SjNlSS.d.mts} +2 -2
  43. package/dist/transaction-B5L9glO0.mjs +533 -0
  44. package/dist/{update-jSXp3nu3.mjs → update-DG0fCwRJ.mjs} +293 -83
  45. package/dist/utils/index.d.mts +1 -1
  46. package/dist/{validation-chain.plugin-DhNyxNCw.mjs → validation-chain.plugin-BLY2gLEk.mjs} +192 -279
  47. package/dist/{validation-chain.plugin-yQRob3Av.d.mts → validation-chain.plugin-DYp9E7K2.d.mts} +26 -20
  48. package/package.json +17 -4
  49. package/dist/PaginationEngine-BX9o_-4R.mjs +0 -735
  50. package/dist/core-62oo3N1C.d.mts +0 -50
  51. package/dist/pagination-jSUdrACK.d.mts +0 -158
@@ -2,6 +2,215 @@ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { n as warn } from "./logger-K7dPmu2U.mjs";
3
3
  import { t as createError } from "./error-BuByZwKU.mjs";
4
4
  import { coerceFilterDates, isFilter } from "@classytic/repo-core/filter";
5
+ //#region src/actions/create.ts
6
+ var create_exports = /* @__PURE__ */ __exportAll({
7
+ create: () => create,
8
+ createDefault: () => createDefault,
9
+ createMany: () => createMany,
10
+ isCreateManyPartialError: () => isCreateManyPartialError,
11
+ upsert: () => upsert
12
+ });
13
+ /**
14
+ * Create single document
15
+ */
16
+ async function create(Model, data, options = {}) {
17
+ const document = new Model(data);
18
+ await document.save({ session: options.session });
19
+ return document;
20
+ }
21
+ /** Narrow a caught error to one carrying a partial-write report. */
22
+ function isCreateManyPartialError(err) {
23
+ return err instanceof Error && typeof err.partial === "object" && err.partial !== null;
24
+ }
25
+ /** Pull the positional failures out of a driver bulk-write error. */
26
+ function readFailures(err, dataArray) {
27
+ const raw = err.writeErrors;
28
+ return (Array.isArray(raw) ? raw : raw ? [raw] : []).map((entry) => {
29
+ const e = entry;
30
+ const inner = e.err ?? e;
31
+ const index = Number(inner.index ?? e.index ?? -1);
32
+ return {
33
+ index,
34
+ doc: dataArray[index] ?? {},
35
+ ...typeof inner.code === "number" ? { code: inner.code } : {},
36
+ message: String(inner.errmsg ?? inner.message ?? e.message ?? "write failed")
37
+ };
38
+ });
39
+ }
40
+ /**
41
+ * Create multiple documents.
42
+ *
43
+ * **A rejection does NOT mean nothing was written.** Neither ordering does:
44
+ * `ordered: true` stops at the first failure and keeps everything before it,
45
+ * `ordered: false` keeps everything valid. Measured on a six-document batch
46
+ * with a conflict in the middle — ordered wrote 3, unordered wrote 5. Only a
47
+ * transaction gives all-or-nothing.
48
+ *
49
+ * So the rejection carries a `partial` report naming what landed and what did
50
+ * not, because the alternative is a caller retrying the whole batch and
51
+ * double-writing everything that had already succeeded. Use it to retry only
52
+ * `failed`, or to reconcile — and prefer a unique index or an idempotency key
53
+ * for anything that will be retried automatically.
54
+ */
55
+ async function createMany(Model, dataArray, options = {}) {
56
+ try {
57
+ return await Model.insertMany(dataArray, {
58
+ session: options.session,
59
+ ordered: options.ordered === true
60
+ });
61
+ } catch (err) {
62
+ const inserted = err.insertedDocs;
63
+ const failed = readFailures(err, dataArray);
64
+ if (Array.isArray(inserted) || failed.length > 0) err.partial = {
65
+ inserted: Array.isArray(inserted) ? inserted : [],
66
+ failed
67
+ };
68
+ throw err;
69
+ }
70
+ }
71
+ /**
72
+ * Create with defaults (useful for initialization)
73
+ */
74
+ async function createDefault(Model, overrides = {}, options = {}) {
75
+ const defaults = {};
76
+ Model.schema.eachPath((path, schemaType) => {
77
+ const schemaOptions = schemaType.options;
78
+ if (schemaOptions.default !== void 0 && path !== "_id") defaults[path] = typeof schemaOptions.default === "function" ? schemaOptions.default() : schemaOptions.default;
79
+ });
80
+ return create(Model, {
81
+ ...defaults,
82
+ ...overrides
83
+ }, options);
84
+ }
85
+ /**
86
+ * Upsert (create or update)
87
+ */
88
+ async function upsert(Model, query, data, options = {}) {
89
+ return Model.findOneAndUpdate(query, { $setOnInsert: data }, {
90
+ upsert: true,
91
+ returnDocument: "after",
92
+ runValidators: true,
93
+ session: options.session,
94
+ ...options.updatePipeline !== void 0 ? { updatePipeline: options.updatePipeline } : {}
95
+ });
96
+ }
97
+ //#endregion
98
+ //#region src/filter/cast-schema.ts
99
+ /** Operators whose operand is a single scalar to cast. */
100
+ const SCALAR_OPS = /* @__PURE__ */ new Set([
101
+ "$eq",
102
+ "$ne",
103
+ "$gt",
104
+ "$gte",
105
+ "$lt",
106
+ "$lte"
107
+ ]);
108
+ /** Operators whose operand is an array of scalars to cast element-wise. */
109
+ const ARRAY_OPS = /* @__PURE__ */ new Set(["$in", "$nin"]);
110
+ /** Logical operators whose operand is an ARRAY of sub-filters. */
111
+ const LOGICAL_ARRAY_OPS$1 = /* @__PURE__ */ new Set([
112
+ "$and",
113
+ "$or",
114
+ "$nor"
115
+ ]);
116
+ /** Logical operators whose operand is a SINGLE nested sub-filter. */
117
+ const LOGICAL_OBJECT_OPS = /* @__PURE__ */ new Set(["$not"]);
118
+ function isPlainObject(value) {
119
+ return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date);
120
+ }
121
+ /**
122
+ * Cast one value through a schema path. Returns the original value when the
123
+ * path is unknown, the value is nullish, or the cast throws — never raises.
124
+ */
125
+ function castValue(schema, field, value) {
126
+ if (value === null || value === void 0) return value;
127
+ if (typeof value === "object" && !(value instanceof Date)) return value;
128
+ let schemaType;
129
+ try {
130
+ schemaType = schema.path(field);
131
+ } catch {
132
+ return value;
133
+ }
134
+ if (!schemaType || typeof schemaType.cast !== "function") return value;
135
+ try {
136
+ return schemaType.cast(value);
137
+ } catch {
138
+ return value;
139
+ }
140
+ }
141
+ /**
142
+ * Cast the operand(s) of a field-level operator object, leaving operators we
143
+ * don't understand (`$regex`, `$exists`, `$size`, `$elemMatch`, …) alone.
144
+ */
145
+ function castOperatorObject(schema, field, ops) {
146
+ let changed = false;
147
+ const out = {};
148
+ for (const [op, operand] of Object.entries(ops)) if (SCALAR_OPS.has(op)) {
149
+ const next = castValue(schema, field, operand);
150
+ out[op] = next;
151
+ if (next !== operand) changed = true;
152
+ } else if (ARRAY_OPS.has(op) && Array.isArray(operand)) {
153
+ const arr = operand.map((entry) => castValue(schema, field, entry));
154
+ out[op] = arr;
155
+ if (arr.some((v, i) => v !== operand[i])) changed = true;
156
+ } else out[op] = operand;
157
+ return changed ? out : ops;
158
+ }
159
+ /**
160
+ * Cast a record-shape Mongo filter against a Mongoose schema so it is safe to
161
+ * hand to a `$match` stage. Recurses `$and` / `$or` / `$nor` / `$not`, since a
162
+ * policy/tenant scope conjoined with a caller filter nests one level down.
163
+ *
164
+ * Filter IR nodes and non-objects pass through untouched — IR values are built
165
+ * in code (already correctly typed) and carry no schema paths to resolve.
166
+ *
167
+ * @example
168
+ * ```ts
169
+ * // organizationId is an ObjectId column; arc supplies the scope id as a string
170
+ * castFilterToSchema({ organizationId: '6a6a…' }, Order.schema)
171
+ * // → { organizationId: ObjectId('6a6a…') }
172
+ * ```
173
+ */
174
+ function castFilterToSchema(filter, schema) {
175
+ if (!isPlainObject(filter)) return filter;
176
+ if (typeof filter.op === "string") return filter;
177
+ let changed = false;
178
+ const out = {};
179
+ for (const [key, value] of Object.entries(filter)) {
180
+ if (LOGICAL_ARRAY_OPS$1.has(key) && Array.isArray(value)) {
181
+ const arr = value.map((entry) => castFilterToSchema(entry, schema));
182
+ out[key] = arr;
183
+ if (arr.some((v, i) => v !== value[i])) changed = true;
184
+ continue;
185
+ }
186
+ if (LOGICAL_OBJECT_OPS.has(key) && isPlainObject(value)) {
187
+ const nested = castFilterToSchema(value, schema);
188
+ out[key] = nested;
189
+ if (nested !== value) changed = true;
190
+ continue;
191
+ }
192
+ if (key.startsWith("$")) {
193
+ out[key] = value;
194
+ continue;
195
+ }
196
+ if (isPlainObject(value)) {
197
+ const keys = Object.keys(value);
198
+ if (keys.length > 0 && keys.every((k) => k.startsWith("$"))) {
199
+ const nextOps = castOperatorObject(schema, key, value);
200
+ out[key] = nextOps;
201
+ if (nextOps !== value) changed = true;
202
+ continue;
203
+ }
204
+ out[key] = value;
205
+ continue;
206
+ }
207
+ const next = castValue(schema, key, value);
208
+ out[key] = next;
209
+ if (next !== value) changed = true;
210
+ }
211
+ return changed ? out : filter;
212
+ }
213
+ //#endregion
5
214
  //#region src/filter/compile.ts
6
215
  /**
7
216
  * Compile a Filter IR node to a MongoDB query object. Returns `{}`
@@ -21,6 +230,12 @@ import { coerceFilterDates, isFilter } from "@classytic/repo-core/filter";
21
230
  * handles them"). This set covers every operator the arc aggregation
22
231
  * guard accepts in `parseDateRange` and `hasFilterOnField`.
23
232
  */
233
+ /**
234
+ * The query-shorthand vocabulary, shared with `compileFilterToMongoExpr` so
235
+ * both filter surfaces recognise the same operator names. Exported because a
236
+ * second private copy is how the two compilers drifted apart in the first
237
+ * place: one accepted `{ f: { eq: 'x' } }` and the other read it as a literal.
238
+ */
24
239
  const SHORTHAND_OPS = /* @__PURE__ */ new Set([
25
240
  "eq",
26
241
  "ne",
@@ -98,7 +313,10 @@ function schemaDateOracle(schema) {
98
313
  }
99
314
  function compileFilterToMongo(input, schema) {
100
315
  if (!input) return {};
101
- if (!isFilter(input)) return coerceFilterDates(expandShorthands(input), schema ? { isDateField: schemaDateOracle(schema) } : void 0);
316
+ if (!isFilter(input)) {
317
+ const expanded = expandShorthands(input);
318
+ return coerceFilterDates(schema ? castFilterToSchema(expanded, schema) : expanded, schema ? { isDateField: schemaDateOracle(schema) } : void 0);
319
+ }
102
320
  return compile(input);
103
321
  }
104
322
  function compile(filter) {
@@ -106,7 +324,7 @@ function compile(filter) {
106
324
  case "true": return {};
107
325
  case "false": return { $expr: false };
108
326
  case "eq": return { [filter.field]: filter.value };
109
- case "ne": return filter.value === null ? { [filter.field]: { $ne: null } } : { $and: [{ [filter.field]: { $ne: filter.value } }, { [filter.field]: { $ne: null } }] };
327
+ case "ne": return filter.value === null ? { [filter.field]: { $ne: null } } : { [filter.field]: { $nin: [filter.value, null] } };
110
328
  case "gt": return { [filter.field]: { $gt: filter.value } };
111
329
  case "gte": return { [filter.field]: { $gte: filter.value } };
112
330
  case "lt": return { [filter.field]: { $lt: filter.value } };
@@ -116,7 +334,7 @@ function compile(filter) {
116
334
  return { [filter.field]: { $in: [...filter.values] } };
117
335
  case "nin":
118
336
  if (filter.values.length === 0) return {};
119
- return { [filter.field]: { $nin: [...filter.values] } };
337
+ return { [filter.field]: { $nin: filter.values.includes(null) ? [...filter.values] : [...filter.values, null] } };
120
338
  case "exists": return filter.exists ? { [filter.field]: { $ne: null } } : { [filter.field]: null };
121
339
  case "like": return { [filter.field]: likeToRegex(filter.pattern, filter.caseSensitivity) };
122
340
  /**
@@ -140,10 +358,10 @@ function compile(filter) {
140
358
  $options: filter.flags
141
359
  } : { $regex: filter.pattern } };
142
360
  case "and": {
143
- if (filter.children.length === 0) return {};
144
- const parts = filter.children.map(compile);
361
+ const parts = filter.children.map(compile).filter((part) => Object.keys(part).length > 0);
362
+ if (parts.length === 0) return {};
145
363
  if (parts.length === 1) return parts[0];
146
- return { $and: parts };
364
+ return mergeConjunction(parts) ?? { $and: parts };
147
365
  }
148
366
  case "or": {
149
367
  if (filter.children.length === 0) return { $expr: false };
@@ -175,7 +393,7 @@ function compile(filter) {
175
393
  * same way sqlitekit's `LIKE` semantically does.
176
394
  */
177
395
  function likeToRegex(pattern, caseSensitivity) {
178
- let out = "^";
396
+ let out = "";
179
397
  for (let i = 0; i < pattern.length; i++) {
180
398
  const ch = pattern[i];
181
399
  if (ch === "\\" && i + 1 < pattern.length) {
@@ -190,12 +408,44 @@ function likeToRegex(pattern, caseSensitivity) {
190
408
  else if (ch === "_") out += ".";
191
409
  else out += escapeRegexChar(ch);
192
410
  }
193
- out += "$";
194
- return caseSensitivity === "sensitive" ? { $regex: out } : {
195
- $regex: out,
411
+ const source = `${out.startsWith(".*") ? out.slice(2) : `^${out}`}`;
412
+ const anchored = source.endsWith(".*") && !source.endsWith("\\.*") ? source.slice(0, -2) : `${source}$`;
413
+ return caseSensitivity === "sensitive" ? { $regex: anchored } : {
414
+ $regex: anchored,
196
415
  $options: "i"
197
416
  };
198
417
  }
418
+ /**
419
+ * Merge an AND of field conditions into one object (`{ price: { $gte, $lte } }`) when no field
420
+ * repeats an operator; `undefined` when a merge would change meaning, so the caller keeps `$and`.
421
+ */
422
+ function mergeConjunction(parts) {
423
+ const merged = {};
424
+ for (const part of parts) for (const [field, condition] of Object.entries(part)) {
425
+ if (field.startsWith("$")) return void 0;
426
+ if (!(field in merged)) {
427
+ merged[field] = condition;
428
+ continue;
429
+ }
430
+ const left = asOperators(merged[field]);
431
+ const right = asOperators(condition);
432
+ if (!left || !right || Object.keys(right).some((op) => op in left)) return void 0;
433
+ merged[field] = {
434
+ ...left,
435
+ ...right
436
+ };
437
+ }
438
+ return merged;
439
+ }
440
+ /** A field condition as an operator object — an equality value becomes `{ $eq }`. */
441
+ function asOperators(condition) {
442
+ if (condition instanceof RegExp || Array.isArray(condition)) return void 0;
443
+ if (condition !== null && typeof condition === "object" && !(condition instanceof Date)) {
444
+ const keys = Object.keys(condition);
445
+ return keys.length > 0 && keys.every((k) => k.startsWith("$")) ? condition : void 0;
446
+ }
447
+ return condition === null ? void 0 : { $eq: condition };
448
+ }
199
449
  function escapeRegexChar(ch) {
200
450
  return /[.*+?^${}()|[\]\\]/.test(ch) ? `\\${ch}` : ch;
201
451
  }
@@ -611,24 +861,35 @@ async function aggregate(Model, pipeline, options = {}) {
611
861
  return aggregation.exec();
612
862
  }
613
863
  /**
614
- * Aggregate with pagination using native MongoDB $facet
615
- * WARNING: $facet results must be <16MB. For larger results (limit >1000),
616
- * consider using Repository.aggregatePaginate() or splitting into separate queries.
864
+ * Aggregate with pagination.
865
+ *
866
+ * Page and count run as TWO concurrent pipelines rather than one `$facet`.
867
+ * `$facet` bundles every returned document plus the count into a SINGLE output
868
+ * document, and no stage may exceed 16MB — so a page of large documents failed
869
+ * with `BSONObjectTooLarge` instead of paginating, and the only defence was a
870
+ * warning above an arbitrary limit of 1000 that told the caller to go
871
+ * elsewhere. `$facet` also cannot use an index for the stages inside it.
872
+ *
873
+ * The trade: two reads, so a concurrent write between them can leave `total`
874
+ * a document out of step with `data` — the same trade `PaginationEngine`
875
+ * already makes on both its offset and aggregate paths.
617
876
  */
618
877
  async function aggregatePaginate(Model, pipeline, options = {}) {
619
878
  const page = parseInt(String(options.page || 1), 10);
620
879
  const limit = parseInt(String(options.limit || 10), 10);
621
880
  const skip = (page - 1) * limit;
622
- if (limit > 1e3) warn(`[mongokit] Large aggregation limit (${limit}). $facet results must be <16MB. Consider using Repository.aggregatePaginate() for safer handling of large datasets.`);
623
- const facetPipeline = [...pipeline, { $facet: {
624
- data: [{ $skip: skip }, { $limit: limit }],
625
- total: [{ $count: "count" }]
626
- } }];
627
- const aggregation = Model.aggregate(facetPipeline);
628
- if (options.session) aggregation.session(options.session);
629
- const [result] = await aggregation.exec();
630
- const data = result.data || [];
631
- const total = result.total[0]?.count || 0;
881
+ const run = (stages) => {
882
+ const aggregation = Model.aggregate(stages);
883
+ if (options.session) aggregation.session(options.session);
884
+ return aggregation.exec();
885
+ };
886
+ const [dataRows, countRows] = await Promise.all([run([
887
+ ...pipeline,
888
+ { $skip: skip },
889
+ { $limit: limit }
890
+ ]), run([...pipeline, { $count: "count" }])]);
891
+ const data = dataRows || [];
892
+ const total = countRows[0]?.count || 0;
632
893
  const pages = Math.ceil(total / limit);
633
894
  return {
634
895
  data,
@@ -748,57 +1009,6 @@ async function minMax(Model, field, query = {}, options = {}) {
748
1009
  };
749
1010
  }
750
1011
  //#endregion
751
- //#region src/actions/create.ts
752
- var create_exports = /* @__PURE__ */ __exportAll({
753
- create: () => create,
754
- createDefault: () => createDefault,
755
- createMany: () => createMany,
756
- upsert: () => upsert
757
- });
758
- /**
759
- * Create single document
760
- */
761
- async function create(Model, data, options = {}) {
762
- const document = new Model(data);
763
- await document.save({ session: options.session });
764
- return document;
765
- }
766
- /**
767
- * Create multiple documents
768
- */
769
- async function createMany(Model, dataArray, options = {}) {
770
- return Model.insertMany(dataArray, {
771
- session: options.session,
772
- ordered: options.ordered === true
773
- });
774
- }
775
- /**
776
- * Create with defaults (useful for initialization)
777
- */
778
- async function createDefault(Model, overrides = {}, options = {}) {
779
- const defaults = {};
780
- Model.schema.eachPath((path, schemaType) => {
781
- const schemaOptions = schemaType.options;
782
- if (schemaOptions.default !== void 0 && path !== "_id") defaults[path] = typeof schemaOptions.default === "function" ? schemaOptions.default() : schemaOptions.default;
783
- });
784
- return create(Model, {
785
- ...defaults,
786
- ...overrides
787
- }, options);
788
- }
789
- /**
790
- * Upsert (create or update)
791
- */
792
- async function upsert(Model, query, data, options = {}) {
793
- return Model.findOneAndUpdate(query, { $setOnInsert: data }, {
794
- upsert: true,
795
- returnDocument: "after",
796
- runValidators: true,
797
- session: options.session,
798
- ...options.updatePipeline !== void 0 ? { updatePipeline: options.updatePipeline } : {}
799
- });
800
- }
801
- //#endregion
802
1012
  //#region src/actions/delete.ts
803
1013
  var delete_exports = /* @__PURE__ */ __exportAll({
804
1014
  deleteById: () => deleteById,
@@ -813,8 +1023,8 @@ var delete_exports = /* @__PURE__ */ __exportAll({
813
1023
  */
814
1024
  async function deleteById(Model, id, options = {}) {
815
1025
  const query = {
816
- _id: id,
817
- ...options.query
1026
+ ...options.query,
1027
+ _id: id
818
1028
  };
819
1029
  if (!await Model.findOneAndDelete(query).session(options.session ?? null)) return null;
820
1030
  return {
@@ -1053,8 +1263,8 @@ function parsePopulate(populate) {
1053
1263
  async function update(Model, id, data, options = {}) {
1054
1264
  assertUpdatePipelineAllowed(data, options.updatePipeline);
1055
1265
  const query = {
1056
- _id: id,
1057
- ...options.query
1266
+ ...options.query,
1267
+ _id: id
1058
1268
  };
1059
1269
  return await Model.findOneAndUpdate(query, data, {
1060
1270
  returnDocument: "after",
@@ -1071,8 +1281,8 @@ async function update(Model, id, data, options = {}) {
1071
1281
  async function updateWithConstraints(Model, id, data, constraints = {}, options = {}) {
1072
1282
  assertUpdatePipelineAllowed(data, options.updatePipeline);
1073
1283
  const query = {
1074
- _id: id,
1075
- ...constraints
1284
+ ...constraints,
1285
+ _id: id
1076
1286
  };
1077
1287
  return await Model.findOneAndUpdate(query, data, {
1078
1288
  returnDocument: "after",
@@ -1097,8 +1307,8 @@ async function updateWithValidation(Model, id, data, validationOptions = {}, opt
1097
1307
  };
1098
1308
  }
1099
1309
  const findQuery = {
1100
- _id: id,
1101
- ...options.query
1310
+ ...options.query,
1311
+ _id: id
1102
1312
  };
1103
1313
  const existing = await Model.findOne(findQuery).select(options.select || "").session(options.session ?? null).lean();
1104
1314
  if (!existing) return {
@@ -1204,4 +1414,4 @@ async function pullFromArray(Model, id, field, value, options = {}) {
1204
1414
  return update(Model, id, { $pull: { [field]: value } }, options);
1205
1415
  }
1206
1416
  //#endregion
1207
- export { upsert as _, count as a, LookupBuilder as b, getByQuery as c, deleteById as d, deleteByQuery as f, create_exports as g, createMany as h, update_exports as i, getOrCreate as l, create as m, update as n, exists as o, delete_exports as p, updateByQuery as r, getById as s, findOneAndUpdate as t, read_exports as u, aggregate_exports as v, compileFilterToMongo as x, distinct as y };
1417
+ export { isCreateManyPartialError as C, create_exports as S, SHORTHAND_OPS as _, count as a, create as b, getByQuery as c, deleteById as d, deleteByQuery as f, LookupBuilder as g, distinct as h, update_exports as i, getOrCreate as l, aggregate_exports as m, update as n, exists as o, delete_exports as p, updateByQuery as r, getById as s, findOneAndUpdate as t, read_exports as u, compileFilterToMongo as v, upsert as w, createMany as x, castFilterToSchema as y };
@@ -1,4 +1,4 @@
1
- import { _ as getMongooseProjection, a as createMemoryCache, b as createError, c as IdType, d as isObjectIdInstance, f as isValidIdForType, g as getFieldsForUser, h as filterResponseData, i as buildCrudSchemasFromMongooseSchema, l as getSchemaIdType, m as createFieldPreset, n as CrudSchemasFramework, o as LoggerConfig, p as toObjectId, r as buildCrudSchemasFromModel, s as configureLogger, t as toPlain, v as CreateErrorOptions, y as ParseDuplicateKeyOptions } from "../to-plain-Dyz_qvuo.mjs";
1
+ import { _ as getMongooseProjection, a as createMemoryCache, b as createError, c as IdType, d as isObjectIdInstance, f as isValidIdForType, g as getFieldsForUser, h as filterResponseData, i as buildCrudSchemasFromMongooseSchema, l as getSchemaIdType, m as createFieldPreset, n as CrudSchemasFramework, o as LoggerConfig, p as toObjectId, r as buildCrudSchemasFromModel, s as configureLogger, t as toPlain, v as CreateErrorOptions, y as ParseDuplicateKeyOptions } from "../to-plain-k7SjNlSS.mjs";
2
2
  import { ClientSession, Model } from "mongoose";
3
3
  //#region src/utils/id-chunks.d.ts
4
4
  /**