@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.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { ObjectId, FindCursor, Collection, MongoClientOptions } from 'mongodb';
1
+ import { ObjectId, DeleteResult, FindCursor, Collection, UpdateResult, MongoClientOptions } from 'mongodb';
2
2
  import { ZodPipe, ZodCustom, ZodTransform, z, ZodDefault } from 'zod';
3
3
 
4
4
  /**
@@ -134,32 +134,6 @@ declare module 'zod' {
134
134
  * ```
135
135
  */
136
136
  declare function getIndexMetadata(schema: unknown): IndexMetadata | undefined;
137
- /**
138
- * Monkey-patch Zod's `ZodType.prototype` with Zodmon extension methods
139
- * (`.index()`, `.unique()`, `.text()`, `.expireAfter()`).
140
- *
141
- * In Zod v4, methods are copied from `ZodType.prototype` to each instance
142
- * during construction via the internal `init` loop (`Object.keys(proto)` ->
143
- * copy to instance). Extension methods use `enumerable: true` so they are
144
- * picked up by this loop for every schema created after installation.
145
- *
146
- * The function is idempotent: calling it more than once is a safe no-op,
147
- * guarded by a non-enumerable `Symbol.for('zodmon_extensions')` property
148
- * on the prototype.
149
- *
150
- * This function is called at module level when `extensions.ts` is first
151
- * imported, so consumers never need to call it manually. It is exported
152
- * primarily for use in tests.
153
- *
154
- * @example
155
- * ```ts
156
- * import { installExtensions } from '@zodmon/core/schema/extensions'
157
- * installExtensions() // safe to call multiple times
158
- *
159
- * const indexed = z.string().index({ unique: true })
160
- * ```
161
- */
162
- declare function installExtensions(): void;
163
137
 
164
138
  /**
165
139
  * The Zod type produced by {@link objectId}. A pipeline that validates an
@@ -290,124 +264,6 @@ type CollectionDefinition<TShape extends z.core.$ZodShape = z.core.$ZodShape> =
290
264
  /** Erased collection type for use in generic contexts. */
291
265
  type AnyCollection = CollectionDefinition<z.core.$ZodShape>;
292
266
 
293
- /**
294
- * Type-safe sort specification for a document type.
295
- *
296
- * Constrains sort keys to top-level fields of `T` with direction `1` (ascending)
297
- * or `-1` (descending). Dot-path sorts deferred to v1.0.
298
- *
299
- * @example
300
- * ```ts
301
- * const sort: TypedSort<User> = { name: 1, createdAt: -1 }
302
- * ```
303
- */
304
- type TypedSort<T> = Partial<Record<keyof T & string, 1 | -1>>;
305
- /**
306
- * Type-safe cursor wrapping MongoDB's `FindCursor`.
307
- *
308
- * Provides chainable query modifiers (`sort`, `skip`, `limit`) that return
309
- * `this` for fluent chaining, and terminal methods (`toArray`,
310
- * `[Symbol.asyncIterator]`) that validate each document against the
311
- * collection's Zod schema before returning.
312
- *
313
- * Created by {@link find} — do not construct directly.
314
- *
315
- * @typeParam TDef - The collection definition type, used to infer the document type.
316
- *
317
- * @example
318
- * ```ts
319
- * const docs = await find(users, { role: 'admin' })
320
- * .sort({ name: 1 })
321
- * .limit(10)
322
- * .toArray()
323
- * ```
324
- */
325
- declare class TypedFindCursor<TDef extends AnyCollection> {
326
- /** @internal */
327
- private cursor;
328
- /** @internal */
329
- private schema;
330
- /** @internal */
331
- private collectionName;
332
- /** @internal */
333
- private mode;
334
- /** @internal */
335
- constructor(cursor: FindCursor<InferDocument<TDef>>, definition: TDef, mode: ValidationMode | false);
336
- /**
337
- * Set the sort order for the query.
338
- *
339
- * Only top-level document fields are accepted as sort keys.
340
- * Values must be `1` (ascending) or `-1` (descending).
341
- *
342
- * @param spec - Sort specification mapping field names to sort direction.
343
- * @returns `this` for chaining.
344
- *
345
- * @example
346
- * ```ts
347
- * find(users, {}).sort({ name: 1, age: -1 }).toArray()
348
- * ```
349
- */
350
- sort(spec: TypedSort<InferDocument<TDef>>): this;
351
- /**
352
- * Skip the first `n` documents in the result set.
353
- *
354
- * @param n - Number of documents to skip.
355
- * @returns `this` for chaining.
356
- *
357
- * @example
358
- * ```ts
359
- * find(users, {}).skip(10).limit(10).toArray() // page 2
360
- * ```
361
- */
362
- skip(n: number): this;
363
- /**
364
- * Limit the number of documents returned.
365
- *
366
- * @param n - Maximum number of documents to return.
367
- * @returns `this` for chaining.
368
- *
369
- * @example
370
- * ```ts
371
- * find(users, {}).limit(10).toArray() // at most 10 docs
372
- * ```
373
- */
374
- limit(n: number): this;
375
- /**
376
- * Execute the query and return all matching documents as an array.
377
- *
378
- * Each document is validated against the collection's Zod schema
379
- * according to the resolved validation mode.
380
- *
381
- * @returns Array of validated documents.
382
- * @throws {ZodmonValidationError} When a document fails schema validation in strict/strip mode.
383
- *
384
- * @example
385
- * ```ts
386
- * const admins = await find(users, { role: 'admin' }).toArray()
387
- * ```
388
- */
389
- toArray(): Promise<InferDocument<TDef>[]>;
390
- /**
391
- * Async iterator for streaming documents one at a time.
392
- *
393
- * Each yielded document is validated against the collection's Zod schema.
394
- * Memory-efficient for large result sets.
395
- *
396
- * @yields Validated documents one at a time.
397
- * @throws {ZodmonValidationError} When a document fails schema validation.
398
- *
399
- * @example
400
- * ```ts
401
- * for await (const user of find(users, {})) {
402
- * console.log(user.name)
403
- * }
404
- * ```
405
- */
406
- [Symbol.asyncIterator](): AsyncGenerator<InferDocument<TDef>>;
407
- /** @internal Validate a single raw document against the schema. */
408
- private validateDoc;
409
- }
410
-
411
267
  /**
412
268
  * Comparison operators for a field value of type `V`.
413
269
  *
@@ -533,142 +389,770 @@ type TypedFilter<T> = {
533
389
  };
534
390
 
535
391
  /**
536
- * Options for {@link findOne} and {@link findOneOrThrow}.
392
+ * Options for {@link findOneAndDelete}.
537
393
  */
538
- type FindOneOptions = {
539
- /** MongoDB projection — include (`1`) or exclude (`0`) fields. Typed projections deferred to v1.0. */
540
- project?: Record<string, 0 | 1>;
394
+ type FindOneAndDeleteOptions = {
541
395
  /** Override the collection-level validation mode, or `false` to skip validation entirely. */
542
396
  validate?: ValidationMode | false;
543
397
  };
544
398
  /**
545
- * Find a single document matching the filter.
399
+ * Delete a single document matching the filter.
546
400
  *
547
- * Queries MongoDB, then validates the fetched document against the collection's
548
- * Zod schema. Validation mode is resolved from the per-query option, falling
549
- * back to the collection-level default (which defaults to `'strict'`).
401
+ * Removes the first document that matches the filter from the collection.
402
+ * No validation is performed the document is deleted directly through
403
+ * the MongoDB driver.
550
404
  *
551
- * @param handle - The collection handle to query.
405
+ * @param handle - The collection handle to delete from.
552
406
  * @param filter - Type-safe filter to match documents.
553
- * @param options - Optional projection and validation overrides.
554
- * @returns The matched document, or `null` if no document matches.
555
- * @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
407
+ * @returns The MongoDB `DeleteResult` with the deleted count.
556
408
  *
557
409
  * @example
558
410
  * ```ts
559
- * const user = await findOne(users, { name: 'Ada' })
560
- * if (user) console.log(user.role) // typed as 'admin' | 'user'
411
+ * const result = await deleteOne(users, { name: 'Ada' })
412
+ * console.log(result.deletedCount) // 1
561
413
  * ```
562
414
  */
563
- declare function findOne<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOneOptions): Promise<InferDocument<TDef> | null>;
415
+ declare function deleteOne<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>): Promise<DeleteResult>;
564
416
  /**
565
- * Find a single document matching the filter, or throw if none exists.
417
+ * Delete all documents matching the filter.
566
418
  *
567
- * Behaves identically to {@link findOne} but throws {@link ZodmonNotFoundError}
568
- * instead of returning `null` when no document matches the filter.
419
+ * Removes every document that matches the filter from the collection.
420
+ * No validation is performed documents are deleted directly through
421
+ * the MongoDB driver.
569
422
  *
570
- * @param handle - The collection handle to query.
423
+ * @param handle - The collection handle to delete from.
571
424
  * @param filter - Type-safe filter to match documents.
572
- * @param options - Optional projection and validation overrides.
573
- * @returns The matched document (never null).
574
- * @throws {ZodmonNotFoundError} When no document matches the filter.
575
- * @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
425
+ * @returns The MongoDB `DeleteResult` with the deleted count.
576
426
  *
577
427
  * @example
578
428
  * ```ts
579
- * const user = await findOneOrThrow(users, { name: 'Ada' })
580
- * console.log(user.role) // typed as 'admin' | 'user', guaranteed non-null
429
+ * const result = await deleteMany(users, { role: 'guest' })
430
+ * console.log(result.deletedCount) // number of guests removed
581
431
  * ```
582
432
  */
