@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.
- package/dist/{PaginationEngine-CBS1XGzp.d.mts → PaginationEngine-D-P19Y9m.d.mts} +34 -9
- package/dist/PaginationEngine-Dvl8jcRY.mjs +1198 -0
- package/dist/{Repository-Ck5x43wF.mjs → Repository-BMgPSkqZ.mjs} +672 -655
- package/dist/{Repository-BdSkQ8vc.d.mts → Repository-CR8Y9g2E.d.mts} +106 -34
- package/dist/actions/index.d.mts +1 -1
- package/dist/actions/index.mjs +1 -1
- package/dist/adapter/index.d.mts +21 -0
- package/dist/adapter/index.mjs +1 -1
- package/dist/{adapter-Bfqz8yHE.mjs → adapter-BrVfPFSW.mjs} +45 -1
- package/dist/ai/index.d.mts +1 -1
- package/dist/better-auth/index.mjs +2 -2
- package/dist/{create-repository-B5EulQ31.mjs → create-repository-BzBUMvd1.mjs} +3 -3
- package/dist/{create-repository-BU4x9Kb0.d.mts → create-repository-CAle1MSU.d.mts} +5 -5
- package/dist/idempotency/index.d.mts +23 -0
- package/dist/idempotency/index.mjs +134 -0
- package/dist/{index-DKEql4cL.d.mts → index-CmjNyulu.d.mts} +67 -8
- package/dist/index.d.mts +125 -35
- package/dist/index.mjs +286 -676
- package/dist/indexes/verify-indexes.d.mts +14 -1
- package/dist/indexes/verify-indexes.mjs +54 -7
- package/dist/{method-registry.plugin-DblM7V6j.mjs → method-registry.plugin-C63pGn1d.mjs} +54 -4
- package/dist/{multi-tenant.plugin-BwSvTirB.d.mts → multi-tenant.plugin-CBgCo9im.d.mts} +77 -5
- package/dist/{operations-DZodvjC-.d.mts → operations-CrRIoc8Z.d.mts} +22 -7
- package/dist/outbox/index.d.mts +1 -1
- package/dist/outbox/index.mjs +7 -5
- package/dist/pagination/PaginationEngine.d.mts +1 -1
- package/dist/pagination/PaginationEngine.mjs +1 -1
- package/dist/pagination/utils/limits.d.mts +1 -1
- package/dist/pagination/utils/limits.mjs +22 -1
- package/dist/pagination-BpIv2bdS.d.mts +364 -0
- package/dist/{plugin-options-DXnlKM3B.d.mts → plugin-options-Zk46lD6F.d.mts} +16 -2
- package/dist/plugins/index.d.mts +8 -3
- package/dist/plugins/index.mjs +99 -26
- package/dist/{repository-H_ffGgpE.d.mts → repository-odl03582.d.mts} +50 -6
- package/dist/sync/index.d.mts +40 -0
- package/dist/sync/index.mjs +334 -0
- package/dist/tenant/index.d.mts +89 -0
- package/dist/tenant/index.mjs +96 -0
- package/dist/testkit/index.d.mts +2 -2
- package/dist/testkit/index.mjs +1 -1
- package/dist/{timestamp.plugin-CBQukQzV.mjs → timestamp.plugin-DF0gJB6p.mjs} +116 -9
- package/dist/{to-plain-Dyz_qvuo.d.mts → to-plain-k7SjNlSS.d.mts} +2 -2
- package/dist/transaction-B5L9glO0.mjs +533 -0
- package/dist/{update-jSXp3nu3.mjs → update-DG0fCwRJ.mjs} +293 -83
- package/dist/utils/index.d.mts +1 -1
- package/dist/{validation-chain.plugin-DhNyxNCw.mjs → validation-chain.plugin-BLY2gLEk.mjs} +192 -279
- package/dist/{validation-chain.plugin-yQRob3Av.d.mts → validation-chain.plugin-DYp9E7K2.d.mts} +26 -20
- package/package.json +17 -4
- package/dist/PaginationEngine-BX9o_-4R.mjs +0 -735
- package/dist/core-62oo3N1C.d.mts +0 -50
- 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))
|
|
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 } } : {
|
|
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
|
-
|
|
144
|
-
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
|
615
|
-
*
|
|
616
|
-
*
|
|
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
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
}
|
|
627
|
-
const
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
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
|
-
|
|
817
|
-
|
|
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
|
-
|
|
1057
|
-
|
|
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
|
-
|
|
1075
|
-
|
|
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
|
-
|
|
1101
|
-
|
|
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 {
|
|
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 };
|
package/dist/utils/index.d.mts
CHANGED
|
@@ -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-
|
|
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
|
/**
|