@zodmon/core 0.6.0 → 0.8.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/index.cjs +703 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1375 -444
- package/dist/index.d.ts +1375 -444
- package/dist/index.js +686 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,19 +1,170 @@
|
|
|
1
1
|
// src/client/client.ts
|
|
2
2
|
import { MongoClient } from "mongodb";
|
|
3
3
|
|
|
4
|
-
// src/
|
|
5
|
-
|
|
4
|
+
// src/indexes/spec.ts
|
|
5
|
+
function toFieldIndexSpec(def) {
|
|
6
|
+
const direction = def.text ? "text" : def.descending ? -1 : 1;
|
|
7
|
+
const key = { [def.field]: direction };
|
|
8
|
+
const options = {};
|
|
9
|
+
if (def.unique) options["unique"] = true;
|
|
10
|
+
if (def.sparse) options["sparse"] = true;
|
|
11
|
+
if (def.expireAfter !== void 0) options["expireAfterSeconds"] = def.expireAfter;
|
|
12
|
+
if (def.partial) options["partialFilterExpression"] = def.partial;
|
|
13
|
+
return { key, options };
|
|
14
|
+
}
|
|
15
|
+
function toCompoundIndexSpec(def) {
|
|
16
|
+
const key = { ...def.fields };
|
|
17
|
+
const options = {};
|
|
18
|
+
if (def.options?.unique) options["unique"] = true;
|
|
19
|
+
if (def.options?.sparse) options["sparse"] = true;
|
|
20
|
+
if (def.options?.name) options["name"] = def.options.name;
|
|
21
|
+
if (def.options?.partial) options["partialFilterExpression"] = def.options.partial;
|
|
22
|
+
return { key, options };
|
|
23
|
+
}
|
|
24
|
+
function serializeIndexKey(key) {
|
|
25
|
+
return Object.entries(key).map(([field, dir]) => `${field}:${dir}`).join(",");
|
|
26
|
+
}
|
|
6
27
|
|
|
7
|
-
// src/
|
|
8
|
-
var
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
28
|
+
// src/indexes/sync.ts
|
|
29
|
+
var COMPARABLE_OPTION_KEYS = [
|
|
30
|
+
"unique",
|
|
31
|
+
"sparse",
|
|
32
|
+
"expireAfterSeconds",
|
|
33
|
+
"partialFilterExpression"
|
|
34
|
+
];
|
|
35
|
+
function extractComparableOptions(info) {
|
|
36
|
+
const result = {};
|
|
37
|
+
for (const key of COMPARABLE_OPTION_KEYS) {
|
|
38
|
+
if (info[key] !== void 0) {
|
|
39
|
+
result[key] = info[key];
|
|
40
|
+
}
|
|
15
41
|
}
|
|
16
|
-
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
function generateIndexName(key) {
|
|
45
|
+
return Object.entries(key).map(([field, dir]) => `${field}_${dir}`).join("_");
|
|
46
|
+
}
|
|
47
|
+
function sortKeys(obj) {
|
|
48
|
+
const sorted = {};
|
|
49
|
+
for (const key of Object.keys(obj).sort()) {
|
|
50
|
+
sorted[key] = obj[key];
|
|
51
|
+
}
|
|
52
|
+
return sorted;
|
|
53
|
+
}
|
|
54
|
+
function resolveSpecName(spec) {
|
|
55
|
+
const specName = spec.options["name"];
|
|
56
|
+
return typeof specName === "string" ? specName : generateIndexName(spec.key);
|
|
57
|
+
}
|
|
58
|
+
function resolveExistingName(info, key) {
|
|
59
|
+
const infoName = info["name"];
|
|
60
|
+
if (typeof infoName === "string") return infoName;
|
|
61
|
+
return generateIndexName(key);
|
|
62
|
+
}
|
|
63
|
+
function optionsMatch(a, b) {
|
|
64
|
+
return JSON.stringify(sortKeys(stripName(a))) === JSON.stringify(sortKeys(stripName(b)));
|
|
65
|
+
}
|
|
66
|
+
function stripName(obj) {
|
|
67
|
+
const { name: _, ...rest } = obj;
|
|
68
|
+
return rest;
|
|
69
|
+
}
|
|
70
|
+
async function processDesiredSpec(spec, existingByKey, native, dryRun, dropOrphaned, acc) {
|
|
71
|
+
const serialized = serializeIndexKey(spec.key);
|
|
72
|
+
const existing = existingByKey.get(serialized);
|
|
73
|
+
if (!existing) {
|
|
74
|
+
if (!dryRun) await native.createIndex(spec.key, spec.options);
|
|
75
|
+
acc.created.push(resolveSpecName(spec));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
acc.matchedKeys.add(serialized);
|
|
79
|
+
const existingName = resolveExistingName(existing, spec.key);
|
|
80
|
+
const existingOpts = extractComparableOptions(existing);
|
|
81
|
+
if (optionsMatch(existingOpts, spec.options)) {
|
|
82
|
+
acc.skipped.push(existingName);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (dropOrphaned) {
|
|
86
|
+
if (!dryRun) {
|
|
87
|
+
await native.dropIndex(existingName);
|
|
88
|
+
await native.createIndex(spec.key, spec.options);
|
|
89
|
+
}
|
|
90
|
+
acc.dropped.push(existingName);
|
|
91
|
+
acc.created.push(resolveSpecName(spec));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
acc.stale.push({
|
|
95
|
+
name: existingName,
|
|
96
|
+
key: spec.key,
|
|
97
|
+
existing: existingOpts,
|
|
98
|
+
desired: spec.options
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
async function processOrphanedIndexes(existingIndexes, desiredKeys, matchedKeys, native, dryRun, dropOrphaned, dropped) {
|
|
102
|
+
for (const idx of existingIndexes) {
|
|
103
|
+
const rawName = idx["name"];
|
|
104
|
+
const name = typeof rawName === "string" ? rawName : "";
|
|
105
|
+
if (name === "_id_") continue;
|
|
106
|
+
const serialized = serializeIndexKey(idx["key"]);
|
|
107
|
+
if (matchedKeys.has(serialized) || desiredKeys.has(serialized)) continue;
|
|
108
|
+
if (dropOrphaned) {
|
|
109
|
+
if (!dryRun) await native.dropIndex(name);
|
|
110
|
+
dropped.push(name);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function listIndexesSafe(native) {
|
|
115
|
+
try {
|
|
116
|
+
return await native.listIndexes().toArray();
|
|
117
|
+
} catch (err) {
|
|
118
|
+
if (err instanceof Error && err.message.includes("ns does not exist")) {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async function syncIndexes(handle, options) {
|
|
125
|
+
const { dryRun = false, dropOrphaned = false } = options ?? {};
|
|
126
|
+
const native = handle.native;
|
|
127
|
+
const def = handle.definition;
|
|
128
|
+
const desiredSpecs = [
|
|
129
|
+
...def.fieldIndexes.map(toFieldIndexSpec),
|
|
130
|
+
...def.compoundIndexes.map(toCompoundIndexSpec)
|
|
131
|
+
];
|
|
132
|
+
const existingIndexes = await listIndexesSafe(native);
|
|
133
|
+
const existingByKey = /* @__PURE__ */ new Map();
|
|
134
|
+
for (const idx of existingIndexes) {
|
|
135
|
+
const serialized = serializeIndexKey(idx["key"]);
|
|
136
|
+
existingByKey.set(serialized, idx);
|
|
137
|
+
}
|
|
138
|
+
const acc = {
|
|
139
|
+
created: [],
|
|
140
|
+
dropped: [],
|
|
141
|
+
skipped: [],
|
|
142
|
+
stale: [],
|
|
143
|
+
matchedKeys: /* @__PURE__ */ new Set()
|
|
144
|
+
};
|
|
145
|
+
for (const spec of desiredSpecs) {
|
|
146
|
+
await processDesiredSpec(spec, existingByKey, native, dryRun, dropOrphaned, acc);
|
|
147
|
+
}
|
|
148
|
+
const desiredKeys = new Set(desiredSpecs.map((s) => serializeIndexKey(s.key)));
|
|
149
|
+
await processOrphanedIndexes(
|
|
150
|
+
existingIndexes,
|
|
151
|
+
desiredKeys,
|
|
152
|
+
acc.matchedKeys,
|
|
153
|
+
native,
|
|
154
|
+
dryRun,
|
|
155
|
+
dropOrphaned,
|
|
156
|
+
acc.dropped
|
|
157
|
+
);
|
|
158
|
+
return {
|
|
159
|
+
created: acc.created,
|
|
160
|
+
dropped: acc.dropped,
|
|
161
|
+
skipped: acc.skipped,
|
|
162
|
+
stale: acc.stale
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/crud/delete.ts
|
|
167
|
+
import { z } from "zod";
|
|
17
168
|
|
|
18
169
|
// src/errors/validation.ts
|
|
19
170
|
var ZodmonValidationError = class extends Error {
|
|
@@ -33,8 +184,136 @@ var ZodmonValidationError = class extends Error {
|
|
|
33
184
|
}
|
|
34
185
|
};
|
|
35
186
|
|
|
187
|
+
// src/crud/delete.ts
|
|
188
|
+
async function deleteOne(handle, filter) {
|
|
189
|
+
return await handle.native.deleteOne(filter);
|
|
190
|
+
}
|
|
191
|
+
async function deleteMany(handle, filter) {
|
|
192
|
+
return await handle.native.deleteMany(filter);
|
|
193
|
+
}
|
|
194
|
+
async function findOneAndDelete(handle, filter, options) {
|
|
195
|
+
const result = await handle.native.findOneAndDelete(
|
|
196
|
+
// biome-ignore lint/suspicious/noExplicitAny: TypedFilter intersection type is not directly assignable to MongoDB's Filter
|
|
197
|
+
filter,
|
|
198
|
+
{ includeResultMetadata: false }
|
|
199
|
+
);
|
|
200
|
+
if (!result) return null;
|
|
201
|
+
const mode = options?.validate !== void 0 ? options.validate : handle.definition.options.validation;
|
|
202
|
+
if (mode === false || mode === "passthrough") {
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
return handle.definition.schema.parse(result);
|
|
207
|
+
} catch (err) {
|
|
208
|
+
if (err instanceof z.ZodError) {
|
|
209
|
+
throw new ZodmonValidationError(handle.definition.name, err);
|
|
210
|
+
}
|
|
211
|
+
throw err;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// src/crud/find.ts
|
|
216
|
+
import { z as z3 } from "zod";
|
|
217
|
+
|
|
218
|
+
// src/errors/not-found.ts
|
|
219
|
+
var ZodmonNotFoundError = class extends Error {
|
|
220
|
+
name = "ZodmonNotFoundError";
|
|
221
|
+
/** The MongoDB collection name where the query found no results. */
|
|
222
|
+
collection;
|
|
223
|
+
constructor(collection2) {
|
|
224
|
+
super(`Document not found in "${collection2}"`);
|
|
225
|
+
this.collection = collection2;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
// src/indexes/warn.ts
|
|
230
|
+
var SKIP_OPERATORS = /* @__PURE__ */ new Set(["$or", "$and", "$nor", "$text", "$where", "$expr", "$comment"]);
|
|
231
|
+
function checkUnindexedFields(definition, filter) {
|
|
232
|
+
if (definition.options.warnUnindexedQueries !== true) return;
|
|
233
|
+
const covered = /* @__PURE__ */ new Set();
|
|
234
|
+
for (const fi of definition.fieldIndexes) {
|
|
235
|
+
covered.add(fi.field);
|
|
236
|
+
}
|
|
237
|
+
for (const ci of definition.compoundIndexes) {
|
|
238
|
+
const firstField = Object.keys(ci.fields)[0];
|
|
239
|
+
if (firstField !== void 0) {
|
|
240
|
+
covered.add(firstField);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
for (const key of Object.keys(filter)) {
|
|
244
|
+
if (key === "_id") continue;
|
|
245
|
+
if (SKIP_OPERATORS.has(key)) continue;
|
|
246
|
+
if (!covered.has(key)) {
|
|
247
|
+
console.warn(`[zodmon] warn: query on '${definition.name}' uses unindexed field '${key}'`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/query/cursor.ts
|
|
253
|
+
import { z as z2 } from "zod";
|
|
254
|
+
|
|
255
|
+
// src/crud/paginate.ts
|
|
256
|
+
import { ObjectId } from "mongodb";
|
|
257
|
+
function serializeValue(value) {
|
|
258
|
+
if (value instanceof ObjectId) return { $oid: value.toHexString() };
|
|
259
|
+
if (value instanceof Date) return { $date: value.getTime() };
|
|
260
|
+
return value;
|
|
261
|
+
}
|
|
262
|
+
function deserializeValue(value) {
|
|
263
|
+
if (value != null && typeof value === "object") {
|
|
264
|
+
if ("$oid" in value) return new ObjectId(value.$oid);
|
|
265
|
+
if ("$date" in value) return new Date(value.$date);
|
|
266
|
+
}
|
|
267
|
+
return value;
|
|
268
|
+
}
|
|
269
|
+
function encodeCursor(doc, sortKeys2, direction) {
|
|
270
|
+
const values = sortKeys2.map(([field]) => serializeValue(doc[field]));
|
|
271
|
+
return btoa(JSON.stringify([direction, ...values]));
|
|
272
|
+
}
|
|
273
|
+
function decodeCursor(cursor) {
|
|
274
|
+
let parsed;
|
|
275
|
+
try {
|
|
276
|
+
parsed = JSON.parse(atob(cursor));
|
|
277
|
+
} catch {
|
|
278
|
+
throw new Error("Invalid cursor: malformed encoding");
|
|
279
|
+
}
|
|
280
|
+
if (!Array.isArray(parsed) || parsed.length < 1) {
|
|
281
|
+
throw new Error("Invalid cursor: expected non-empty array");
|
|
282
|
+
}
|
|
283
|
+
const [direction, ...rawValues] = parsed;
|
|
284
|
+
if (direction !== "f" && direction !== "b") {
|
|
285
|
+
throw new Error("Invalid cursor: unknown direction flag");
|
|
286
|
+
}
|
|
287
|
+
return { direction, values: rawValues.map(deserializeValue) };
|
|
288
|
+
}
|
|
289
|
+
function buildCursorFilter(sortKeys2, values, isBackward) {
|
|
290
|
+
const clauses = [];
|
|
291
|
+
for (let i = 0; i < sortKeys2.length; i++) {
|
|
292
|
+
const clause = {};
|
|
293
|
+
for (let j = 0; j < i; j++) {
|
|
294
|
+
clause[sortKeys2[j][0]] = values[j];
|
|
295
|
+
}
|
|
296
|
+
const [field, direction] = sortKeys2[i];
|
|
297
|
+
const isAsc = direction === 1;
|
|
298
|
+
const op = isAsc !== isBackward ? "$gt" : "$lt";
|
|
299
|
+
if (values[i] === null) {
|
|
300
|
+
clause[field] = { $ne: null };
|
|
301
|
+
} else {
|
|
302
|
+
clause[field] = { [op]: values[i] };
|
|
303
|
+
}
|
|
304
|
+
clauses.push(clause);
|
|
305
|
+
}
|
|
306
|
+
return { $or: clauses };
|
|
307
|
+
}
|
|
308
|
+
function resolveSortKeys(sortSpec) {
|
|
309
|
+
const entries = sortSpec ? Object.entries(sortSpec) : [];
|
|
310
|
+
if (!entries.some(([field]) => field === "_id")) {
|
|
311
|
+
entries.push(["_id", 1]);
|
|
312
|
+
}
|
|
313
|
+
return entries;
|
|
314
|
+
}
|
|
315
|
+
|
|
36
316
|
// src/query/cursor.ts
|
|
37
|
-
import { z } from "zod";
|
|
38
317
|
var TypedFindCursor = class {
|
|
39
318
|
/** @internal */
|
|
40
319
|
cursor;
|
|
@@ -45,11 +324,21 @@ var TypedFindCursor = class {
|
|
|
45
324
|
/** @internal */
|
|
46
325
|
mode;
|
|
47
326
|
/** @internal */
|
|
48
|
-
|
|
327
|
+
nativeCollection;
|
|
328
|
+
/** @internal */
|
|
329
|
+
// biome-ignore lint/suspicious/noExplicitAny: TypedFilter is not assignable to MongoDB's Filter; stored opaquely for paginate
|
|
330
|
+
filter;
|
|
331
|
+
/** @internal */
|
|
332
|
+
sortSpec;
|
|
333
|
+
/** @internal */
|
|
334
|
+
constructor(cursor, definition, mode, nativeCollection, filter) {
|
|
49
335
|
this.cursor = cursor;
|
|
50
336
|
this.schema = definition.schema;
|
|
51
337
|
this.collectionName = definition.name;
|
|
52
338
|
this.mode = mode;
|
|
339
|
+
this.nativeCollection = nativeCollection;
|
|
340
|
+
this.filter = filter;
|
|
341
|
+
this.sortSpec = null;
|
|
53
342
|
}
|
|
54
343
|
/**
|
|
55
344
|
* Set the sort order for the query.
|
|
@@ -66,6 +355,7 @@ var TypedFindCursor = class {
|
|
|
66
355
|
* ```
|
|
67
356
|
*/
|
|
68
357
|
sort(spec) {
|
|
358
|
+
this.sortSpec = spec;
|
|
69
359
|
this.cursor.sort(spec);
|
|
70
360
|
return this;
|
|
71
361
|
}
|
|
@@ -99,6 +389,80 @@ var TypedFindCursor = class {
|
|
|
99
389
|
this.cursor.limit(n);
|
|
100
390
|
return this;
|
|
101
391
|
}
|
|
392
|
+
/**
|
|
393
|
+
* Force the query optimizer to use the specified index.
|
|
394
|
+
*
|
|
395
|
+
* Only accepts index names that were declared via `.name()` in the
|
|
396
|
+
* collection definition. If no named indexes exist, any string is accepted.
|
|
397
|
+
*
|
|
398
|
+
* @param indexName - The name of a declared compound index.
|
|
399
|
+
* @returns `this` for chaining.
|
|
400
|
+
*
|
|
401
|
+
* @example
|
|
402
|
+
* ```ts
|
|
403
|
+
* const Users = collection('users', { email: z.string(), role: z.string() }, {
|
|
404
|
+
* indexes: [index({ email: 1, role: -1 }).name('email_role_idx')],
|
|
405
|
+
* })
|
|
406
|
+
* const admins = await users.find({ role: 'admin' })
|
|
407
|
+
* .hint('email_role_idx')
|
|
408
|
+
* .toArray()
|
|
409
|
+
* ```
|
|
410
|
+
*/
|
|
411
|
+
hint(indexName) {
|
|
412
|
+
this.cursor.hint(indexName);
|
|
413
|
+
return this;
|
|
414
|
+
}
|
|
415
|
+
async paginate(opts) {
|
|
416
|
+
const sortRecord = this.sortSpec ? this.sortSpec : null;
|
|
417
|
+
const sortKeys2 = resolveSortKeys(sortRecord);
|
|
418
|
+
const sort = Object.fromEntries(sortKeys2);
|
|
419
|
+
if ("page" in opts) {
|
|
420
|
+
return await this.offsetPaginate(sortKeys2, sort, opts);
|
|
421
|
+
}
|
|
422
|
+
return await this.cursorPaginate(sortKeys2, sort, opts);
|
|
423
|
+
}
|
|
424
|
+
/** @internal Offset pagination implementation. */
|
|
425
|
+
async offsetPaginate(_sortKeys, sort, opts) {
|
|
426
|
+
const [total, raw2] = await Promise.all([
|
|
427
|
+
this.nativeCollection.countDocuments(this.filter),
|
|
428
|
+
this.nativeCollection.find(this.filter).sort(sort).skip((opts.page - 1) * opts.perPage).limit(opts.perPage).toArray()
|
|
429
|
+
]);
|
|
430
|
+
const docs = raw2.map((doc) => this.validateDoc(doc));
|
|
431
|
+
const totalPages = Math.ceil(total / opts.perPage);
|
|
432
|
+
return {
|
|
433
|
+
docs,
|
|
434
|
+
total,
|
|
435
|
+
page: opts.page,
|
|
436
|
+
perPage: opts.perPage,
|
|
437
|
+
totalPages,
|
|
438
|
+
hasNext: opts.page < totalPages,
|
|
439
|
+
hasPrev: opts.page > 1
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
/** @internal Cursor pagination implementation. */
|
|
443
|
+
async cursorPaginate(sortKeys2, sort, opts) {
|
|
444
|
+
let isBackward = false;
|
|
445
|
+
let combinedFilter = this.filter;
|
|
446
|
+
if (opts.cursor) {
|
|
447
|
+
const decoded = decodeCursor(opts.cursor);
|
|
448
|
+
isBackward = decoded.direction === "b";
|
|
449
|
+
const cursorFilter = buildCursorFilter(sortKeys2, decoded.values, isBackward);
|
|
450
|
+
combinedFilter = this.filter && Object.keys(this.filter).length > 0 ? { $and: [this.filter, cursorFilter] } : cursorFilter;
|
|
451
|
+
}
|
|
452
|
+
const effectiveSort = isBackward ? Object.fromEntries(sortKeys2.map(([f, d]) => [f, d === 1 ? -1 : 1])) : sort;
|
|
453
|
+
const raw2 = await this.nativeCollection.find(combinedFilter).sort(effectiveSort).limit(opts.limit + 1).toArray();
|
|
454
|
+
const hasMore = raw2.length > opts.limit;
|
|
455
|
+
if (hasMore) raw2.pop();
|
|
456
|
+
if (isBackward) raw2.reverse();
|
|
457
|
+
const docs = raw2.map((doc) => this.validateDoc(doc));
|
|
458
|
+
return {
|
|
459
|
+
docs,
|
|
460
|
+
hasNext: isBackward ? true : hasMore,
|
|
461
|
+
hasPrev: isBackward ? hasMore : opts.cursor != null,
|
|
462
|
+
startCursor: docs.length > 0 ? encodeCursor(docs[0], sortKeys2, "b") : null,
|
|
463
|
+
endCursor: docs.length > 0 ? encodeCursor(docs[docs.length - 1], sortKeys2, "f") : null
|
|
464
|
+
};
|
|
465
|
+
}
|
|
102
466
|
/**
|
|
103
467
|
* Execute the query and return all matching documents as an array.
|
|
104
468
|
*
|
|
@@ -146,7 +510,7 @@ var TypedFindCursor = class {
|
|
|
146
510
|
try {
|
|
147
511
|
return this.schema.parse(raw2);
|
|
148
512
|
} catch (err) {
|
|
149
|
-
if (err instanceof
|
|
513
|
+
if (err instanceof z2.ZodError) {
|
|
150
514
|
throw new ZodmonValidationError(this.collectionName, err);
|
|
151
515
|
}
|
|
152
516
|
throw err;
|
|
@@ -156,6 +520,7 @@ var TypedFindCursor = class {
|
|
|
156
520
|
|
|
157
521
|
// src/crud/find.ts
|
|
158
522
|
async function findOne(handle, filter, options) {
|
|
523
|
+
checkUnindexedFields(handle.definition, filter);
|
|
159
524
|
const findOptions = options?.project ? { projection: options.project } : void 0;
|
|
160
525
|
const raw2 = await handle.native.findOne(filter, findOptions);
|
|
161
526
|
if (!raw2) return null;
|
|
@@ -166,7 +531,7 @@ async function findOne(handle, filter, options) {
|
|
|
166
531
|
try {
|
|
167
532
|
return handle.definition.schema.parse(raw2);
|
|
168
533
|
} catch (err) {
|
|
169
|
-
if (err instanceof
|
|
534
|
+
if (err instanceof z3.ZodError) {
|
|
170
535
|
throw new ZodmonValidationError(handle.definition.name, err);
|
|
171
536
|
}
|
|
172
537
|
throw err;
|
|
@@ -180,20 +545,21 @@ async function findOneOrThrow(handle, filter, options) {
|
|
|
180
545
|
return doc;
|
|
181
546
|
}
|
|
182
547
|
function find(handle, filter, options) {
|
|
548
|
+
checkUnindexedFields(handle.definition, filter);
|
|
183
549
|
const raw2 = handle.native.find(filter);
|
|
184
550
|
const cursor = raw2;
|
|
185
551
|
const mode = options?.validate !== void 0 ? options.validate : handle.definition.options.validation;
|
|
186
|
-
return new TypedFindCursor(cursor, handle.definition, mode);
|
|
552
|
+
return new TypedFindCursor(cursor, handle.definition, mode, handle.native, filter);
|
|
187
553
|
}
|
|
188
554
|
|
|
189
555
|
// src/crud/insert.ts
|
|
190
|
-
import { z as
|
|
556
|
+
import { z as z4 } from "zod";
|
|
191
557
|
async function insertOne(handle, doc) {
|
|
192
558
|
let parsed;
|
|
193
559
|
try {
|
|
194
560
|
parsed = handle.definition.schema.parse(doc);
|
|
195
561
|
} catch (err) {
|
|
196
|
-
if (err instanceof
|
|
562
|
+
if (err instanceof z4.ZodError) {
|
|
197
563
|
throw new ZodmonValidationError(handle.definition.name, err);
|
|
198
564
|
}
|
|
199
565
|
throw err;
|
|
@@ -208,7 +574,7 @@ async function insertMany(handle, docs) {
|
|
|
208
574
|
try {
|
|
209
575
|
parsed.push(handle.definition.schema.parse(doc));
|
|
210
576
|
} catch (err) {
|
|
211
|
-
if (err instanceof
|
|
577
|
+
if (err instanceof z4.ZodError) {
|
|
212
578
|
throw new ZodmonValidationError(handle.definition.name, err);
|
|
213
579
|
}
|
|
214
580
|
throw err;
|
|
@@ -218,6 +584,45 @@ async function insertMany(handle, docs) {
|
|
|
218
584
|
return parsed;
|
|
219
585
|
}
|
|
220
586
|
|
|
587
|
+
// src/crud/update.ts
|
|
588
|
+
import { z as z5 } from "zod";
|
|
589
|
+
async function updateOne(handle, filter, update, options) {
|
|
590
|
+
return await handle.native.updateOne(filter, update, options);
|
|
591
|
+
}
|
|
592
|
+
async function updateMany(handle, filter, update, options) {
|
|
593
|
+
return await handle.native.updateMany(filter, update, options);
|
|
594
|
+
}
|
|
595
|
+
async function findOneAndUpdate(handle, filter, update, options) {
|
|
596
|
+
const driverOptions = {
|
|
597
|
+
returnDocument: options?.returnDocument ?? "after",
|
|
598
|
+
includeResultMetadata: false
|
|
599
|
+
};
|
|
600
|
+
if (options?.upsert !== void 0) {
|
|
601
|
+
driverOptions["upsert"] = options.upsert;
|
|
602
|
+
}
|
|
603
|
+
const result = await handle.native.findOneAndUpdate(
|
|
604
|
+
// biome-ignore lint/suspicious/noExplicitAny: TypedFilter intersection type is not directly assignable to MongoDB's Filter
|
|
605
|
+
filter,
|
|
606
|
+
// biome-ignore lint/suspicious/noExplicitAny: TypedUpdateFilter intersection type is not directly assignable to MongoDB's UpdateFilter
|
|
607
|
+
update,
|
|
608
|
+
// biome-ignore lint/suspicious/noExplicitAny: dynamic options object is not assignable to driver's FindOneAndUpdateOptions under exactOptionalPropertyTypes
|
|
609
|
+
driverOptions
|
|
610
|
+
);
|
|
611
|
+
if (!result) return null;
|
|
612
|
+
const mode = options?.validate !== void 0 ? options.validate : handle.definition.options.validation;
|
|
613
|
+
if (mode === false || mode === "passthrough") {
|
|
614
|
+
return result;
|
|
615
|
+
}
|
|
616
|
+
try {
|
|
617
|
+
return handle.definition.schema.parse(result);
|
|
618
|
+
} catch (err) {
|
|
619
|
+
if (err instanceof z5.ZodError) {
|
|
620
|
+
throw new ZodmonValidationError(handle.definition.name, err);
|
|
621
|
+
}
|
|
622
|
+
throw err;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
221
626
|
// src/client/handle.ts
|
|
222
627
|
var CollectionHandle = class {
|
|
223
628
|
/** The collection definition containing schema, name, and index metadata. */
|
|
@@ -339,6 +744,169 @@ var CollectionHandle = class {
|
|
|
339
744
|
find(filter, options) {
|
|
340
745
|
return find(this, filter, options);
|
|
341
746
|
}
|
|
747
|
+
/**
|
|
748
|
+
* Update a single document matching the filter.
|
|
749
|
+
*
|
|
750
|
+
* Applies the update operators to the first document that matches the filter.
|
|
751
|
+
* Does not validate the update against the Zod schema — validation happens
|
|
752
|
+
* at the field-operator level through {@link TypedUpdateFilter}.
|
|
753
|
+
*
|
|
754
|
+
* @param filter - Type-safe filter to match documents.
|
|
755
|
+
* @param update - Type-safe update operators to apply.
|
|
756
|
+
* @param options - Optional settings such as `upsert`.
|
|
757
|
+
* @returns The MongoDB `UpdateResult` with match/modify counts.
|
|
758
|
+
*
|
|
759
|
+
* @example
|
|
760
|
+
* ```ts
|
|
761
|
+
* const users = db.use(Users)
|
|
762
|
+
* const result = await users.updateOne({ name: 'Ada' }, { $set: { role: 'admin' } })
|
|
763
|
+
* console.log(result.modifiedCount) // 1
|
|
764
|
+
* ```
|
|
765
|
+
*/
|
|
766
|
+
async updateOne(filter, update, options) {
|
|
767
|
+
return await updateOne(this, filter, update, options);
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Update all documents matching the filter.
|
|
771
|
+
*
|
|
772
|
+
* Applies the update operators to every document that matches the filter.
|
|
773
|
+
* Does not validate the update against the Zod schema — validation happens
|
|
774
|
+
* at the field-operator level through {@link TypedUpdateFilter}.
|
|
775
|
+
*
|
|
776
|
+
* @param filter - Type-safe filter to match documents.
|
|
777
|
+
* @param update - Type-safe update operators to apply.
|
|
778
|
+
* @param options - Optional settings such as `upsert`.
|
|
779
|
+
* @returns The MongoDB `UpdateResult` with match/modify counts.
|
|
780
|
+
*
|
|
781
|
+
* @example
|
|
782
|
+
* ```ts
|
|
783
|
+
* const users = db.use(Users)
|
|
784
|
+
* const result = await users.updateMany({ role: 'guest' }, { $set: { role: 'user' } })
|
|
785
|
+
* console.log(result.modifiedCount) // number of guests promoted
|
|
786
|
+
* ```
|
|
787
|
+
*/
|
|
788
|
+
async updateMany(filter, update, options) {
|
|
789
|
+
return await updateMany(this, filter, update, options);
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Find a single document matching the filter, apply an update, and return the document.
|
|
793
|
+
*
|
|
794
|
+
* By default, returns the document **after** the update is applied. Set
|
|
795
|
+
* `returnDocument: 'before'` to get the pre-update snapshot. The returned
|
|
796
|
+
* document is validated against the collection's Zod schema using the same
|
|
797
|
+
* resolution logic as {@link findOne}.
|
|
798
|
+
*
|
|
799
|
+
* @param filter - Type-safe filter to match documents.
|
|
800
|
+
* @param update - Type-safe update operators to apply.
|
|
801
|
+
* @param options - Optional settings: `returnDocument`, `upsert`, `validate`.
|
|
802
|
+
* @returns The matched document (before or after update), or `null` if no document matches.
|
|
803
|
+
* @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
|
|
804
|
+
*
|
|
805
|
+
* @example
|
|
806
|
+
* ```ts
|
|
807
|
+
* const users = db.use(Users)
|
|
808
|
+
* const user = await users.findOneAndUpdate(
|
|
809
|
+
* { name: 'Ada' },
|
|
810
|
+
* { $set: { role: 'admin' } },
|
|
811
|
+
* )
|
|
812
|
+
* if (user) console.log(user.role) // 'admin' (returned after update)
|
|
813
|
+
* ```
|
|
814
|
+
*/
|
|
815
|
+
async findOneAndUpdate(filter, update, options) {
|
|
816
|
+
return await findOneAndUpdate(this, filter, update, options);
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* Delete a single document matching the filter.
|
|
820
|
+
*
|
|
821
|
+
* Removes the first document that matches the filter from the collection.
|
|
822
|
+
* No validation is performed — the document is deleted directly through
|
|
823
|
+
* the MongoDB driver.
|
|
824
|
+
*
|
|
825
|
+
* @param filter - Type-safe filter to match documents.
|
|
826
|
+
* @returns The MongoDB `DeleteResult` with the deleted count.
|
|
827
|
+
*
|
|
828
|
+
* @example
|
|
829
|
+
* ```ts
|
|
830
|
+
* const users = db.use(Users)
|
|
831
|
+
* const result = await users.deleteOne({ name: 'Ada' })
|
|
832
|
+
* console.log(result.deletedCount) // 1
|
|
833
|
+
* ```
|
|
834
|
+
*/
|
|
835
|
+
async deleteOne(filter) {
|
|
836
|
+
return await deleteOne(this, filter);
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* Delete all documents matching the filter.
|
|
840
|
+
*
|
|
841
|
+
* Removes every document that matches the filter from the collection.
|
|
842
|
+
* No validation is performed — documents are deleted directly through
|
|
843
|
+
* the MongoDB driver.
|
|
844
|
+
*
|
|
845
|
+
* @param filter - Type-safe filter to match documents.
|
|
846
|
+
* @returns The MongoDB `DeleteResult` with the deleted count.
|
|
847
|
+
*
|
|
848
|
+
* @example
|
|
849
|
+
* ```ts
|
|
850
|
+
* const users = db.use(Users)
|
|
851
|
+
* const result = await users.deleteMany({ role: 'guest' })
|
|
852
|
+
* console.log(result.deletedCount) // number of guests removed
|
|
853
|
+
* ```
|
|
854
|
+
*/
|
|
855
|
+
async deleteMany(filter) {
|
|
856
|
+
return await deleteMany(this, filter);
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* Find a single document matching the filter, delete it, and return the document.
|
|
860
|
+
*
|
|
861
|
+
* Returns the deleted document, or `null` if no document matches the filter.
|
|
862
|
+
* The returned document is validated against the collection's Zod schema
|
|
863
|
+
* using the same resolution logic as {@link findOne}.
|
|
864
|
+
*
|
|
865
|
+
* @param filter - Type-safe filter to match documents.
|
|
866
|
+
* @param options - Optional settings: `validate`.
|
|
867
|
+
* @returns The deleted document, or `null` if no document matches.
|
|
868
|
+
* @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
|
|
869
|
+
*
|
|
870
|
+
* @example
|
|
871
|
+
* ```ts
|
|
872
|
+
* const users = db.use(Users)
|
|
873
|
+
* const user = await users.findOneAndDelete({ name: 'Ada' })
|
|
874
|
+
* if (user) console.log(user.name) // 'Ada' (the deleted document)
|
|
875
|
+
* ```
|
|
876
|
+
*/
|
|
877
|
+
async findOneAndDelete(filter, options) {
|
|
878
|
+
return await findOneAndDelete(this, filter, options);
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Synchronize the indexes declared in this collection's schema with MongoDB.
|
|
882
|
+
*
|
|
883
|
+
* Compares the desired indexes (from field-level `.index()` / `.unique()` /
|
|
884
|
+
* `.text()` / `.expireAfter()` and compound `indexes` in collection options)
|
|
885
|
+
* with the indexes that currently exist in MongoDB, then creates, drops, or
|
|
886
|
+
* reports differences depending on the options.
|
|
887
|
+
*
|
|
888
|
+
* @param options - Optional sync behavior (dryRun, dropOrphaned).
|
|
889
|
+
* @returns A summary of created, dropped, skipped, and stale indexes.
|
|
890
|
+
*
|
|
891
|
+
* @example
|
|
892
|
+
* ```ts
|
|
893
|
+
* const users = db.use(Users)
|
|
894
|
+
* const result = await users.syncIndexes()
|
|
895
|
+
* console.log('Created:', result.created)
|
|
896
|
+
* console.log('Stale:', result.stale.map(s => s.name))
|
|
897
|
+
* ```
|
|
898
|
+
*
|
|
899
|
+
* @example
|
|
900
|
+
* ```ts
|
|
901
|
+
* // Dry run to preview changes without modifying the database
|
|
902
|
+
* const diff = await users.syncIndexes({ dryRun: true })
|
|
903
|
+
* console.log('Would create:', diff.created)
|
|
904
|
+
* console.log('Would drop:', diff.dropped)
|
|
905
|
+
* ```
|
|
906
|
+
*/
|
|
907
|
+
async syncIndexes(options) {
|
|
908
|
+
return await syncIndexes(this, options);
|
|
909
|
+
}
|
|
342
910
|
};
|
|
343
911
|
|
|
344
912
|
// src/client/client.ts
|
|
@@ -364,19 +932,42 @@ var Database = class {
|
|
|
364
932
|
*/
|
|
365
933
|
use(def) {
|
|
366
934
|
this._collections.set(def.name, def);
|
|
367
|
-
const native = this._db.collection(
|
|
935
|
+
const native = this._db.collection(
|
|
936
|
+
def.name
|
|
937
|
+
);
|
|
368
938
|
return new CollectionHandle(
|
|
369
939
|
def,
|
|
370
940
|
native
|
|
371
941
|
);
|
|
372
942
|
}
|
|
373
943
|
/**
|
|
374
|
-
* Synchronize indexes
|
|
944
|
+
* Synchronize indexes for all registered collections with MongoDB.
|
|
945
|
+
*
|
|
946
|
+
* Iterates every collection registered via {@link use} and calls
|
|
947
|
+
* {@link syncIndexes} on each one. Returns a record keyed by collection
|
|
948
|
+
* name with the sync result for each.
|
|
949
|
+
*
|
|
950
|
+
* @param options - Optional sync behavior (dryRun, dropOrphaned).
|
|
951
|
+
* @returns A record mapping collection names to their sync results.
|
|
375
952
|
*
|
|
376
|
-
*
|
|
953
|
+
* @example
|
|
954
|
+
* ```ts
|
|
955
|
+
* const db = createClient('mongodb://localhost:27017', 'myapp')
|
|
956
|
+
* db.use(Users)
|
|
957
|
+
* db.use(Posts)
|
|
958
|
+
* const results = await db.syncIndexes()
|
|
959
|
+
* console.log(results['users'].created) // ['email_1']
|
|
960
|
+
* console.log(results['posts'].created) // ['title_1']
|
|
961
|
+
* ```
|
|
377
962
|
*/
|
|
378
|
-
syncIndexes() {
|
|
379
|
-
|
|
963
|
+
async syncIndexes(options) {
|
|
964
|
+
const results = {};
|
|
965
|
+
for (const [name, def] of this._collections) {
|
|
966
|
+
const native = this._db.collection(name);
|
|
967
|
+
const handle = new CollectionHandle(def, native);
|
|
968
|
+
results[name] = await syncIndexes(handle, options);
|
|
969
|
+
}
|
|
970
|
+
return results;
|
|
380
971
|
}
|
|
381
972
|
/**
|
|
382
973
|
* Execute a function within a MongoDB transaction with auto-commit/rollback.
|
|
@@ -416,14 +1007,14 @@ function createClient(uri, dbNameOrOptions, maybeOptions) {
|
|
|
416
1007
|
}
|
|
417
1008
|
|
|
418
1009
|
// src/collection/collection.ts
|
|
419
|
-
import { ObjectId as
|
|
420
|
-
import { z as
|
|
1010
|
+
import { ObjectId as ObjectId3 } from "mongodb";
|
|
1011
|
+
import { z as z9 } from "zod";
|
|
421
1012
|
|
|
422
1013
|
// src/schema/extensions.ts
|
|
423
|
-
import { z as
|
|
1014
|
+
import { z as z7 } from "zod";
|
|
424
1015
|
|
|
425
1016
|
// src/schema/ref.ts
|
|
426
|
-
import { z as
|
|
1017
|
+
import { z as z6 } from "zod";
|
|
427
1018
|
var refMetadata = /* @__PURE__ */ new WeakMap();
|
|
428
1019
|
function getRefMetadata(schema) {
|
|
429
1020
|
if (typeof schema !== "object" || schema === null) return void 0;
|
|
@@ -431,7 +1022,7 @@ function getRefMetadata(schema) {
|
|
|
431
1022
|
}
|
|
432
1023
|
var REF_GUARD = /* @__PURE__ */ Symbol.for("zodmon_ref");
|
|
433
1024
|
function installRefExtension() {
|
|
434
|
-
const proto =
|
|
1025
|
+
const proto = z6.ZodType.prototype;
|
|
435
1026
|
if (REF_GUARD in proto) return;
|
|
436
1027
|
Object.defineProperty(proto, "ref", {
|
|
437
1028
|
value(collection2) {
|
|
@@ -458,7 +1049,7 @@ function getIndexMetadata(schema) {
|
|
|
458
1049
|
}
|
|
459
1050
|
var GUARD = /* @__PURE__ */ Symbol.for("zodmon_extensions");
|
|
460
1051
|
function installExtensions() {
|
|
461
|
-
const proto =
|
|
1052
|
+
const proto = z7.ZodType.prototype;
|
|
462
1053
|
if (GUARD in proto) return;
|
|
463
1054
|
Object.defineProperty(proto, "index", {
|
|
464
1055
|
/**
|
|
@@ -556,14 +1147,14 @@ function installExtensions() {
|
|
|
556
1147
|
installExtensions();
|
|
557
1148
|
|
|
558
1149
|
// src/schema/object-id.ts
|
|
559
|
-
import { ObjectId } from "mongodb";
|
|
560
|
-
import { z as
|
|
1150
|
+
import { ObjectId as ObjectId2 } from "mongodb";
|
|
1151
|
+
import { z as z8 } from "zod";
|
|
561
1152
|
var OBJECT_ID_HEX = /^[a-f\d]{24}$/i;
|
|
562
1153
|
function objectId() {
|
|
563
|
-
return
|
|
564
|
-
if (val instanceof
|
|
1154
|
+
return z8.custom((val) => {
|
|
1155
|
+
if (val instanceof ObjectId2) return true;
|
|
565
1156
|
return typeof val === "string" && OBJECT_ID_HEX.test(val);
|
|
566
|
-
}, "Invalid ObjectId").transform((val) => val instanceof
|
|
1157
|
+
}, "Invalid ObjectId").transform((val) => val instanceof ObjectId2 ? val : ObjectId2.createFromHexString(val));
|
|
567
1158
|
}
|
|
568
1159
|
|
|
569
1160
|
// src/collection/collection.ts
|
|
@@ -578,8 +1169,8 @@ function extractFieldIndexes(shape) {
|
|
|
578
1169
|
return result;
|
|
579
1170
|
}
|
|
580
1171
|
function collection(name, shape, options) {
|
|
581
|
-
const resolvedShape = "_id" in shape ? shape : { _id: objectId().default(() => new
|
|
582
|
-
const schema =
|
|
1172
|
+
const resolvedShape = "_id" in shape ? shape : { _id: objectId().default(() => new ObjectId3()), ...shape };
|
|
1173
|
+
const schema = z9.object(resolvedShape);
|
|
583
1174
|
const fieldIndexes = extractFieldIndexes(shape);
|
|
584
1175
|
const { indexes: compoundIndexes, validation, ...rest } = options ?? {};
|
|
585
1176
|
return {
|
|
@@ -591,6 +1182,8 @@ function collection(name, shape, options) {
|
|
|
591
1182
|
schema,
|
|
592
1183
|
shape,
|
|
593
1184
|
fieldIndexes,
|
|
1185
|
+
// Safe cast: compoundIndexes is TIndexes at runtime (or an empty array when
|
|
1186
|
+
// no options provided). The spread into [...TIndexes] preserves the tuple type.
|
|
594
1187
|
compoundIndexes: compoundIndexes ?? [],
|
|
595
1188
|
options: {
|
|
596
1189
|
validation: validation ?? "strict",
|
|
@@ -615,12 +1208,29 @@ var IndexBuilder = class _IndexBuilder {
|
|
|
615
1208
|
options
|
|
616
1209
|
});
|
|
617
1210
|
}
|
|
1211
|
+
// Safe cast: _clone returns IndexBuilder<TKeys> but `this` may carry an
|
|
1212
|
+
// intersection from .name(). The cast is safe because _clone preserves all fields.
|
|
618
1213
|
unique() {
|
|
619
1214
|
return this._clone({ ...this.options, unique: true });
|
|
620
1215
|
}
|
|
1216
|
+
// Safe cast: same reasoning as unique().
|
|
621
1217
|
sparse() {
|
|
622
1218
|
return this._clone({ ...this.options, sparse: true });
|
|
623
1219
|
}
|
|
1220
|
+
/**
|
|
1221
|
+
* Set a custom name for this index, preserving the literal type.
|
|
1222
|
+
*
|
|
1223
|
+
* The returned builder carries the literal name type via an intersection,
|
|
1224
|
+
* enabling type-safe `.hint()` on cursors that only accepts declared names.
|
|
1225
|
+
*
|
|
1226
|
+
* @param name - The index name.
|
|
1227
|
+
* @returns A new IndexBuilder with the name recorded at the type level.
|
|
1228
|
+
*
|
|
1229
|
+
* @example
|
|
1230
|
+
* ```ts
|
|
1231
|
+
* index({ email: 1, role: -1 }).name('email_role_idx')
|
|
1232
|
+
* ```
|
|
1233
|
+
*/
|
|
624
1234
|
name(name) {
|
|
625
1235
|
return this._clone({ ...this.options, name });
|
|
626
1236
|
}
|
|
@@ -630,14 +1240,14 @@ function index(fields) {
|
|
|
630
1240
|
}
|
|
631
1241
|
|
|
632
1242
|
// src/helpers/oid.ts
|
|
633
|
-
import { ObjectId as
|
|
1243
|
+
import { ObjectId as ObjectId4 } from "mongodb";
|
|
634
1244
|
function oid(value) {
|
|
635
|
-
if (value === void 0) return new
|
|
636
|
-
if (value instanceof
|
|
637
|
-
return
|
|
1245
|
+
if (value === void 0) return new ObjectId4();
|
|
1246
|
+
if (value instanceof ObjectId4) return value;
|
|
1247
|
+
return ObjectId4.createFromHexString(value);
|
|
638
1248
|
}
|
|
639
1249
|
function isOid(value) {
|
|
640
|
-
return value instanceof
|
|
1250
|
+
return value instanceof ObjectId4;
|
|
641
1251
|
}
|
|
642
1252
|
|
|
643
1253
|
// src/query/operators.ts
|
|
@@ -660,7 +1270,27 @@ var $or = (...filters) => ({ $or: filters });
|
|
|
660
1270
|
var $and = (...filters) => ({ $and: filters });
|
|
661
1271
|
var $nor = (...filters) => ({ $nor: filters });
|
|
662
1272
|
var raw = (filter) => filter;
|
|
1273
|
+
|
|
1274
|
+
// src/query/namespace.ts
|
|
1275
|
+
var $ = {
|
|
1276
|
+
eq: $eq,
|
|
1277
|
+
ne: $ne,
|
|
1278
|
+
gt: $gt,
|
|
1279
|
+
gte: $gte,
|
|
1280
|
+
lt: $lt,
|
|
1281
|
+
lte: $lte,
|
|
1282
|
+
in: $in,
|
|
1283
|
+
nin: $nin,
|
|
1284
|
+
exists: $exists,
|
|
1285
|
+
regex: $regex,
|
|
1286
|
+
not: $not,
|
|
1287
|
+
or: $or,
|
|
1288
|
+
and: $and,
|
|
1289
|
+
nor: $nor,
|
|
1290
|
+
raw
|
|
1291
|
+
};
|
|
663
1292
|
export {
|
|
1293
|
+
$,
|
|
664
1294
|
$and,
|
|
665
1295
|
$eq,
|
|
666
1296
|
$exists,
|
|
@@ -681,23 +1311,34 @@ export {
|
|
|
681
1311
|
TypedFindCursor,
|
|
682
1312
|
ZodmonNotFoundError,
|
|
683
1313
|
ZodmonValidationError,
|
|
1314
|
+
checkUnindexedFields,
|
|
684
1315
|
collection,
|
|
685
1316
|
createClient,
|
|
1317
|
+
deleteMany,
|
|
1318
|
+
deleteOne,
|
|
1319
|
+
extractComparableOptions,
|
|
686
1320
|
extractDbName,
|
|
687
1321
|
extractFieldIndexes,
|
|
688
1322
|
find,
|
|
689
1323
|
findOne,
|
|
1324
|
+
findOneAndDelete,
|
|
1325
|
+
findOneAndUpdate,
|
|
690
1326
|
findOneOrThrow,
|
|
1327
|
+
generateIndexName,
|
|
691
1328
|
getIndexMetadata,
|
|
692
1329
|
getRefMetadata,
|
|
693
1330
|
index,
|
|
694
1331
|
insertMany,
|
|
695
1332
|
insertOne,
|
|
696
|
-
installExtensions,
|
|
697
|
-
installRefExtension,
|
|
698
1333
|
isOid,
|
|
699
1334
|
objectId,
|
|
700
1335
|
oid,
|
|
701
|
-
raw
|
|
1336
|
+
raw,
|
|
1337
|
+
serializeIndexKey,
|
|
1338
|
+
syncIndexes,
|
|
1339
|
+
toCompoundIndexSpec,
|
|
1340
|
+
toFieldIndexSpec,
|
|
1341
|
+
updateMany,
|
|
1342
|
+
updateOne
|
|
702
1343
|
};
|
|
703
1344
|
//# sourceMappingURL=index.js.map
|