583
- declare function findOneOrThrow<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOneOptions): Promise<InferDocument<TDef>>;
433
+ declare function deleteMany<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>): Promise<DeleteResult>;
584
434
  /**
585
- * Options for {@link find}.
435
+ * Find a single document matching the filter, delete it, and return the document.
436
+ *
437
+ * Returns the deleted document, or `null` if no document matches the filter.
438
+ * The returned document is validated against the collection's Zod schema
439
+ * using the same resolution logic as {@link findOne}.
440
+ *
441
+ * @param handle - The collection handle to delete from.
442
+ * @param filter - Type-safe filter to match documents.
443
+ * @param options - Optional settings: `validate`.
444
+ * @returns The deleted document, or `null` if no document matches.
445
+ * @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
446
+ *
447
+ * @example
448
+ * ```ts
449
+ * const user = await findOneAndDelete(users, { name: 'Ada' })
450
+ * if (user) console.log(user.name) // 'Ada' (the deleted document)
451
+ * ```
452
+ *
453
+ * @example
454
+ * ```ts
455
+ * const user = await findOneAndDelete(
456
+ * users,
457
+ * { role: 'guest' },
458
+ * { validate: false },
459
+ * )
460
+ * ```
586
461
  */
587
- type FindOptions = {
588
- /** Override the collection-level validation mode, or `false` to skip validation entirely. */
589
- validate?: ValidationMode | false;
590
- };
462
+ declare function findOneAndDelete<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOneAndDeleteOptions): Promise<InferDocument<TDef> | null>;
463
+
591
464
  /**
592
- * Find all documents matching the filter, returning a chainable typed cursor.
593
- *
594
- * The cursor is lazy — no query is executed until a terminal method
595
- * (`toArray`, `for await`) is called. Use `sort`, `skip`, and `limit`
596
- * to shape the query before executing.
465
+ * Options for offset-based pagination.
597
466
  *
598
- * Each document is validated against the collection's Zod schema when
599
- * a terminal method consumes it.
467
+ * @example
468
+ * ```ts
469
+ * await users.find({}).sort({ name: 1 }).paginate({ page: 2, perPage: 10 })
470
+ * ```
471
+ */
472
+ type OffsetPaginateOptions = {
473
+ /** The page number to retrieve (1-indexed). */
474
+ page: number;
475
+ /** The number of documents per page. */
476
+ perPage: number;
477
+ };
478
+ /**
479
+ * Options for cursor-based pagination.
600
480
  *
601
- * @param handle - The collection handle to query.
602
- * @param filter - Type-safe filter to match documents.
603
- * @param options - Optional validation overrides.
604
- * @returns A typed cursor for chaining query modifiers.
481
+ * @example
482
+ * ```ts
483
+ * const first = await users.find({}).sort({ name: 1 }).paginate({ limit: 10 })
484
+ * const next = await users.find({}).sort({ name: 1 }).paginate({ cursor: first.endCursor, limit: 10 })
485
+ * ```
486
+ */
487
+ type CursorPaginateOptions = {
488
+ /** Maximum number of documents to return. */
489
+ limit: number;
490
+ /** Opaque cursor string from a previous `startCursor` or `endCursor`. */
491
+ cursor?: string | null;
492
+ };
493
+ /**
494
+ * Result of offset-based pagination.
605
495
  *
606
496
  * @example
607
497
  * ```ts
608
- * const admins = await find(users, { role: 'admin' })
609
- * .sort({ name: 1 })
610
- * .limit(10)
611
- * .toArray()
498
+ * const page = await users.find({}).paginate({ page: 1, perPage: 10 })
499
+ * console.log(page.total, page.totalPages, page.hasNext)
612
500
  * ```
501
+ */
502
+ type OffsetPage<TDoc> = {
503
+ /** The documents for this page. */
504
+ docs: TDoc[];
505
+ /** Total number of matching documents. */
506
+ total: number;
507
+ /** Current page number (1-indexed). */
508
+ page: number;
509
+ /** Number of documents per page. */
510
+ perPage: number;
511
+ /** Total number of pages (`Math.ceil(total / perPage)`). */
512
+ totalPages: number;
513
+ /** Whether there is a next page. */
514
+ hasNext: boolean;
515
+ /** Whether there is a previous page. */
516
+ hasPrev: boolean;
517
+ };
518
+ /**
519
+ * Result of cursor-based pagination.
613
520
  *
614
521
  * @example
615
522
  * ```ts
616
- * for await (const user of find(users, {})) {
617
- * console.log(user.name)
523
+ * const page = await users.find({}).paginate({ limit: 10 })
524
+ * if (page.hasNext) {
525
+ * const next = await users.find({}).paginate({ cursor: page.endCursor, limit: 10 })
618
526
  * }
619
527
  * ```
620
528
  */
621
- declare function find<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOptions): TypedFindCursor<TDef>;
529
+ type CursorPage<TDoc> = {
530
+ /** The documents for this page. */
531
+ docs: TDoc[];
532
+ /** Whether there are more documents after this page. */
533
+ hasNext: boolean;
534
+ /** Whether there are documents before this page. */
535
+ hasPrev: boolean;
536
+ /** Cursor for the first document (pass to `cursor` to go backward). `null` when empty. */
537
+ startCursor: string | null;
538
+ /** Cursor for the last document (pass to `cursor` to go forward). `null` when empty. */
539
+ endCursor: string | null;
540
+ };
622
541
 
623
542
  /**
624
- * Typed wrapper around a MongoDB driver `Collection`.
543
+ * Type-safe sort specification for a document type.
625
544
  *
626
- * Created by {@link Database.use}. Holds the original `CollectionDefinition`
627
- * (for runtime schema validation and index metadata) alongside the native
628
- * driver collection parameterized with the inferred document type.
545
+ * Constrains sort keys to top-level fields of `T` with direction `1` (ascending)
546
+ * or `-1` (descending). Dot-path sorts deferred to v1.0.
629
547
  *
630
- * @typeParam TDef - The collection definition type. Used to derive both
631
- * the document type (`InferDocument`) and the insert type (`InferInsert`).
548
+ * @example
549
+ * ```ts
550
+ * const sort: TypedSort<User> = { name: 1, createdAt: -1 }
551
+ * ```
632
552
  */
