@zodmon/core 0.6.0 → 0.7.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 +404 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +963 -456
- package/dist/index.d.ts +963 -456
- package/dist/index.js +394 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,19 +1,8 @@
|
|
|
1
1
|
// src/client/client.ts
|
|
2
2
|
import { MongoClient } from "mongodb";
|
|
3
3
|
|
|
4
|
-
// src/crud/
|
|
5
|
-
import { z
|
|
6
|
-
|
|
7
|
-
// src/errors/not-found.ts
|
|
8
|
-
var ZodmonNotFoundError = class extends Error {
|
|
9
|
-
name = "ZodmonNotFoundError";
|
|
10
|
-
/** The MongoDB collection name where the query found no results. */
|
|
11
|
-
collection;
|
|
12
|
-
constructor(collection2) {
|
|
13
|
-
super(`Document not found in "${collection2}"`);
|
|
14
|
-
this.collection = collection2;
|
|
15
|
-
}
|
|
16
|
-
};
|
|
4
|
+
// src/crud/delete.ts
|
|
5
|
+
import { z } from "zod";
|
|
17
6
|
|
|
18
7
|
// src/errors/validation.ts
|
|
19
8
|
var ZodmonValidationError = class extends Error {
|
|
@@ -33,8 +22,113 @@ var ZodmonValidationError = class extends Error {
|
|
|
33
22
|
}
|
|
34
23
|
};
|
|
35
24
|
|
|
25
|
+
// src/crud/delete.ts
|
|
26
|
+
async function deleteOne(handle, filter) {
|
|
27
|
+
return await handle.native.deleteOne(filter);
|
|
28
|
+
}
|
|
29
|
+
async function deleteMany(handle, filter) {
|
|
30
|
+
return await handle.native.deleteMany(filter);
|
|
31
|
+
}
|
|
32
|
+
async function findOneAndDelete(handle, filter, options) {
|
|
33
|
+
const result = await handle.native.findOneAndDelete(
|
|
34
|
+
// biome-ignore lint/suspicious/noExplicitAny: TypedFilter intersection type is not directly assignable to MongoDB's Filter
|
|
35
|
+
filter,
|
|
36
|
+
{ includeResultMetadata: false }
|
|
37
|
+
);
|
|
38
|
+
if (!result) return null;
|
|
39
|
+
const mode = options?.validate !== void 0 ? options.validate : handle.definition.options.validation;
|
|
40
|
+
if (mode === false || mode === "passthrough") {
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
return handle.definition.schema.parse(result);
|
|
45
|
+
} catch (err) {
|
|
46
|
+
if (err instanceof z.ZodError) {
|
|
47
|
+
throw new ZodmonValidationError(handle.definition.name, err);
|
|
48
|
+
}
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/crud/find.ts
|
|
54
|
+
import { z as z3 } from "zod";
|
|
55
|
+
|
|
56
|
+
// src/errors/not-found.ts
|
|
57
|
+
var ZodmonNotFoundError = class extends Error {
|
|
58
|
+
name = "ZodmonNotFoundError";
|
|
59
|
+
/** The MongoDB collection name where the query found no results. */
|
|
60
|
+
collection;
|
|
61
|
+
constructor(collection2) {
|
|
62
|
+
super(`Document not found in "${collection2}"`);
|
|
63
|
+
this.collection = collection2;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// src/query/cursor.ts
|
|
68
|
+
import { z as z2 } from "zod";
|
|
69
|
+
|
|
70
|
+
// src/crud/paginate.ts
|
|
71
|
+
import { ObjectId } from "mongodb";
|
|
72
|
+
function serializeValue(value) {
|
|
73
|
+
if (value instanceof ObjectId) return { $oid: value.toHexString() };
|
|
74
|
+
if (value instanceof Date) return { $date: value.getTime() };
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
function deserializeValue(value) {
|
|
78
|
+
if (value != null && typeof value === "object") {
|
|
79
|
+
if ("$oid" in value) return new ObjectId(value.$oid);
|
|
80
|
+
if ("$date" in value) return new Date(value.$date);
|
|
81
|
+
}
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
function encodeCursor(doc, sortKeys, direction) {
|
|
85
|
+
const values = sortKeys.map(([field]) => serializeValue(doc[field]));
|
|
86
|
+
return btoa(JSON.stringify([direction, ...values]));
|
|
87
|
+
}
|
|
88
|
+
function decodeCursor(cursor) {
|
|
89
|
+
let parsed;
|
|
90
|
+
try {
|
|
91
|
+
parsed = JSON.parse(atob(cursor));
|
|
92
|
+
} catch {
|
|
93
|
+
throw new Error("Invalid cursor: malformed encoding");
|
|
94
|
+
}
|
|
95
|
+
if (!Array.isArray(parsed) || parsed.length < 1) {
|
|
96
|
+
throw new Error("Invalid cursor: expected non-empty array");
|
|
97
|
+
}
|
|
98
|
+
const [direction, ...rawValues] = parsed;
|
|
99
|
+
if (direction !== "f" && direction !== "b") {
|
|
100
|
+
throw new Error("Invalid cursor: unknown direction flag");
|
|
101
|
+
}
|
|
102
|
+
return { direction, values: rawValues.map(deserializeValue) };
|
|
103
|
+
}
|
|
104
|
+
function buildCursorFilter(sortKeys, values, isBackward) {
|
|
105
|
+
const clauses = [];
|
|
106
|
+
for (let i = 0; i < sortKeys.length; i++) {
|
|
107
|
+
const clause = {};
|
|
108
|
+
for (let j = 0; j < i; j++) {
|
|
109
|
+
clause[sortKeys[j][0]] = values[j];
|
|
110
|
+
}
|
|
111
|
+
const [field, direction] = sortKeys[i];
|
|
112
|
+
const isAsc = direction === 1;
|
|
113
|
+
const op = isAsc !== isBackward ? "$gt" : "$lt";
|
|
114
|
+
if (values[i] === null) {
|
|
115
|
+
clause[field] = { $ne: null };
|
|
116
|
+
} else {
|
|
117
|
+
clause[field] = { [op]: values[i] };
|
|
118
|
+
}
|
|
119
|
+
clauses.push(clause);
|
|
120
|
+
}
|
|
121
|
+
return { $or: clauses };
|
|
122
|
+
}
|
|
123
|
+
function resolveSortKeys(sortSpec) {
|
|
124
|
+
const entries = sortSpec ? Object.entries(sortSpec) : [];
|
|
125
|
+
if (!entries.some(([field]) => field === "_id")) {
|
|
126
|
+
entries.push(["_id", 1]);
|
|
127
|
+
}
|
|
128
|
+
return entries;
|
|
129
|
+
}
|
|
130
|
+
|
|
36
131
|
// src/query/cursor.ts
|
|
37
|
-
import { z } from "zod";
|
|
38
132
|
var TypedFindCursor = class {
|
|
39
133
|
/** @internal */
|
|
40
134
|
cursor;
|
|
@@ -45,11 +139,21 @@ var TypedFindCursor = class {
|
|
|
45
139
|
/** @internal */
|
|
46
140
|
mode;
|
|
47
141
|
/** @internal */
|
|
48
|
-
|
|
142
|
+
nativeCollection;
|
|
143
|
+
/** @internal */
|
|
144
|
+
// biome-ignore lint/suspicious/noExplicitAny: TypedFilter is not assignable to MongoDB's Filter; stored opaquely for paginate
|
|
145
|
+
filter;
|
|
146
|
+
/** @internal */
|
|
147
|
+
sortSpec;
|
|
148
|
+
/** @internal */
|
|
149
|
+
constructor(cursor, definition, mode, nativeCollection, filter) {
|
|
49
150
|
this.cursor = cursor;
|
|
50
151
|
this.schema = definition.schema;
|
|
51
152
|
this.collectionName = definition.name;
|
|
52
153
|
this.mode = mode;
|
|
154
|
+
this.nativeCollection = nativeCollection;
|
|
155
|
+
this.filter = filter;
|
|
156
|
+
this.sortSpec = null;
|
|
53
157
|
}
|
|
54
158
|
/**
|
|
55
159
|
* Set the sort order for the query.
|
|
@@ -66,6 +170,7 @@ var TypedFindCursor = class {
|
|
|
66
170
|
* ```
|
|
67
171
|
*/
|
|
68
172
|
sort(spec) {
|
|
173
|
+
this.sortSpec = spec;
|
|
69
174
|
this.cursor.sort(spec);
|
|
70
175
|
return this;
|
|
71
176
|
}
|
|
@@ -99,6 +204,57 @@ var TypedFindCursor = class {
|
|
|
99
204
|
this.cursor.limit(n);
|
|
100
205
|
return this;
|
|
101
206
|
}
|
|
207
|
+
async paginate(opts) {
|
|
208
|
+
const sortRecord = this.sortSpec ? this.sortSpec : null;
|
|
209
|
+
const sortKeys = resolveSortKeys(sortRecord);
|
|
210
|
+
const sort = Object.fromEntries(sortKeys);
|
|
211
|
+
if ("page" in opts) {
|
|
212
|
+
return await this.offsetPaginate(sortKeys, sort, opts);
|
|
213
|
+
}
|
|
214
|
+
return await this.cursorPaginate(sortKeys, sort, opts);
|
|
215
|
+
}
|
|
216
|
+
/** @internal Offset pagination implementation. */
|
|
217
|
+
async offsetPaginate(_sortKeys, sort, opts) {
|
|
218
|
+
const [total, raw2] = await Promise.all([
|
|
219
|
+
this.nativeCollection.countDocuments(this.filter),
|
|
220
|
+
this.nativeCollection.find(this.filter).sort(sort).skip((opts.page - 1) * opts.perPage).limit(opts.perPage).toArray()
|
|
221
|
+
]);
|
|
222
|
+
const docs = raw2.map((doc) => this.validateDoc(doc));
|
|
223
|
+
const totalPages = Math.ceil(total / opts.perPage);
|
|
224
|
+
return {
|
|
225
|
+
docs,
|
|
226
|
+
total,
|
|
227
|
+
page: opts.page,
|
|
228
|
+
perPage: opts.perPage,
|
|
229
|
+
totalPages,
|
|
230
|
+
hasNext: opts.page < totalPages,
|
|
231
|
+
hasPrev: opts.page > 1
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
/** @internal Cursor pagination implementation. */
|
|
235
|
+
async cursorPaginate(sortKeys, sort, opts) {
|
|
236
|
+
let isBackward = false;
|
|
237
|
+
let combinedFilter = this.filter;
|
|
238
|
+
if (opts.cursor) {
|
|
239
|
+
const decoded = decodeCursor(opts.cursor);
|
|
240
|
+
isBackward = decoded.direction === "b";
|
|
241
|
+
const cursorFilter = buildCursorFilter(sortKeys, decoded.values, isBackward);
|
|
242
|
+
combinedFilter = this.filter && Object.keys(this.filter).length > 0 ? { $and: [this.filter, cursorFilter] } : cursorFilter;
|
|
243
|
+
}
|
|
244
|
+
const effectiveSort = isBackward ? Object.fromEntries(sortKeys.map(([f, d]) => [f, d === 1 ? -1 : 1])) : sort;
|
|
245
|
+
const raw2 = await this.nativeCollection.find(combinedFilter).sort(effectiveSort).limit(opts.limit + 1).toArray();
|
|
246
|
+
const hasMore = raw2.length > opts.limit;
|
|
247
|
+
if (hasMore) raw2.pop();
|
|
248
|
+
if (isBackward) raw2.reverse();
|
|
249
|
+
const docs = raw2.map((doc) => this.validateDoc(doc));
|
|
250
|
+
return {
|
|
251
|
+
docs,
|
|
252
|
+
hasNext: isBackward ? true : hasMore,
|
|
253
|
+
hasPrev: isBackward ? hasMore : opts.cursor != null,
|
|
254
|
+
startCursor: docs.length > 0 ? encodeCursor(docs[0], sortKeys, "b") : null,
|
|
255
|
+
endCursor: docs.length > 0 ? encodeCursor(docs[docs.length - 1], sortKeys, "f") : null
|
|
256
|
+
};
|
|
257
|
+
}
|
|
102
258
|
/**
|
|
103
259
|
* Execute the query and return all matching documents as an array.
|
|
104
260
|
*
|
|
@@ -146,7 +302,7 @@ var TypedFindCursor = class {
|
|
|
146
302
|
try {
|
|
147
303
|
return this.schema.parse(raw2);
|
|
148
304
|
} catch (err) {
|
|
149
|
-
if (err instanceof
|
|
305
|
+
if (err instanceof z2.ZodError) {
|
|
150
306
|
throw new ZodmonValidationError(this.collectionName, err);
|
|
151
307
|
}
|
|
152
308
|
throw err;
|
|
@@ -166,7 +322,7 @@ async function findOne(handle, filter, options) {
|
|
|
166
322
|
try {
|
|
167
323
|
return handle.definition.schema.parse(raw2);
|
|
168
324
|
} catch (err) {
|
|
169
|
-
if (err instanceof
|
|
325
|
+
if (err instanceof z3.ZodError) {
|
|
170
326
|
throw new ZodmonValidationError(handle.definition.name, err);
|
|
171
327
|
}
|
|
172
328
|
throw err;
|
|
@@ -183,17 +339,17 @@ function find(handle, filter, options) {
|
|
|
183
339
|
const raw2 = handle.native.find(filter);
|
|
184
340
|
const cursor = raw2;
|
|
185
341
|
const mode = options?.validate !== void 0 ? options.validate : handle.definition.options.validation;
|
|
186
|
-
return new TypedFindCursor(cursor, handle.definition, mode);
|
|
342
|
+
return new TypedFindCursor(cursor, handle.definition, mode, handle.native, filter);
|
|
187
343
|
}
|
|
188
344
|
|
|
189
345
|
// src/crud/insert.ts
|
|
190
|
-
import { z as
|
|
346
|
+
import { z as z4 } from "zod";
|
|
191
347
|
async function insertOne(handle, doc) {
|
|
192
348
|
let parsed;
|
|
193
349
|
try {
|
|
194
350
|
parsed = handle.definition.schema.parse(doc);
|
|
195
351
|
} catch (err) {
|
|
196
|
-
if (err instanceof
|
|
352
|
+
if (err instanceof z4.ZodError) {
|
|
197
353
|
throw new ZodmonValidationError(handle.definition.name, err);
|
|
198
354
|
}
|
|
199
355
|
throw err;
|
|
@@ -208,7 +364,7 @@ async function insertMany(handle, docs) {
|
|
|
208
364
|
try {
|
|
209
365
|
parsed.push(handle.definition.schema.parse(doc));
|
|
210
366
|
} catch (err) {
|
|
211
|
-
if (err instanceof
|
|
367
|
+
if (err instanceof z4.ZodError) {
|
|
212
368
|
throw new ZodmonValidationError(handle.definition.name, err);
|
|
213
369
|
}
|
|
214
370
|
throw err;
|
|
@@ -218,6 +374,45 @@ async function insertMany(handle, docs) {
|
|
|
218
374
|
return parsed;
|
|
219
375
|
}
|
|
220
376
|
|
|
377
|
+
// src/crud/update.ts
|
|
378
|
+
import { z as z5 } from "zod";
|
|
379
|
+
async function updateOne(handle, filter, update, options) {
|
|
380
|
+
return await handle.native.updateOne(filter, update, options);
|
|
381
|
+
}
|
|
382
|
+
async function updateMany(handle, filter, update, options) {
|
|
383
|
+
return await handle.native.updateMany(filter, update, options);
|
|
384
|
+
}
|
|
385
|
+
async function findOneAndUpdate(handle, filter, update, options) {
|
|
386
|
+
const driverOptions = {
|
|
387
|
+
returnDocument: options?.returnDocument ?? "after",
|
|
388
|
+
includeResultMetadata: false
|
|
389
|
+
};
|
|
390
|
+
if (options?.upsert !== void 0) {
|
|
391
|
+
driverOptions["upsert"] = options.upsert;
|
|
392
|
+
}
|
|
393
|
+
const result = await handle.native.findOneAndUpdate(
|
|
394
|
+
// biome-ignore lint/suspicious/noExplicitAny: TypedFilter intersection type is not directly assignable to MongoDB's Filter
|
|
395
|
+
filter,
|
|
396
|
+
// biome-ignore lint/suspicious/noExplicitAny: TypedUpdateFilter intersection type is not directly assignable to MongoDB's UpdateFilter
|
|
397
|
+
update,
|
|
398
|
+
// biome-ignore lint/suspicious/noExplicitAny: dynamic options object is not assignable to driver's FindOneAndUpdateOptions under exactOptionalPropertyTypes
|
|
399
|
+
driverOptions
|
|
400
|
+
);
|
|
401
|
+
if (!result) return null;
|
|
402
|
+
const mode = options?.validate !== void 0 ? options.validate : handle.definition.options.validation;
|
|
403
|
+
if (mode === false || mode === "passthrough") {
|
|
404
|
+
return result;
|
|
405
|
+
}
|
|
406
|
+
try {
|
|
407
|
+
return handle.definition.schema.parse(result);
|
|
408
|
+
} catch (err) {
|
|
409
|
+
if (err instanceof z5.ZodError) {
|
|
410
|
+
throw new ZodmonValidationError(handle.definition.name, err);
|
|
411
|
+
}
|
|
412
|
+
throw err;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
221
416
|
// src/client/handle.ts
|
|
222
417
|
var CollectionHandle = class {
|
|
223
418
|
/** The collection definition containing schema, name, and index metadata. */
|
|
@@ -339,6 +534,139 @@ var CollectionHandle = class {
|
|
|
339
534
|
find(filter, options) {
|
|
340
535
|
return find(this, filter, options);
|
|
341
536
|
}
|
|
537
|
+
/**
|
|
538
|
+
* Update a single document matching the filter.
|
|
539
|
+
*
|
|
540
|
+
* Applies the update operators to the first document that matches the filter.
|
|
541
|
+
* Does not validate the update against the Zod schema — validation happens
|
|
542
|
+
* at the field-operator level through {@link TypedUpdateFilter}.
|
|
543
|
+
*
|
|
544
|
+
* @param filter - Type-safe filter to match documents.
|
|
545
|
+
* @param update - Type-safe update operators to apply.
|
|
546
|
+
* @param options - Optional settings such as `upsert`.
|
|
547
|
+
* @returns The MongoDB `UpdateResult` with match/modify counts.
|
|
548
|
+
*
|
|
549
|
+
* @example
|
|
550
|
+
* ```ts
|
|
551
|
+
* const users = db.use(Users)
|
|
552
|
+
* const result = await users.updateOne({ name: 'Ada' }, { $set: { role: 'admin' } })
|
|
553
|
+
* console.log(result.modifiedCount) // 1
|
|
554
|
+
* ```
|
|
555
|
+
*/
|
|
556
|
+
async updateOne(filter, update, options) {
|
|
557
|
+
return await updateOne(this, filter, update, options);
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Update all documents matching the filter.
|
|
561
|
+
*
|
|
562
|
+
* Applies the update operators to every document that matches the filter.
|
|
563
|
+
* Does not validate the update against the Zod schema — validation happens
|
|
564
|
+
* at the field-operator level through {@link TypedUpdateFilter}.
|
|
565
|
+
*
|
|
566
|
+
* @param filter - Type-safe filter to match documents.
|
|
567
|
+
* @param update - Type-safe update operators to apply.
|
|
568
|
+
* @param options - Optional settings such as `upsert`.
|
|
569
|
+
* @returns The MongoDB `UpdateResult` with match/modify counts.
|
|
570
|
+
*
|
|
571
|
+
* @example
|
|
572
|
+
* ```ts
|
|
573
|
+
* const users = db.use(Users)
|
|
574
|
+
* const result = await users.updateMany({ role: 'guest' }, { $set: { role: 'user' } })
|
|
575
|
+
* console.log(result.modifiedCount) // number of guests promoted
|
|
576
|
+
* ```
|
|
577
|
+
*/
|
|
578
|
+
async updateMany(filter, update, options) {
|
|
579
|
+
return await updateMany(this, filter, update, options);
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Find a single document matching the filter, apply an update, and return the document.
|
|
583
|
+
*
|
|
584
|
+
* By default, returns the document **after** the update is applied. Set
|
|
585
|
+
* `returnDocument: 'before'` to get the pre-update snapshot. The returned
|
|
586
|
+
* document is validated against the collection's Zod schema using the same
|
|
587
|
+
* resolution logic as {@link findOne}.
|
|
588
|
+
*
|
|
589
|
+
* @param filter - Type-safe filter to match documents.
|
|
590
|
+
* @param update - Type-safe update operators to apply.
|
|
591
|
+
* @param options - Optional settings: `returnDocument`, `upsert`, `validate`.
|
|
592
|
+
* @returns The matched document (before or after update), or `null` if no document matches.
|
|
593
|
+
* @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
|
|
594
|
+
*
|
|
595
|
+
* @example
|
|
596
|
+
* ```ts
|
|
597
|
+
* const users = db.use(Users)
|
|
598
|
+
* const user = await users.findOneAndUpdate(
|
|
599
|
+
* { name: 'Ada' },
|
|
600
|
+
* { $set: { role: 'admin' } },
|
|
601
|
+
* )
|
|
602
|
+
* if (user) console.log(user.role) // 'admin' (returned after update)
|
|
603
|
+
* ```
|
|
604
|
+
*/
|
|
605
|
+
async findOneAndUpdate(filter, update, options) {
|
|
606
|
+
return await findOneAndUpdate(this, filter, update, options);
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Delete a single document matching the filter.
|
|
610
|
+
*
|
|
611
|
+
* Removes the first document that matches the filter from the collection.
|
|
612
|
+
* No validation is performed — the document is deleted directly through
|
|
613
|
+
* the MongoDB driver.
|
|
614
|
+
*
|
|
615
|
+
* @param filter - Type-safe filter to match documents.
|
|
616
|
+
* @returns The MongoDB `DeleteResult` with the deleted count.
|
|
617
|
+
*
|
|
618
|
+
* @example
|
|
619
|
+
* ```ts
|
|
620
|
+
* const users = db.use(Users)
|
|
621
|
+
* const result = await users.deleteOne({ name: 'Ada' })
|
|
622
|
+
* console.log(result.deletedCount) // 1
|
|
623
|
+
* ```
|
|
624
|
+
*/
|
|
625
|
+
async deleteOne(filter) {
|
|
626
|
+
return await deleteOne(this, filter);
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Delete all documents matching the filter.
|
|
630
|
+
*
|
|
631
|
+
* Removes every document that matches the filter from the collection.
|
|
632
|
+
* No validation is performed — documents are deleted directly through
|
|
633
|
+
* the MongoDB driver.
|
|
634
|
+
*
|
|
635
|
+
* @param filter - Type-safe filter to match documents.
|
|
636
|
+
* @returns The MongoDB `DeleteResult` with the deleted count.
|
|
637
|
+
*
|
|
638
|
+
* @example
|
|
639
|
+
* ```ts
|
|
640
|
+
* const users = db.use(Users)
|
|
641
|
+
* const result = await users.deleteMany({ role: 'guest' })
|
|
642
|
+
* console.log(result.deletedCount) // number of guests removed
|
|
643
|
+
* ```
|
|
644
|
+
*/
|
|
645
|
+
async deleteMany(filter) {
|
|
646
|
+
return await deleteMany(this, filter);
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Find a single document matching the filter, delete it, and return the document.
|
|
650
|
+
*
|
|
651
|
+
* Returns the deleted document, or `null` if no document matches the filter.
|
|
652
|
+
* The returned document is validated against the collection's Zod schema
|
|
653
|
+
* using the same resolution logic as {@link findOne}.
|
|
654
|
+
*
|
|
655
|
+
* @param filter - Type-safe filter to match documents.
|
|
656
|
+
* @param options - Optional settings: `validate`.
|
|
657
|
+
* @returns The deleted document, or `null` if no document matches.
|
|
658
|
+
* @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
|
|
659
|
+
*
|
|
660
|
+
* @example
|
|
661
|
+
* ```ts
|
|
662
|
+
* const users = db.use(Users)
|
|
663
|
+
* const user = await users.findOneAndDelete({ name: 'Ada' })
|
|
664
|
+
* if (user) console.log(user.name) // 'Ada' (the deleted document)
|
|
665
|
+
* ```
|
|
666
|
+
*/
|
|
667
|
+
async findOneAndDelete(filter, options) {
|
|
668
|
+
return await findOneAndDelete(this, filter, options);
|
|
669
|
+
}
|
|
342
670
|
};
|
|
343
671
|
|
|
344
672
|
// src/client/client.ts
|
|
@@ -416,14 +744,14 @@ function createClient(uri, dbNameOrOptions, maybeOptions) {
|
|
|
416
744
|
}
|
|
417
745
|
|
|
418
746
|
// src/collection/collection.ts
|
|
419
|
-
import { ObjectId as
|
|
420
|
-
import { z as
|
|
747
|
+
import { ObjectId as ObjectId3 } from "mongodb";
|
|
748
|
+
import { z as z9 } from "zod";
|
|
421
749
|
|
|
422
750
|
// src/schema/extensions.ts
|
|
423
|
-
import { z as
|
|
751
|
+
import { z as z7 } from "zod";
|
|
424
752
|
|
|
425
753
|
// src/schema/ref.ts
|
|
426
|
-
import { z as
|
|
754
|
+
import { z as z6 } from "zod";
|
|
427
755
|
var refMetadata = /* @__PURE__ */ new WeakMap();
|
|
428
756
|
function getRefMetadata(schema) {
|
|
429
757
|
if (typeof schema !== "object" || schema === null) return void 0;
|
|
@@ -431,7 +759,7 @@ function getRefMetadata(schema) {
|
|
|
431
759
|
}
|
|
432
760
|
var REF_GUARD = /* @__PURE__ */ Symbol.for("zodmon_ref");
|
|
433
761
|
function installRefExtension() {
|
|
434
|
-
const proto =
|
|
762
|
+
const proto = z6.ZodType.prototype;
|
|
435
763
|
if (REF_GUARD in proto) return;
|
|
436
764
|
Object.defineProperty(proto, "ref", {
|
|
437
765
|
value(collection2) {
|
|
@@ -458,7 +786,7 @@ function getIndexMetadata(schema) {
|
|
|
458
786
|
}
|
|
459
787
|
var GUARD = /* @__PURE__ */ Symbol.for("zodmon_extensions");
|
|
460
788
|
function installExtensions() {
|
|
461
|
-
const proto =
|
|
789
|
+
const proto = z7.ZodType.prototype;
|
|
462
790
|
if (GUARD in proto) return;
|
|
463
791
|
Object.defineProperty(proto, "index", {
|
|
464
792
|
/**
|
|
@@ -556,14 +884,14 @@ function installExtensions() {
|
|
|
556
884
|
installExtensions();
|
|
557
885
|
|
|
558
886
|
// src/schema/object-id.ts
|
|
559
|
-
import { ObjectId } from "mongodb";
|
|
560
|
-
import { z as
|
|
887
|
+
import { ObjectId as ObjectId2 } from "mongodb";
|
|
888
|
+
import { z as z8 } from "zod";
|
|
561
889
|
var OBJECT_ID_HEX = /^[a-f\d]{24}$/i;
|
|
562
890
|
function objectId() {
|
|
563
|
-
return
|
|
564
|
-
if (val instanceof
|
|
891
|
+
return z8.custom((val) => {
|
|
892
|
+
if (val instanceof ObjectId2) return true;
|
|
565
893
|
return typeof val === "string" && OBJECT_ID_HEX.test(val);
|
|
566
|
-
}, "Invalid ObjectId").transform((val) => val instanceof
|
|
894
|
+
}, "Invalid ObjectId").transform((val) => val instanceof ObjectId2 ? val : ObjectId2.createFromHexString(val));
|
|
567
895
|
}
|
|
568
896
|
|
|
569
897
|
// src/collection/collection.ts
|
|
@@ -578,8 +906,8 @@ function extractFieldIndexes(shape) {
|
|
|
578
906
|
return result;
|
|
579
907
|
}
|
|
580
908
|
function collection(name, shape, options) {
|
|
581
|
-
const resolvedShape = "_id" in shape ? shape : { _id: objectId().default(() => new
|
|
582
|
-
const schema =
|
|
909
|
+
const resolvedShape = "_id" in shape ? shape : { _id: objectId().default(() => new ObjectId3()), ...shape };
|
|
910
|
+
const schema = z9.object(resolvedShape);
|
|
583
911
|
const fieldIndexes = extractFieldIndexes(shape);
|
|
584
912
|
const { indexes: compoundIndexes, validation, ...rest } = options ?? {};
|
|
585
913
|
return {
|
|
@@ -630,14 +958,14 @@ function index(fields) {
|
|
|
630
958
|
}
|
|
631
959
|
|
|
632
960
|
// src/helpers/oid.ts
|
|
633
|
-
import { ObjectId as
|
|
961
|
+
import { ObjectId as ObjectId4 } from "mongodb";
|
|
634
962
|
function oid(value) {
|
|
635
|
-
if (value === void 0) return new
|
|
636
|
-
if (value instanceof
|
|
637
|
-
return
|
|
963
|
+
if (value === void 0) return new ObjectId4();
|
|
964
|
+
if (value instanceof ObjectId4) return value;
|
|
965
|
+
return ObjectId4.createFromHexString(value);
|
|
638
966
|
}
|
|
639
967
|
function isOid(value) {
|
|
640
|
-
return value instanceof
|
|
968
|
+
return value instanceof ObjectId4;
|
|
641
969
|
}
|
|
642
970
|
|
|
643
971
|
// src/query/operators.ts
|
|
@@ -660,7 +988,27 @@ var $or = (...filters) => ({ $or: filters });
|
|
|
660
988
|
var $and = (...filters) => ({ $and: filters });
|
|
661
989
|
var $nor = (...filters) => ({ $nor: filters });
|
|
662
990
|
var raw = (filter) => filter;
|
|
991
|
+
|
|
992
|
+
// src/query/namespace.ts
|
|
993
|
+
var $ = {
|
|
994
|
+
eq: $eq,
|
|
995
|
+
ne: $ne,
|
|
996
|
+
gt: $gt,
|
|
997
|
+
gte: $gte,
|
|
998
|
+
lt: $lt,
|
|
999
|
+
lte: $lte,
|
|
1000
|
+
in: $in,
|
|
1001
|
+
nin: $nin,
|
|
1002
|
+
exists: $exists,
|
|
1003
|
+
regex: $regex,
|
|
1004
|
+
not: $not,
|
|
1005
|
+
or: $or,
|
|
1006
|
+
and: $and,
|
|
1007
|
+
nor: $nor,
|
|
1008
|
+
raw
|
|
1009
|
+
};
|
|
663
1010
|
export {
|
|
1011
|
+
$,
|
|
664
1012
|
$and,
|
|
665
1013
|
$eq,
|
|
666
1014
|
$exists,
|
|
@@ -683,21 +1031,25 @@ export {
|
|
|
683
1031
|
ZodmonValidationError,
|
|
684
1032
|
collection,
|
|
685
1033
|
createClient,
|
|
1034
|
+
deleteMany,
|
|
1035
|
+
deleteOne,
|
|
686
1036
|
extractDbName,
|
|
687
1037
|
extractFieldIndexes,
|
|
688
1038
|
find,
|
|
689
1039
|
findOne,
|
|
1040
|
+
findOneAndDelete,
|
|
1041
|
+
findOneAndUpdate,
|
|
690
1042
|
findOneOrThrow,
|
|
691
1043
|
getIndexMetadata,
|
|
692
1044
|
getRefMetadata,
|
|
693
1045
|
index,
|
|
694
1046
|
insertMany,
|
|
695
1047
|
insertOne,
|
|
696
|
-
installExtensions,
|
|
697
|
-
installRefExtension,
|
|
698
1048
|
isOid,
|
|
699
1049
|
objectId,
|
|
700
1050
|
oid,
|
|
701
|
-
raw
|
|
1051
|
+
raw,
|
|
1052
|
+
updateMany,
|
|
1053
|
+
updateOne
|
|
702
1054
|
};
|
|
703
1055
|
//# sourceMappingURL=index.js.map
|