633
- declare class CollectionHandle<TDef extends AnyCollection = AnyCollection> {
634
- /** The collection definition containing schema, name, and index metadata. */
635
- readonly definition: TDef;
636
- /** The underlying MongoDB driver collection, typed to the inferred document type. */
637
- readonly native: Collection<InferDocument<TDef>>;
638
- constructor(definition: TDef, native: Collection<InferDocument<TDef>>);
639
- /**
640
- * Insert a single document into the collection.
641
- *
642
- * Validates the input against the collection's Zod schema before writing.
643
- * Schema defaults (including auto-generated `_id`) are applied during
644
- * validation. Returns the full document with all defaults filled in.
645
- *
646
- * @param doc - The document to insert. Fields with `.default()` are optional.
647
- * @returns The inserted document with `_id` and all defaults applied.
648
- * @throws {ZodmonValidationError} When the document fails schema validation.
649
- *
650
- * @example
651
- * ```ts
652
- * const users = db.use(Users)
653
- * const user = await users.insertOne({ name: 'Ada' })
654
- * console.log(user._id) // ObjectId (auto-generated)
655
- * console.log(user.role) // 'user' (schema default)
656
- * ```
657
- */
658
- insertOne(doc: InferInsert<TDef>): Promise<InferDocument<TDef>>;
659
- /**
660
- * Insert multiple documents into the collection.
661
- *
662
- * Validates every document against the collection's Zod schema before
663
- * writing any to MongoDB. If any document fails validation, none are
664
- * inserted (fail-fast before the driver call).
665
- *
666
- * @param docs - The documents to insert.
667
- * @returns The inserted documents with `_id` and all defaults applied.
668
- * @throws {ZodmonValidationError} When any document fails schema validation.
669
- *
670
- * @example
671
- * ```ts
553
+ type TypedSort<T> = Partial<Record<keyof T & string, 1 | -1>>;
554
+ /**
555
+ * Type-safe cursor wrapping MongoDB's `FindCursor`.
556
+ *
557
+ * Provides chainable query modifiers (`sort`, `skip`, `limit`) that return
558
+ * `this` for fluent chaining, and terminal methods (`toArray`,
559
+ * `[Symbol.asyncIterator]`) that validate each document against the
560
+ * collection's Zod schema before returning.
561
+ *
562
+ * Created by {@link find} do not construct directly.
563
+ *
564
+ * @typeParam TDef - The collection definition type, used to infer the document type.
565
+ *
566
+ * @example
567
+ * ```ts
568
+ * const docs = await find(users, { role: 'admin' })
569
+ * .sort({ name: 1 })
570
+ * .limit(10)
571
+ * .toArray()
572
+ * ```
573
+ */
574
+ declare class TypedFindCursor<TDef extends AnyCollection> {
575
+ /** @internal */
576
+ private cursor;
577
+ /** @internal */
578
+ private schema;
579
+ /** @internal */
580
+ private collectionName;
581
+ /** @internal */
582
+ private mode;
583
+ /** @internal */
584
+ private readonly nativeCollection;
585
+ /** @internal */
586
+ private readonly filter;
587
+ /** @internal */
588
+ private sortSpec;
589
+ /** @internal */
590
+ constructor(cursor: FindCursor<InferDocument<TDef>>, definition: TDef, mode: ValidationMode | false, nativeCollection: Collection<InferDocument<TDef>>, filter: any);
591
+ /**
592
+ * Set the sort order for the query.
593
+ *
594
+ * Only top-level document fields are accepted as sort keys.
595
+ * Values must be `1` (ascending) or `-1` (descending).
596
+ *
597
+ * @param spec - Sort specification mapping field names to sort direction.
598
+ * @returns `this` for chaining.
599
+ *
600
+ * @example
601
+ * ```ts
602
+ * find(users, {}).sort({ name: 1, age: -1 }).toArray()
603
+ * ```
604
+ */
605
+ sort(spec: TypedSort<InferDocument<TDef>>): this;
606
+ /**
607
+ * Skip the first `n` documents in the result set.
608
+ *
609
+ * @param n - Number of documents to skip.
610
+ * @returns `this` for chaining.
611
+ *
612
+ * @example
613
+ * ```ts
614
+ * find(users, {}).skip(10).limit(10).toArray() // page 2
615
+ * ```
616
+ */
617
+ skip(n: number): this;
618
+ /**
619
+ * Limit the number of documents returned.
620
+ *
621
+ * @param n - Maximum number of documents to return.
622
+ * @returns `this` for chaining.
623
+ *
624
+ * @example
625
+ * ```ts
626
+ * find(users, {}).limit(10).toArray() // at most 10 docs
627
+ * ```
628
+ */
629
+ limit(n: number): this;
630
+ /**
631
+ * Execute the query with offset-based pagination, returning a page of documents
632
+ * with total count and navigation metadata.
633
+ *
634
+ * Runs `countDocuments` and `find` in parallel for performance. Ignores any
635
+ * `.skip()` or `.limit()` already set on the cursor — issues a fresh query.
636
+ *
637
+ * @param opts - Offset pagination options: `page` (1-indexed) and `perPage`.
638
+ * @returns A page with `docs`, `total`, `totalPages`, `hasNext`, `hasPrev`.
639
+ * @throws {ZodmonValidationError} When a document fails schema validation.
640
+ *
641
+ * @example
642
+ * ```ts
643
+ * const page = await users.find({ role: 'admin' })
644
+ * .sort({ createdAt: -1 })
645
+ * .paginate({ page: 2, perPage: 10 })
646
+ * console.log(page.total, page.totalPages, page.hasNext)
647
+ * ```
648
+ */
649
+ paginate(opts: OffsetPaginateOptions): Promise<OffsetPage<InferDocument<TDef>>>;
650
+ /**
651
+ * Execute the query with cursor-based pagination, returning a page of documents
652
+ * with opaque cursors for forward/backward navigation.
653
+ *
654
+ * Uses the `limit + 1` trick to determine `hasNext`/`hasPrev` without extra queries.
655
+ * Direction is encoded in the cursor — pass `endCursor` to go forward, `startCursor`
656
+ * to go backward.
657
+ *
658
+ * @param opts - Cursor pagination options: `limit` and optional `cursor`.
659
+ * @returns A page with `docs`, `hasNext`, `hasPrev`, `startCursor`, `endCursor`.
660
+ * @throws {ZodmonValidationError} When a document fails schema validation.
661
+ * @throws {Error} When the cursor string is malformed.
662
+ *
663
+ * @example
664
+ * ```ts
665
+ * const first = await users.find({}).sort({ name: 1 }).paginate({ limit: 10 })
666
+ * const next = await users.find({}).sort({ name: 1 })
667
+ * .paginate({ cursor: first.endCursor, limit: 10 })
668
+ * ```
669
+ */
670
+ paginate(opts: CursorPaginateOptions): Promise<CursorPage<InferDocument<TDef>>>;
671
+ /** @internal Offset pagination implementation. */
672
+ private offsetPaginate;
673
+ /** @internal Cursor pagination implementation. */
674
+ private cursorPaginate;
675
+ /**
676
+ * Execute the query and return all matching documents as an array.
677
+ *
678
+ * Each document is validated against the collection's Zod schema
679
+ * according to the resolved validation mode.
680
+ *
681
+ * @returns Array of validated documents.
682
+ * @throws {ZodmonValidationError} When a document fails schema validation in strict/strip mode.
683
+ *
684
+ * @example
685
+ * ```ts
686
+ * const admins = await find(users, { role: 'admin' }).toArray()
687
+ * ```
688
+ */
689
+ toArray(): Promise<InferDocument<TDef>[]>;
690
+ /**
691
+ * Async iterator for streaming documents one at a time.
692
+ *
693
+ * Each yielded document is validated against the collection's Zod schema.
694
+ * Memory-efficient for large result sets.
695
+ *
696
+ * @yields Validated documents one at a time.
697
+ * @throws {ZodmonValidationError} When a document fails schema validation.
698
+ *
699
+ * @example
700
+ * ```ts
701
+ * for await (const user of find(users, {})) {
702
+ * console.log(user.name)
703
+ * }
704
+ * ```
705
+ */
706
+ [Symbol.asyncIterator](): AsyncGenerator<InferDocument<TDef>>;
707
+ /** @internal Validate a single raw document against the schema. */
708
+ private validateDoc;
709
+ }
710
+
711
+ /**
712
+ * Options for {@link findOne} and {@link findOneOrThrow}.
713
+ */
714
+ type FindOneOptions = {
715
+ /** MongoDB projection — include (`1`) or exclude (`0`) fields. Typed projections deferred to v1.0. */
716
+ project?: Record<string, 0 | 1>;
717
+ /** Override the collection-level validation mode, or `false` to skip validation entirely. */
718
+ validate?: ValidationMode | false;
719
+ };
720
+ /**
721
+ * Find a single document matching the filter.
722
+ *
723
+ * Queries MongoDB, then validates the fetched document against the collection's
724
+ * Zod schema. Validation mode is resolved from the per-query option, falling
725
+ * back to the collection-level default (which defaults to `'strict'`).
726
+ *
727
+ * @param handle - The collection handle to query.
728
+ * @param filter - Type-safe filter to match documents.
729
+ * @param options - Optional projection and validation overrides.
730
+ * @returns The matched document, or `null` if no document matches.
731
+ * @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
732
+ *
733
+ * @example
734
+ * ```ts
735
+ * const user = await findOne(users, { name: 'Ada' })
736
+ * if (user) console.log(user.role) // typed as 'admin' | 'user'
737
+ * ```
738
+ */
739
+ declare function findOne<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOneOptions): Promise<InferDocument<TDef> | null>;
740
+ /**
741
+ * Find a single document matching the filter, or throw if none exists.
742
+ *
743
+ * Behaves identically to {@link findOne} but throws {@link ZodmonNotFoundError}
744
+ * instead of returning `null` when no document matches the filter.
745
+ *
746
+ * @param handle - The collection handle to query.
747
+ * @param filter - Type-safe filter to match documents.
748
+ * @param options - Optional projection and validation overrides.
749
+ * @returns The matched document (never null).
750
+ * @throws {ZodmonNotFoundError} When no document matches the filter.
751
+ * @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
752
+ *
753
+ * @example
754
+ * ```ts
755
+ * const user = await findOneOrThrow(users, { name: 'Ada' })
756
+ * console.log(user.role) // typed as 'admin' | 'user', guaranteed non-null
757
+ * ```
758
+ */
759
+ declare function findOneOrThrow<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOneOptions): Promise<InferDocument<TDef>>;
760
+ /**
761
+ * Options for {@link find}.
762
+ */
763
+ type FindOptions = {
764
+ /** Override the collection-level validation mode, or `false` to skip validation entirely. */
765
+ validate?: ValidationMode | false;
766
+ };
767
+ /**
768
+ * Find all documents matching the filter, returning a chainable typed cursor.
769
+ *
770
+ * The cursor is lazy — no query is executed until a terminal method
771
+ * (`toArray`, `for await`) is called. Use `sort`, `skip`, and `limit`
772
+ * to shape the query before executing.
773
+ *
774
+ * Each document is validated against the collection's Zod schema when
775
+ * a terminal method consumes it.
776
+ *
777
+ * @param handle - The collection handle to query.
778
+ * @param filter - Type-safe filter to match documents.
779
+ * @param options - Optional validation overrides.
780
+ * @returns A typed cursor for chaining query modifiers.
781
+ *
782
+ * @example
783
+ * ```ts
784
+ * const admins = await find(users, { role: 'admin' })
785
+ * .sort({ name: 1 })
786
+ * .limit(10)
787
+ * .toArray()
788
+ * ```
789
+ *
790
+ * @example
791
+ * ```ts
792
+ * for await (const user of find(users, {})) {
793
+ * console.log(user.name)
794
+ * }
795
+ * ```
796
+ */
797
+ declare function find<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOptions): TypedFindCursor<TDef>;
798
+
799
+ /**
800
+ * Extracts the element type from an array type.
801
+ *
802
+ * @example
803
+ * ```ts
804
+ * type E = ArrayElement<string[]> // string
805
+ * type N = ArrayElement<number[]> // number
806
+ * ```
807
+ */
808
+ type ArrayElement<T> = T extends ReadonlyArray<infer E> ? E : never;
809
+ /**
810
+ * Fields valid for `$set`, `$setOnInsert`, `$min`, and `$max` operators.
811
+ *
812
+ * Allows top-level fields with matching value types plus dot-notation paths
813
+ * for nested field updates.
814
+ *
815
+ * @example
816
+ * ```ts
817
+ * const set: SetFields<User> = { name: 'Alice', 'address.city': 'NYC' }
818
+ * ```
819
+ */
820
+ type SetFields<T> = {
821
+ [K in keyof T]?: T[K];
822
+ } & {
823
+ [P in DotPaths<T>]?: DotPathType<T, P>;
824
+ };
825
+ /**
826
+ * Fields valid for the `$inc` operator — only number-typed fields.
827
+ *
828
+ * Includes dot-notation paths that resolve to number types.
829
+ *
830
+ * @example
831
+ * ```ts
832
+ * const inc: IncFields<User> = { age: 1, 'stats.views': 5 }
833
+ * ```
834
+ */
835
+ type IncFields<T> = {
836
+ [K in keyof T as NonNullable<T[K]> extends number ? K : never]?: number;
837
+ } & {
838
+ [P in DotPaths<T> as DotPathType<T, P> extends number ? P : never]?: number;
839
+ };
840
+ /**
841
+ * Modifiers for the `$push` operator.
842
+ *
843
+ * Use with `$push` to insert multiple elements and control array position/size.
844
+ *
845
+ * @example
846
+ * ```ts
847
+ * const push = { tags: { $each: ['a', 'b'], $position: 0, $slice: 10 } }
848
+ * ```
849
+ */
850
+ type PushModifiers<E> = {
851
+ /** Array of elements to push. */
852
+ $each: E[];
853
+ /** Position at which to insert elements. */
854
+ $position?: number;
855
+ /** Maximum array length after push. */
856
+ $slice?: number;
857
+ /** Sort order applied after push. */
858
+ $sort?: 1 | -1 | Record<string, 1 | -1>;
859
+ };
860
+ /**
861
+ * Fields valid for the `$push` operator — only array-typed fields.
862
+ *
863
+ * Accepts a single element value or a modifier object with `$each`.
864
+ *
865
+ * @example
866
+ * ```ts
867
+ * const push: PushFields<User> = { tags: 'dev' }
868
+ * const pushMany: PushFields<User> = { tags: { $each: ['a', 'b'] } }
869
+ * ```
870
+ */
871
+ type PushFields<T> = {
872
+ [K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: ArrayElement<NonNullable<T[K]>> | PushModifiers<ArrayElement<NonNullable<T[K]>>>;
873
+ };
874
+ /**
875
+ * Fields valid for the `$pull` operator — only array-typed fields.
876
+ *
877
+ * For primitive arrays: accepts a value or comparison operators.
878
+ * For object arrays: also accepts a `TypedFilter` on the element type.
879
+ *
880
+ * @example
881
+ * ```ts
882
+ * const pull: PullFields<User> = { tags: 'old' }
883
+ * const pullQuery: PullFields<User> = { scores: { $lt: 50 } }
884
+ * const pullObj: PullFields<User> = { comments: { author: 'spam' } }
885
+ * ```
886
+ */
887
+ type PullFields<T> = {
888
+ [K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: ArrayElement<NonNullable<T[K]>> | ComparisonOperators<ArrayElement<NonNullable<T[K]>>> | (ArrayElement<NonNullable<T[K]>> extends Record<string, unknown> ? TypedFilter<ArrayElement<NonNullable<T[K]>>> : unknown);
889
+ };
890
+ /**
891
+ * Modifier for the `$addToSet` operator's `$each` syntax.
892
+ *
893
+ * @example
894
+ * ```ts
895
+ * const addToSet = { tags: { $each: ['a', 'b'] } }
896
+ * ```
897
+ */
898
+ type AddToSetEach<E> = {
899
+ $each: E[];
900
+ };
901
+ /**
902
+ * Fields valid for the `$addToSet` operator — only array-typed fields.
903
+ *
904
+ * Accepts a single element value or `{ $each: [...] }` for multiple elements.
905
+ *
906
+ * @example
907
+ * ```ts
908
+ * const add: AddToSetFields<User> = { tags: 'dev' }
909
+ * const addMany: AddToSetFields<User> = { tags: { $each: ['a', 'b'] } }
910
+ * ```
911
+ */
912
+ type AddToSetFields<T> = {
913
+ [K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: ArrayElement<NonNullable<T[K]>> | AddToSetEach<ArrayElement<NonNullable<T[K]>>>;
914
+ };
915
+ /**
916
+ * Fields valid for the `$pop` operator — only array-typed fields.
917
+ *
918
+ * Value `1` removes the last element, `-1` removes the first.
919
+ *
920
+ * @example
921
+ * ```ts
922
+ * const pop: PopFields<User> = { tags: -1 } // remove first
923
+ * ```
924
+ */
925
+ type PopFields<T> = {
926
+ [K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: 1 | -1;
927
+ };
928
+ /**
929
+ * Fields valid for the `$unset` operator — any existing field.
930
+ *
931
+ * Value is `''`, `true`, or `1` (all mean "remove this field").
932
+ *
933
+ * @example
934
+ * ```ts
935
+ * const unset: UnsetFields<User> = { middleName: '' }
936
+ * ```
937
+ */
938
+ type UnsetFields<T> = {
939
+ [K in keyof T]?: '' | true | 1;
940
+ };
941
+ /**
942
+ * Fields valid for the `$currentDate` operator — only Date-typed fields.
943
+ *
944
+ * Sets the field to the current date. Value is `true` or `{ $type: 'date' }`.
945
+ *
946
+ * @example
947
+ * ```ts
948
+ * const cd: CurrentDateFields<User> = { createdAt: true }
949
+ * ```
950
+ */
951
+ type CurrentDateFields<T> = {
952
+ [K in keyof T as NonNullable<T[K]> extends Date ? K : never]?: true | {
953
+ $type: 'date';
954
+ };
955
+ };
956
+ /**
957
+ * Fields valid for the `$rename` operator.
958
+ *
959
+ * Renames an existing field to a new name. Key is the current field name,
960
+ * value is the new name as a string.
961
+ *
962
+ * @example
963
+ * ```ts
964
+ * const rename: RenameFields<User> = { name: 'fullName' }
965
+ * ```
966
+ */
967
+ type RenameFields<T> = {
968
+ [K in keyof T & string]?: string;
969
+ };
970
+ /**
971
+ * Strict type-safe MongoDB update filter.
972
+ *
973
+ * Validates update operators against field types at compile time. Each operator
974
+ * constrains which fields it accepts (e.g. `$inc` only on numbers, `$push` only
975
+ * on arrays). Supports dot-notation paths for nested field access.
976
+ *
977
+ * @example
978
+ * ```ts
979
+ * const update: TypedUpdateFilter<User> = {
980
+ * $set: { name: 'Alice' },
981
+ * $inc: { age: 1 },
982
+ * }
983
+ * ```
984
+ */
985
+ type TypedUpdateFilter<T> = {
986
+ /** Sets the value of one or more fields. */
987
+ $set?: SetFields<T>;
988
+ /** Sets fields only when inserting (upsert). Same typing as `$set`. */
989
+ $setOnInsert?: SetFields<T>;
990
+ /** Increments numeric fields by the given amount. Only accepts number-typed fields. */
991
+ $inc?: IncFields<T>;
992
+ /** Updates the field if the given value is less than the current value. */
993
+ $min?: SetFields<T>;
994
+ /** Updates the field if the given value is greater than the current value. */
995
+ $max?: SetFields<T>;
996
+ /** Appends a value to an array field. Supports `$each`, `$position`, `$slice`, `$sort`. */
997
+ $push?: PushFields<T>;
998
+ /** Removes matching values from an array field. */
999
+ $pull?: PullFields<T>;
1000
+ /** Adds a value to an array only if it doesn't already exist. */
1001
+ $addToSet?: AddToSetFields<T>;
1002
+ /** Removes the first (`-1`) or last (`1`) element of an array. */
1003
+ $pop?: PopFields<T>;
1004
+ /** Removes the specified fields from the document. */
1005
+ $unset?: UnsetFields<T>;
1006
+ /** Sets the field to the current date. Only accepts Date-typed fields. */
1007
+ $currentDate?: CurrentDateFields<T>;
1008
+ /** Renames a field. */
1009
+ $rename?: RenameFields<T>;
1010
+ };
1011
+
1012
+ /**
1013
+ * Options for {@link updateOne} and {@link updateMany}.
1014
+ */
1015
+ type UpdateOptions = {
1016
+ /** When `true`, inserts a new document if no document matches the filter. */
1017
+ upsert?: boolean;
1018
+ };
1019
+ /**
1020
+ * Options for {@link findOneAndUpdate}.
1021
+ */
1022
+ type FindOneAndUpdateOptions = {
1023
+ /** Whether to return the document before or after the update. Defaults to `'after'`. */
1024
+ returnDocument?: 'before' | 'after';
1025
+ /** When `true`, inserts a new document if no document matches the filter. */
1026
+ upsert?: boolean;
1027
+ /** Override the collection-level validation mode, or `false` to skip validation entirely. */
1028
+ validate?: ValidationMode | false;
1029
+ };
1030
+ /**
1031
+ * Update a single document matching the filter.
1032
+ *
1033
+ * Applies the update operators to the first document that matches the filter.
1034
+ * Does not validate the update against the Zod schema — validation happens
1035
+ * at the field-operator level through {@link TypedUpdateFilter}.
1036
+ *
1037
+ * @param handle - The collection handle to update in.
1038
+ * @param filter - Type-safe filter to match documents.
1039
+ * @param update - Type-safe update operators to apply.
1040
+ * @param options - Optional settings such as `upsert`.
1041
+ * @returns The MongoDB `UpdateResult` with match/modify counts.
1042
+ *
1043
+ * @example
1044
+ * ```ts
1045
+ * const result = await updateOne(users, { name: 'Ada' }, { $set: { role: 'admin' } })
1046
+ * console.log(result.modifiedCount) // 1
1047
+ * ```
1048
+ */
1049
+ declare function updateOne<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: UpdateOptions): Promise<UpdateResult>;
1050
+ /**
1051
+ * Update all documents matching the filter.
1052
+ *
1053
+ * Applies the update operators to every document that matches the filter.
1054
+ * Does not validate the update against the Zod schema — validation happens
1055
+ * at the field-operator level through {@link TypedUpdateFilter}.
1056
+ *
1057
+ * @param handle - The collection handle to update in.
1058
+ * @param filter - Type-safe filter to match documents.
1059
+ * @param update - Type-safe update operators to apply.
1060
+ * @param options - Optional settings such as `upsert`.
1061
+ * @returns The MongoDB `UpdateResult` with match/modify counts.
1062
+ *
1063
+ * @example
1064
+ * ```ts
1065
+ * const result = await updateMany(users, { role: 'guest' }, { $set: { role: 'user' } })
1066
+ * console.log(result.modifiedCount) // number of guests promoted
1067
+ * ```
1068
+ */
1069
+ declare function updateMany<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: UpdateOptions): Promise<UpdateResult>;
1070
+ /**
1071
+ * Find a single document matching the filter, apply an update, and return the document.
1072
+ *
1073
+ * By default, returns the document **after** the update is applied. Set
1074
+ * `returnDocument: 'before'` to get the pre-update snapshot. The returned
1075
+ * document is validated against the collection's Zod schema using the same
1076
+ * resolution logic as {@link findOne}.
1077
+ *
1078
+ * @param handle - The collection handle to update in.
1079
+ * @param filter - Type-safe filter to match documents.
1080
+ * @param update - Type-safe update operators to apply.
1081
+ * @param options - Optional settings: `returnDocument`, `upsert`, `validate`.
1082
+ * @returns The matched document (before or after update), or `null` if no document matches.
1083
+ * @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
1084
+ *
1085
+ * @example
1086
+ * ```ts
1087
+ * const user = await findOneAndUpdate(
1088
+ * users,
1089
+ * { name: 'Ada' },
1090
+ * { $set: { role: 'admin' } },
1091
+ * )
1092
+ * if (user) console.log(user.role) // 'admin' (returned after update)
1093
+ * ```
1094
+ *
1095
+ * @example
1096
+ * ```ts
1097
+ * const before = await findOneAndUpdate(
1098
+ * users,
1099
+ * { name: 'Ada' },
1100
+ * { $inc: { loginCount: 1 } },
1101
+ * { returnDocument: 'before' },
1102
+ * )
1103
+ * ```
1104
+ */
1105
+ declare function findOneAndUpdate<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: FindOneAndUpdateOptions): Promise<InferDocument<TDef> | null>;
1106
+
1107
+ /**
1108
+ * Typed wrapper around a MongoDB driver `Collection`.
1109
+ *
1110
+ * Created by {@link Database.use}. Holds the original `CollectionDefinition`
1111
+ * (for runtime schema validation and index metadata) alongside the native
1112
+ * driver collection parameterized with the inferred document type.
1113
+ *
1114
+ * @typeParam TDef - The collection definition type. Used to derive both
1115
+ * the document type (`InferDocument`) and the insert type (`InferInsert`).
1116
+ */
1117
+ declare class CollectionHandle<TDef extends AnyCollection = AnyCollection> {
1118
+ /** The collection definition containing schema, name, and index metadata. */
1119
+ readonly definition: TDef;
1120
+ /** The underlying MongoDB driver collection, typed to the inferred document type. */
1121
+ readonly native: Collection<InferDocument<TDef>>;
1122
+ constructor(definition: TDef, native: Collection<InferDocument<TDef>>);
1123
+ /**
1124
+ * Insert a single document into the collection.
1125
+ *
1126
+ * Validates the input against the collection's Zod schema before writing.
1127
+ * Schema defaults (including auto-generated `_id`) are applied during
1128
+ * validation. Returns the full document with all defaults filled in.
1129
+ *
1130
+ * @param doc - The document to insert. Fields with `.default()` are optional.
1131
+ * @returns The inserted document with `_id` and all defaults applied.
1132
+ * @throws {ZodmonValidationError} When the document fails schema validation.
1133
+ *
1134
+ * @example
1135
+ * ```ts
1136
+ * const users = db.use(Users)
1137
+ * const user = await users.insertOne({ name: 'Ada' })
1138
+ * console.log(user._id) // ObjectId (auto-generated)
1139
+ * console.log(user.role) // 'user' (schema default)
1140
+ * ```
1141
+ */
1142
+ insertOne(doc: InferInsert<TDef>): Promise<InferDocument<TDef>>;
1143
+ /**
1144
+ * Insert multiple documents into the collection.
1145
+ *
1146
+ * Validates every document against the collection's Zod schema before
1147
+ * writing any to MongoDB. If any document fails validation, none are
1148
+ * inserted (fail-fast before the driver call).
1149
+ *
1150
+ * @param docs - The documents to insert.
1151
+ * @returns The inserted documents with `_id` and all defaults applied.
1152
+ * @throws {ZodmonValidationError} When any document fails schema validation.
1153
+ *
1154
+ * @example
1155
+ * ```ts
672
1156
  * const created = await users.insertMany([
673
1157
  * { name: 'Ada' },
674
1158
  * { name: 'Bob', role: 'admin' },
@@ -737,6 +1221,127 @@ declare class CollectionHandle<TDef extends AnyCollection = AnyCollection> {
737
1221
  * ```
738
1222
  */
739
1223
  find(filter: TypedFilter<InferDocument<TDef>>, options?: FindOptions): TypedFindCursor<TDef>;
1224
+ /**
1225
+ * Update a single document matching the filter.
1226
+ *
1227
+ * Applies the update operators to the first document that matches the filter.
1228
+ * Does not validate the update against the Zod schema — validation happens
1229
+ * at the field-operator level through {@link TypedUpdateFilter}.
1230
+ *
1231
+ * @param filter - Type-safe filter to match documents.
1232
+ * @param update - Type-safe update operators to apply.
1233
+ * @param options - Optional settings such as `upsert`.
1234
+ * @returns The MongoDB `UpdateResult` with match/modify counts.
1235
+ *
1236
+ * @example
1237
+ * ```ts
1238
+ * const users = db.use(Users)
1239
+ * const result = await users.updateOne({ name: 'Ada' }, { $set: { role: 'admin' } })
1240
+ * console.log(result.modifiedCount) // 1
1241
+ * ```
1242
+ */
1243
+ updateOne(filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: UpdateOptions): Promise<UpdateResult>;
1244
+ /**
1245
+ * Update all documents matching the filter.
1246
+ *
1247
+ * Applies the update operators to every document that matches the filter.
1248
+ * Does not validate the update against the Zod schema — validation happens
1249
+ * at the field-operator level through {@link TypedUpdateFilter}.
1250
+ *
1251
+ * @param filter - Type-safe filter to match documents.
1252
+ * @param update - Type-safe update operators to apply.
1253
+ * @param options - Optional settings such as `upsert`.
1254
+ * @returns The MongoDB `UpdateResult` with match/modify counts.
1255
+ *
1256
+ * @example
1257
+ * ```ts
1258
+ * const users = db.use(Users)
1259
+ * const result = await users.updateMany({ role: 'guest' }, { $set: { role: 'user' } })
1260
+ * console.log(result.modifiedCount) // number of guests promoted
1261
+ * ```
1262
+ */
1263
+ updateMany(filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: UpdateOptions): Promise<UpdateResult>;
1264
+ /**
1265
+ * Find a single document matching the filter, apply an update, and return the document.
1266
+ *
1267
+ * By default, returns the document **after** the update is applied. Set
1268
+ * `returnDocument: 'before'` to get the pre-update snapshot. The returned
1269
+ * document is validated against the collection's Zod schema using the same
1270
+ * resolution logic as {@link findOne}.
1271
+ *
1272
+ * @param filter - Type-safe filter to match documents.
1273
+ * @param update - Type-safe update operators to apply.
1274
+ * @param options - Optional settings: `returnDocument`, `upsert`, `validate`.
1275
+ * @returns The matched document (before or after update), or `null` if no document matches.
1276
+ * @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
1277
+ *
1278
+ * @example
1279
+ * ```ts
1280
+ * const users = db.use(Users)
1281
+ * const user = await users.findOneAndUpdate(
1282
+ * { name: 'Ada' },
1283
+ * { $set: { role: 'admin' } },
1284
+ * )
1285
+ * if (user) console.log(user.role) // 'admin' (returned after update)
1286
+ * ```
1287
+ */
1288
+ findOneAndUpdate(filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: FindOneAndUpdateOptions): Promise<InferDocument<TDef> | null>;
1289
+ /**
1290
+ * Delete a single document matching the filter.
1291
+ *
1292
+ * Removes the first document that matches the filter from the collection.
1293
+ * No validation is performed — the document is deleted directly through
1294
+ * the MongoDB driver.
1295
+ *
1296
+ * @param filter - Type-safe filter to match documents.
1297
+ * @returns The MongoDB `DeleteResult` with the deleted count.
1298
+ *
1299
+ * @example
1300
+ * ```ts
1301
+ * const users = db.use(Users)
1302
+ * const result = await users.deleteOne({ name: 'Ada' })
1303
+ * console.log(result.deletedCount) // 1
1304
+ * ```
1305
+ */
1306
+ deleteOne(filter: TypedFilter<InferDocument<TDef>>): Promise<DeleteResult>;
1307
+ /**
1308
+ * Delete all documents matching the filter.
1309
+ *
1310
+ * Removes every document that matches the filter from the collection.
1311
+ * No validation is performed — documents are deleted directly through
1312
+ * the MongoDB driver.
1313
+ *
1314
+ * @param filter - Type-safe filter to match documents.
1315
+ * @returns The MongoDB `DeleteResult` with the deleted count.
1316
+ *
1317
+ * @example
1318
+ * ```ts
1319
+ * const users = db.use(Users)
1320
+ * const result = await users.deleteMany({ role: 'guest' })
1321
+ * console.log(result.deletedCount) // number of guests removed
1322
+ * ```
1323
+ */
1324
+ deleteMany(filter: TypedFilter<InferDocument<TDef>>): Promise<DeleteResult>;
1325
+ /**
1326
+ * Find a single document matching the filter, delete it, and return the document.
1327
+ *
1328
+ * Returns the deleted document, or `null` if no document matches the filter.
1329
+ * The returned document is validated against the collection's Zod schema
1330
+ * using the same resolution logic as {@link findOne}.
1331
+ *
1332
+ * @param filter - Type-safe filter to match documents.
1333
+ * @param options - Optional settings: `validate`.
1334
+ * @returns The deleted document, or `null` if no document matches.
1335
+ * @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
1336
+ *
1337
+ * @example
1338
+ * ```ts
1339
+ * const users = db.use(Users)
1340
+ * const user = await users.findOneAndDelete({ name: 'Ada' })
1341
+ * if (user) console.log(user.name) // 'Ada' (the deleted document)
1342
+ * ```
1343
+ */
1344
+ findOneAndDelete(filter: TypedFilter<InferDocument<TDef>>, options?: FindOneAndDeleteOptions): Promise<InferDocument<TDef> | null>;
740
1345
  }
741
1346
 
742
1347
  /**
@@ -1047,6 +1652,62 @@ declare function oid(value: ObjectId): ObjectId;
1047
1652
  */
1048
1653
  declare function isOid(value: unknown): value is ObjectId;
1049
1654
 
1655
+ /**
1656
+ * Convenience namespace that groups all query operators under a single import.
1657
+ *
1658
+ * Property names strip the `$` prefix since the namespace itself is `$`.
1659
+ * Individual operator exports (`$or`, `$gt`, etc.) remain available for
1660
+ * tree-shaking — this namespace is the ergonomic alternative.
1661
+ *
1662
+ * @example
1663
+ * ```ts
1664
+ * import { $ } from '@zodmon/core'
1665
+ *
1666
+ * users.find($.or({ role: 'admin' }, { age: $.gte(25) }))
1667
+ * users.find({ name: $.regex(/^A/i), age: $.gt(18) })
1668
+ * users.find($.and({ published: true }, { views: $.gte(100) }))
1669
+ * ```
1670
+ */
1671
+ declare const $: {
1672
+ readonly eq: <V>(value: V) => {
1673
+ $eq: V;
1674
+ };
1675
+ readonly ne: <V>(value: V) => {
1676
+ $ne: V;
1677
+ };
1678
+ readonly gt: <V>(value: V) => {
1679
+ $gt: V;
1680
+ };
1681
+ readonly gte: <V>(value: V) => {
1682
+ $gte: V;
1683
+ };
1684
+ readonly lt: <V>(value: V) => {
1685
+ $lt: V;
1686
+ };
1687
+ readonly lte: <V>(value: V) => {
1688
+ $lte: V;
1689
+ };
1690
+ readonly in: <V>(values: V[]) => {
1691
+ $in: V[];
1692
+ };
1693
+ readonly nin: <V>(values: V[]) => {
1694
+ $nin: V[];
1695
+ };
1696
+ readonly exists: (flag?: boolean) => {
1697
+ $exists: boolean;
1698
+ };
1699
+ readonly regex: (pattern: RegExp | string) => {
1700
+ $regex: RegExp | string;
1701
+ };
1702
+ readonly not: <O extends Record<string, unknown>>(op: O) => {
1703
+ $not: O;
1704
+ };
1705
+ readonly or: <T>(...filters: NoInfer<TypedFilter<T>>[]) => TypedFilter<T>;
1706
+ readonly and: <T>(...filters: NoInfer<TypedFilter<T>>[]) => TypedFilter<T>;
1707
+ readonly nor: <T>(...filters: NoInfer<TypedFilter<T>>[]) => TypedFilter<T>;
1708
+ readonly raw: <T = any>(filter: Record<string, unknown>) => TypedFilter<T>;
1709
+ };
1710
+
1050
1711
  /**
1051
1712
  * Matches values equal to the specified value.
1052
1713
  *
@@ -1234,219 +1895,6 @@ declare const $nor: <T>(...filters: NoInfer<TypedFilter<T>>[]) => TypedFilter<T>
1234
1895
  */
1235
1896
  declare const raw: <T = any>(filter: Record<string, unknown>) => TypedFilter<T>;
1236
1897
 
1237
- /**
1238
- * Extracts the element type from an array type.
1239
- *
1240
- * @example
1241
- * ```ts
1242
- * type E = ArrayElement<string[]> // string
1243
- * type N = ArrayElement<number[]> // number
1244
- * ```
1245
- */
1246
- type ArrayElement<T> = T extends ReadonlyArray<infer E> ? E : never;
1247
- /**
1248
- * Fields valid for `$set`, `$setOnInsert`, `$min`, and `$max` operators.
1249
- *
1250
- * Allows top-level fields with matching value types plus dot-notation paths
1251
- * for nested field updates.
1252
- *
1253
- * @example
1254
- * ```ts
1255
- * const set: SetFields<User> = { name: 'Alice', 'address.city': 'NYC' }
1256
- * ```
1257
- */
1258
- type SetFields<T> = {
1259
- [K in keyof T]?: T[K];
1260
- } & {
1261
- [P in DotPaths<T>]?: DotPathType<T, P>;
1262
- };
1263
- /**
1264
- * Fields valid for the `$inc` operator — only number-typed fields.
1265
- *
1266
- * Includes dot-notation paths that resolve to number types.
1267
- *
1268
- * @example
1269
- * ```ts
1270
- * const inc: IncFields<User> = { age: 1, 'stats.views': 5 }
1271
- * ```
1272
- */
1273
- type IncFields<T> = {
1274
- [K in keyof T as NonNullable<T[K]> extends number ? K : never]?: number;
1275
- } & {
1276
- [P in DotPaths<T> as DotPathType<T, P> extends number ? P : never]?: number;
1277
- };
1278
- /**
1279
- * Modifiers for the `$push` operator.
1280
- *
1281
- * Use with `$push` to insert multiple elements and control array position/size.
1282
- *
1283
- * @example
1284
- * ```ts
1285
- * const push = { tags: { $each: ['a', 'b'], $position: 0, $slice: 10 } }
1286
- * ```
1287
- */
1288
- type PushModifiers<E> = {
1289
- /** Array of elements to push. */
1290
- $each: E[];
1291
- /** Position at which to insert elements. */
1292
- $position?: number;
1293
- /** Maximum array length after push. */
1294
- $slice?: number;
1295
- /** Sort order applied after push. */
1296
- $sort?: 1 | -1 | Record<string, 1 | -1>;
1297
- };
1298
- /**
1299
- * Fields valid for the `$push` operator — only array-typed fields.
1300
- *
1301
- * Accepts a single element value or a modifier object with `$each`.
1302
- *
1303
- * @example
1304
- * ```ts
1305
- * const push: PushFields<User> = { tags: 'dev' }
1306
- * const pushMany: PushFields<User> = { tags: { $each: ['a', 'b'] } }
1307
- * ```
1308
- */
1309
- type PushFields<T> = {
1310
- [K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: ArrayElement<NonNullable<T[K]>> | PushModifiers<ArrayElement<NonNullable<T[K]>>>;
1311
- };
1312
- /**
1313
- * Fields valid for the `$pull` operator — only array-typed fields.
1314
- *
1315
- * For primitive arrays: accepts a value or comparison operators.
1316
- * For object arrays: also accepts a `TypedFilter` on the element type.
1317
- *
1318
- * @example
1319
- * ```ts
1320
- * const pull: PullFields<User> = { tags: 'old' }
1321
- * const pullQuery: PullFields<User> = { scores: { $lt: 50 } }
1322
- * const pullObj: PullFields<User> = { comments: { author: 'spam' } }
1323
- * ```
1324
- */
1325
- type PullFields<T> = {
1326
- [K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: ArrayElement<NonNullable<T[K]>> | ComparisonOperators<ArrayElement<NonNullable<T[K]>>> | (ArrayElement<NonNullable<T[K]>> extends Record<string, unknown> ? TypedFilter<ArrayElement<NonNullable<T[K]>>> : unknown);
1327
- };
1328
- /**
1329
- * Modifier for the `$addToSet` operator's `$each` syntax.
1330
- *
1331
- * @example
1332
- * ```ts
1333
- * const addToSet = { tags: { $each: ['a', 'b'] } }
1334
- * ```
1335
- */
1336
- type AddToSetEach<E> = {
1337
- $each: E[];
1338
- };
1339
- /**
1340
- * Fields valid for the `$addToSet` operator — only array-typed fields.
1341
- *
1342
- * Accepts a single element value or `{ $each: [...] }` for multiple elements.
1343
- *
1344
- * @example
1345
- * ```ts
1346
- * const add: AddToSetFields<User> = { tags: 'dev' }
1347
- * const addMany: AddToSetFields<User> = { tags: { $each: ['a', 'b'] } }
1348
- * ```
1349
- */
1350
- type AddToSetFields<T> = {
1351
- [K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: ArrayElement<NonNullable<T[K]>> | AddToSetEach<ArrayElement<NonNullable<T[K]>>>;
1352
- };
1353
- /**
1354
- * Fields valid for the `$pop` operator — only array-typed fields.
1355
- *
1356
- * Value `1` removes the last element, `-1` removes the first.
1357
- *
1358
- * @example
1359
- * ```ts
1360
- * const pop: PopFields<User> = { tags: -1 } // remove first
1361
- * ```
1362
- */
1363
- type PopFields<T> = {
1364
- [K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: 1 | -1;
1365
- };
1366
- /**
1367
- * Fields valid for the `$unset` operator — any existing field.
1368
- *
1369
- * Value is `''`, `true`, or `1` (all mean "remove this field").
1370
- *
1371
- * @example
1372
- * ```ts
1373
- * const unset: UnsetFields<User> = { middleName: '' }
1374
- * ```
1375
- */
1376
- type UnsetFields<T> = {
1377
- [K in keyof T]?: '' | true | 1;
1378
- };
1379
- /**
1380
- * Fields valid for the `$currentDate` operator — only Date-typed fields.
1381
- *
1382
- * Sets the field to the current date. Value is `true` or `{ $type: 'date' }`.
1383
- *
1384
- * @example
1385
- * ```ts
1386
- * const cd: CurrentDateFields<User> = { createdAt: true }
1387
- * ```
1388
- */
1389
- type CurrentDateFields<T> = {
1390
- [K in keyof T as NonNullable<T[K]> extends Date ? K : never]?: true | {
1391
- $type: 'date';
1392
- };
1393
- };
1394
- /**
1395
- * Fields valid for the `$rename` operator.
1396
- *
1397
- * Renames an existing field to a new name. Key is the current field name,
1398
- * value is the new name as a string.
1399
- *
1400
- * @example
1401
- * ```ts
1402
- * const rename: RenameFields<User> = { name: 'fullName' }
1403
- * ```
1404
- */
1405
- type RenameFields<T> = {
1406
- [K in keyof T & string]?: string;
1407
- };
1408
- /**
1409
- * Strict type-safe MongoDB update filter.
1410
- *
1411
- * Validates update operators against field types at compile time. Each operator
1412
- * constrains which fields it accepts (e.g. `$inc` only on numbers, `$push` only
1413
- * on arrays). Supports dot-notation paths for nested field access.
1414
- *
1415
- * @example
1416
- * ```ts
1417
- * const update: TypedUpdateFilter<User> = {
1418
- * $set: { name: 'Alice' },
1419
- * $inc: { age: 1 },
1420
- * }
1421
- * ```
1422
- */
1423
- type TypedUpdateFilter<T> = {
1424
- /** Sets the value of one or more fields. */
1425
- $set?: SetFields<T>;
1426
- /** Sets fields only when inserting (upsert). Same typing as `$set`. */
1427
- $setOnInsert?: SetFields<T>;
1428
- /** Increments numeric fields by the given amount. Only accepts number-typed fields. */
1429
- $inc?: IncFields<T>;
1430
- /** Updates the field if the given value is less than the current value. */
1431
- $min?: SetFields<T>;
1432
- /** Updates the field if the given value is greater than the current value. */
1433
- $max?: SetFields<T>;
1434
- /** Appends a value to an array field. Supports `$each`, `$position`, `$slice`, `$sort`. */
1435
- $push?: PushFields<T>;
1436
- /** Removes matching values from an array field. */
1437
- $pull?: PullFields<T>;
1438
- /** Adds a value to an array only if it doesn't already exist. */
1439
- $addToSet?: AddToSetFields<T>;
1440
- /** Removes the first (`-1`) or last (`1`) element of an array. */
1441
- $pop?: PopFields<T>;
1442
- /** Removes the specified fields from the document. */
1443
- $unset?: UnsetFields<T>;
1444
- /** Sets the field to the current date. Only accepts Date-typed fields. */
1445
- $currentDate?: CurrentDateFields<T>;
1446
- /** Renames a field. */
1447
- $rename?: RenameFields<T>;
1448
- };
1449
-
1450
1898
  /**
1451
1899
  * Type-level marker that carries the target collection type through the
1452
1900
  * type system. Intersected with the schema return type by `.ref()` so
@@ -1524,11 +1972,70 @@ declare module 'zod' {
1524
1972
  * ```
1525
1973
  */
1526
1974
  declare function getRefMetadata(schema: unknown): RefMetadata | undefined;
1975
+
1976
+ /**
1977
+ * Shorthand for `CollectionHandle<TDef>`.
1978
+ *
1979
+ * Reduces boilerplate in function signatures that accept a collection handle.
1980
+ *
1981
+ * @example
1982
+ * ```ts
1983
+ * import { type HandleOf } from '@zodmon/core'
1984
+ *
1985
+ * const Users = collection('users', { name: z.string() })
1986
+ *
1987
+ * async function seed(users: HandleOf<typeof Users>) {
1988
+ * await users.insertOne({ name: 'Ada' })
1989
+ * }
1990
+ * ```
1991
+ */
1992
+ type HandleOf<TDef extends AnyCollection> = CollectionHandle<TDef>;
1993
+ /**
1994
+ * Shorthand for `TypedFilter<InferDocument<TDef>>`.
1995
+ *
1996
+ * Derives the filter type directly from a collection definition,
1997
+ * removing the need to compose `TypedFilter` and `InferDocument` manually.
1998
+ *
1999
+ * @example
2000
+ * ```ts
2001
+ * import { type FilterOf } from '@zodmon/core'
2002
+ *
2003
+ * const Users = collection('users', { name: z.string(), age: z.number() })
2004
+ *
2005
+ * const conditions: FilterOf<typeof Users>[] = []
2006
+ * conditions.push({ age: { $gte: 18 } })
2007
+ * ```
2008
+ */
2009
+ type FilterOf<TDef extends AnyCollection> = TypedFilter<InferDocument<TDef>>;
2010
+ /**
2011
+ * Shorthand for `TypedUpdateFilter<InferDocument<TDef>>`.
2012
+ *
2013
+ * Derives the update filter type directly from a collection definition.
2014
+ *
2015
+ * @example
2016
+ * ```ts
2017
+ * import { type UpdateFilterOf } from '@zodmon/core'
2018
+ *
2019
+ * const Users = collection('users', { name: z.string(), role: z.string() })
2020
+ *
2021
+ * const update: UpdateFilterOf<typeof Users> = { $set: { role: 'admin' } }
2022
+ * ```
2023
+ */
2024
+ type UpdateFilterOf<TDef extends AnyCollection> = TypedUpdateFilter<InferDocument<TDef>>;
1527
2025
  /**
1528
- * Install the `.ref()` extension method on `ZodType.prototype`.
2026
+ * Shorthand for `TypedSort<InferDocument<TDef>>`.
2027
+ *
2028
+ * Derives the sort specification type directly from a collection definition.
2029
+ *
2030
+ * @example
2031
+ * ```ts
2032
+ * import { type SortOf } from '@zodmon/core'
1529
2033
  *
1530
- * Idempotent safe to call multiple times.
2034
+ * const Users = collection('users', { name: z.string(), age: z.number() })
2035
+ *
2036
+ * const sort: SortOf<typeof Users> = { age: -1, name: 1 }
2037
+ * ```
1531
2038
  */
1532
- declare function installRefExtension(): void;
2039
+ type SortOf<TDef extends AnyCollection> = TypedSort<InferDocument<TDef>>;
1533
2040
 
1534
- export { $and, $eq, $exists, $gt, $gte, $in, $lt, $lte, $ne, $nin, $nor, $not, $or, $regex, type AddToSetEach, type AddToSetFields, type AnyCollection, type ArrayElement, type CollectionDefinition, CollectionHandle, type CollectionOptions, type ComparisonOperators, type CompoundIndexDefinition, type CurrentDateFields, Database, type DotPathType, type DotPaths, type FieldIndexDefinition, type FindOneOptions, type FindOptions, type IncFields, IndexBuilder, type IndexMetadata, type IndexOptions, type InferDocument, type InferInsert, type PopFields, type PullFields, type PushFields, type PushModifiers, type RefMarker, type RefMetadata, type RenameFields, type ResolvedShape, type SetFields, type TypedFilter, TypedFindCursor, type TypedSort, type TypedUpdateFilter, type UnsetFields, type ValidationMode, type ZodObjectId, ZodmonNotFoundError, ZodmonValidationError, collection, createClient, extractDbName, extractFieldIndexes, find, findOne, findOneOrThrow, getIndexMetadata, getRefMetadata, index, insertMany, insertOne, installExtensions, installRefExtension, isOid, objectId, oid, raw };
2041
+ export { $, $and, $eq, $exists, $gt, $gte, $in, $lt, $lte, $ne, $nin, $nor, $not, $or, $regex, type AddToSetEach, type AddToSetFields, type AnyCollection, type ArrayElement, type CollectionDefinition, CollectionHandle, type CollectionOptions, type ComparisonOperators, type CompoundIndexDefinition, type CurrentDateFields, type CursorPage, type CursorPaginateOptions, Database, type DotPathType, type DotPaths, type FieldIndexDefinition, type FilterOf, type FindOneAndDeleteOptions, type FindOneAndUpdateOptions, type FindOneOptions, type FindOptions, type HandleOf, type IncFields, IndexBuilder, type IndexMetadata, type IndexOptions, type InferDocument, type InferInsert, type OffsetPage, type OffsetPaginateOptions, type PopFields, type PullFields, type PushFields, type PushModifiers, type RefMarker, type RefMetadata, type RenameFields, type ResolvedShape, type SetFields, type SortOf, type TypedFilter, TypedFindCursor, type TypedSort, type TypedUpdateFilter, type UnsetFields, type UpdateFilterOf, type UpdateOptions, type ValidationMode, type ZodObjectId, ZodmonNotFoundError, ZodmonValidationError, collection, createClient, deleteMany, deleteOne, extractDbName, extractFieldIndexes, find, findOne, findOneAndDelete, findOneAndUpdate, findOneOrThrow, getIndexMetadata, getRefMetadata, index, insertMany, insertOne, isOid, objectId, oid, raw, updateMany, updateOne };