@zodmon/core 0.2.0 → 0.4.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.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { ZodPipe, ZodCustom, ZodTransform, z } from 'zod';
2
- import { ObjectId } from 'mongodb';
1
+ import { ObjectId, Collection, MongoClientOptions } from 'mongodb';
2
+ import { ZodPipe, ZodCustom, ZodTransform, z, ZodDefault } from 'zod';
3
3
 
4
4
  /**
5
5
  * Options controlling how a field-level MongoDB index is created.
@@ -225,10 +225,12 @@ type CompoundIndexDefinition<TKeys extends string = string> = {
225
225
  type FieldIndexDefinition = {
226
226
  field: string;
227
227
  } & IndexOptions;
228
+ /** Validation strategy for documents read from or written to MongoDB. */
229
+ type ValidationMode = 'strict' | 'strip' | 'passthrough';
228
230
  /** Options passed to collection() as the third argument. */
229
231
  type CollectionOptions<TKeys extends string = string> = {
230
232
  indexes?: CompoundIndexDefinition<TKeys>[];
231
- validation?: 'strict' | 'strip' | 'passthrough';
233
+ validation?: ValidationMode;
232
234
  warnUnindexedQueries?: boolean;
233
235
  schemaVersion?: number;
234
236
  migrate?: (doc: Record<string, unknown>, version: number) => Record<string, unknown>;
@@ -242,7 +244,7 @@ type CollectionOptions<TKeys extends string = string> = {
242
244
  * This allows custom id types (nanoid, UUID, etc.) when needed.
243
245
  */
244
246
  type ResolvedShape<TShape extends z.core.$ZodShape> = '_id' extends keyof TShape ? TShape : {
245
- _id: ZodObjectId;
247
+ _id: ZodDefault<ZodObjectId>;
246
248
  } & TShape;
247
249
  /**
248
250
  * The document type inferred from a collection definition.
@@ -256,6 +258,23 @@ type ResolvedShape<TShape extends z.core.$ZodShape> = '_id' extends keyof TShape
256
258
  type InferDocument<TDef extends {
257
259
  readonly schema: z.ZodType;
258
260
  }> = z.infer<TDef['schema']>;
261
+ /**
262
+ * The input type for inserting a document into a collection.
263
+ *
264
+ * Uses Zod's input type so fields with `.default()` (including the
265
+ * auto-generated `_id`) are optional. Custom `_id` fields without
266
+ * a default remain required.
267
+ *
268
+ * @example
269
+ * ```ts
270
+ * // Auto-generated _id — optional on insert
271
+ * type Insert = InferInsert<typeof Users>
272
+ * // { _id?: string | ObjectId; name: string; role?: string }
273
+ * ```
274
+ */
275
+ type InferInsert<TDef extends {
276
+ readonly schema: z.ZodType;
277
+ }> = z.input<TDef['schema']>;
259
278
  /**
260
279
  * The immutable definition object returned by collection().
261
280
  * Holds everything needed to later create a live collection handle.
@@ -271,6 +290,357 @@ type CollectionDefinition<TShape extends z.core.$ZodShape = z.core.$ZodShape> =
271
290
  /** Erased collection type for use in generic contexts. */
272
291
  type AnyCollection = CollectionDefinition<z.core.$ZodShape>;
273
292
 
293
+ /**
294
+ * Comparison operators for a field value of type `V`.
295
+ *
296
+ * Maps each MongoDB comparison operator to its expected value type.
297
+ * `$regex` is only available when `V` extends `string`.
298
+ *
299
+ * Used as the operator object that can be assigned to a field in {@link TypedFilter}.
300
+ *
301
+ * @example
302
+ * ```ts
303
+ * // As a raw object (without builder functions)
304
+ * const filter: TypedFilter<User> = { age: { $gt: 25, $lte: 65 } }
305
+ *
306
+ * // $regex only available on string fields
307
+ * const filter: TypedFilter<User> = { name: { $regex: /^A/i } }
308
+ * ```
309
+ */
310
+ type ComparisonOperators<V> = {
311
+ /** Matches values equal to the specified value. */
312
+ $eq?: V;
313
+ /** Matches values not equal to the specified value. */
314
+ $ne?: V;
315
+ /** Matches values greater than the specified value. */
316
+ $gt?: V;
317
+ /** Matches values greater than or equal to the specified value. */
318
+ $gte?: V;
319
+ /** Matches values less than the specified value. */
320
+ $lt?: V;
321
+ /** Matches values less than or equal to the specified value. */
322
+ $lte?: V;
323
+ /** Matches any value in the specified array. */
324
+ $in?: V[];
325
+ /** Matches none of the values in the specified array. */
326
+ $nin?: V[];
327
+ /** Matches documents where the field exists (`true`) or does not exist (`false`). */
328
+ $exists?: boolean;
329
+ /** Negates a comparison operator. */
330
+ $not?: ComparisonOperators<V>;
331
+ } & (V extends string ? {
332
+ $regex?: RegExp | string;
333
+ } : unknown);
334
+ /** Depth counter for limiting dot-notation recursion. Index = current depth, value = next depth. */
335
+ type Prev = [never, 0, 1, 2];
336
+ /**
337
+ * Generates a union of all valid dot-separated paths for nested object fields in `T`.
338
+ *
339
+ * Recursion is limited to 3 levels deep to prevent TypeScript compilation performance issues.
340
+ * Only plain object fields are traversed — arrays, `Date`, `RegExp`, and `ObjectId` are
341
+ * treated as leaf nodes and do not produce sub-paths.
342
+ *
343
+ * @example
344
+ * ```ts
345
+ * type User = { address: { city: string; geo: { lat: number; lng: number } } }
346
+ *
347
+ * // DotPaths<User> = 'address.city' | 'address.geo' | 'address.geo.lat' | 'address.geo.lng'
348
+ * ```
349
+ */
350
+ type DotPaths<T, Depth extends number = 3> = Depth extends 0 ? never : {
351
+ [K in keyof T & string]: NonNullable<T[K]> extends ReadonlyArray<unknown> | Date | RegExp | ObjectId ? never : NonNullable<T[K]> extends Record<string, unknown> ? `${K}.${keyof NonNullable<T[K]> & string}` | `${K}.${DotPaths<NonNullable<T[K]>, Prev[Depth]>}` : never;
352
+ }[keyof T & string];
353
+ /**
354
+ * Resolves the value type at a dot-separated path `P` within type `T`.
355
+ *
356
+ * Splits `P` on the first `.` and recursively descends into `T`'s nested types.
357
+ * Returns `never` if the path is invalid.
358
+ *
359
+ * @example
360
+ * ```ts
361
+ * type User = { address: { city: string; geo: { lat: number } } }
362
+ *
363
+ * // DotPathType<User, 'address.city'> = string
364
+ * // DotPathType<User, 'address.geo.lat'> = number
365
+ * ```
366
+ */
367
+ type DotPathType<T, P extends string> = P extends `${infer K}.${infer Rest}` ? K extends keyof T ? Rest extends keyof NonNullable<T[K]> ? NonNullable<T[K]>[Rest] : DotPathType<NonNullable<T[K]>, Rest> : never : P extends keyof T ? T[P] : never;
368
+ /**
369
+ * Strict type-safe MongoDB filter query type.
370
+ *
371
+ * Validates filter objects at compile time — rejects nonexistent fields, type mismatches,
372
+ * and invalid operator usage. Unlike the MongoDB driver's `Filter<T>`, does NOT allow
373
+ * arbitrary keys via `& Document`.
374
+ *
375
+ * Supports three forms of filter expressions:
376
+ * - **Direct field values** (implicit `$eq`): `{ name: 'Alice' }`
377
+ * - **Comparison operators**: `{ age: { $gt: 25 } }` or `{ age: $gt(25) }`
378
+ * - **Dot notation** for nested fields up to 3 levels: `{ 'address.city': 'NYC' }`
379
+ *
380
+ * Logical operators `$and`, `$or`, and `$nor` accept arrays of `TypedFilter<T>`
381
+ * for composing complex queries.
382
+ *
383
+ * @example
384
+ * ```ts
385
+ * // Simple equality
386
+ * const filter: TypedFilter<User> = { name: 'Alice' }
387
+ *
388
+ * // Builder functions mixed with object literals
389
+ * const filter: TypedFilter<User> = { age: $gte(18), role: $in(['admin', 'mod']) }
390
+ *
391
+ * // Logical composition
392
+ * const filter = $and<User>(
393
+ * $or<User>({ role: 'admin' }, { role: 'moderator' }),
394
+ * { age: $gte(18) },
395
+ * { email: $exists() },
396
+ * )
397
+ *
398
+ * // Dynamic conditional building
399
+ * const conditions: TypedFilter<User>[] = []
400
+ * if (name) conditions.push({ name })
401
+ * if (minAge) conditions.push({ age: $gte(minAge) })
402
+ * const filter = conditions.length ? $and<User>(...conditions) : {}
403
+ * ```
404
+ */
405
+ type TypedFilter<T> = {
406
+ [K in keyof T]?: T[K] | ComparisonOperators<T[K]>;
407
+ } & {
408
+ [P in DotPaths<T>]?: DotPathType<T, P> | ComparisonOperators<DotPathType<T, P>>;
409
+ } & {
410
+ /** Joins clauses with a logical AND. Matches documents that satisfy all filters. */
411
+ $and?: TypedFilter<T>[];
412
+ /** Joins clauses with a logical OR. Matches documents that satisfy at least one filter. */
413
+ $or?: TypedFilter<T>[];
414
+ /** Joins clauses with a logical NOR. Matches documents that fail all filters. */
415
+ $nor?: TypedFilter<T>[];
416
+ };
417
+
418
+ /**
419
+ * Options for {@link findOne} and {@link findOneOrThrow}.
420
+ */
421
+ type FindOneOptions = {
422
+ /** MongoDB projection — include (`1`) or exclude (`0`) fields. Typed projections deferred to v1.0. */
423
+ project?: Record<string, 0 | 1>;
424
+ /** Override the collection-level validation mode, or `false` to skip validation entirely. */
425
+ validate?: ValidationMode | false;
426
+ };
427
+ /**
428
+ * Find a single document matching the filter.
429
+ *
430
+ * Queries MongoDB, then validates the fetched document against the collection's
431
+ * Zod schema. Validation mode is resolved from the per-query option, falling
432
+ * back to the collection-level default (which defaults to `'strict'`).
433
+ *
434
+ * @param handle - The collection handle to query.
435
+ * @param filter - Type-safe filter to match documents.
436
+ * @param options - Optional projection and validation overrides.
437
+ * @returns The matched document, or `null` if no document matches.
438
+ * @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
439
+ *
440
+ * @example
441
+ * ```ts
442
+ * const user = await findOne(users, { name: 'Ada' })
443
+ * if (user) console.log(user.role) // typed as 'admin' | 'user'
444
+ * ```
445
+ */
446
+ declare function findOne<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOneOptions): Promise<InferDocument<TDef> | null>;
447
+ /**
448
+ * Find a single document matching the filter, or throw if none exists.
449
+ *
450
+ * Behaves identically to {@link findOne} but throws {@link ZodmonNotFoundError}
451
+ * instead of returning `null` when no document matches the filter.
452
+ *
453
+ * @param handle - The collection handle to query.
454
+ * @param filter - Type-safe filter to match documents.
455
+ * @param options - Optional projection and validation overrides.
456
+ * @returns The matched document (never null).
457
+ * @throws {ZodmonNotFoundError} When no document matches the filter.
458
+ * @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
459
+ *
460
+ * @example
461
+ * ```ts
462
+ * const user = await findOneOrThrow(users, { name: 'Ada' })
463
+ * console.log(user.role) // typed as 'admin' | 'user', guaranteed non-null
464
+ * ```
465
+ */
466
+ declare function findOneOrThrow<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOneOptions): Promise<InferDocument<TDef>>;
467
+
468
+ /**
469
+ * Typed wrapper around a MongoDB driver `Collection`.
470
+ *
471
+ * Created by {@link Database.use}. Holds the original `CollectionDefinition`
472
+ * (for runtime schema validation and index metadata) alongside the native
473
+ * driver collection parameterized with the inferred document type.
474
+ *
475
+ * @typeParam TDef - The collection definition type. Used to derive both
476
+ * the document type (`InferDocument`) and the insert type (`InferInsert`).
477
+ */
478
+ declare class CollectionHandle<TDef extends AnyCollection = AnyCollection> {
479
+ /** The collection definition containing schema, name, and index metadata. */
480
+ readonly definition: TDef;
481
+ /** The underlying MongoDB driver collection, typed to the inferred document type. */
482
+ readonly native: Collection<InferDocument<TDef>>;
483
+ constructor(definition: TDef, native: Collection<InferDocument<TDef>>);
484
+ /**
485
+ * Insert a single document into the collection.
486
+ *
487
+ * Validates the input against the collection's Zod schema before writing.
488
+ * Schema defaults (including auto-generated `_id`) are applied during
489
+ * validation. Returns the full document with all defaults filled in.
490
+ *
491
+ * @param doc - The document to insert. Fields with `.default()` are optional.
492
+ * @returns The inserted document with `_id` and all defaults applied.
493
+ * @throws {ZodmonValidationError} When the document fails schema validation.
494
+ *
495
+ * @example
496
+ * ```ts
497
+ * const users = db.use(Users)
498
+ * const user = await users.insertOne({ name: 'Ada' })
499
+ * console.log(user._id) // ObjectId (auto-generated)
500
+ * console.log(user.role) // 'user' (schema default)
501
+ * ```
502
+ */
503
+ insertOne(doc: InferInsert<TDef>): Promise<InferDocument<TDef>>;
504
+ /**
505
+ * Insert multiple documents into the collection.
506
+ *
507
+ * Validates every document against the collection's Zod schema before
508
+ * writing any to MongoDB. If any document fails validation, none are
509
+ * inserted (fail-fast before the driver call).
510
+ *
511
+ * @param docs - The documents to insert.
512
+ * @returns The inserted documents with `_id` and all defaults applied.
513
+ * @throws {ZodmonValidationError} When any document fails schema validation.
514
+ *
515
+ * @example
516
+ * ```ts
517
+ * const created = await users.insertMany([
518
+ * { name: 'Ada' },
519
+ * { name: 'Bob', role: 'admin' },
520
+ * ])
521
+ * ```
522
+ */
523
+ insertMany(docs: InferInsert<TDef>[]): Promise<InferDocument<TDef>[]>;
524
+ /**
525
+ * Find a single document matching the filter.
526
+ *
527
+ * Queries MongoDB, then validates the fetched document against the collection's
528
+ * Zod schema. Validation mode is resolved from the per-query option, falling
529
+ * back to the collection-level default (which defaults to `'strict'`).
530
+ *
531
+ * @param filter - Type-safe filter to match documents.
532
+ * @param options - Optional projection and validation overrides.
533
+ * @returns The matched document, or `null` if no document matches.
534
+ * @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
535
+ *
536
+ * @example
537
+ * ```ts
538
+ * const users = db.use(Users)
539
+ * const user = await users.findOne({ name: 'Ada' })
540
+ * if (user) console.log(user.role)
541
+ * ```
542
+ */
543
+ findOne(filter: TypedFilter<InferDocument<TDef>>, options?: FindOneOptions): Promise<InferDocument<TDef> | null>;
544
+ /**
545
+ * Find a single document matching the filter, or throw if none exists.
546
+ *
547
+ * Behaves identically to {@link findOne} but throws {@link ZodmonNotFoundError}
548
+ * instead of returning `null` when no document matches the filter.
549
+ *
550
+ * @param filter - Type-safe filter to match documents.
551
+ * @param options - Optional projection and validation overrides.
552
+ * @returns The matched document (never null).
553
+ * @throws {ZodmonNotFoundError} When no document matches the filter.
554
+ * @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
555
+ *
556
+ * @example
557
+ * ```ts
558
+ * const users = db.use(Users)
559
+ * const user = await users.findOneOrThrow({ name: 'Ada' })
560
+ * console.log(user.role) // guaranteed non-null
561
+ * ```
562
+ */
563
+ findOneOrThrow(filter: TypedFilter<InferDocument<TDef>>, options?: FindOneOptions): Promise<InferDocument<TDef>>;
564
+ }
565
+
566
+ /**
567
+ * Wraps a MongoDB `MongoClient` and `Db`, providing typed collection access
568
+ * through {@link CollectionHandle}s.
569
+ *
570
+ * Connection is lazy — the driver connects on the first operation, not at
571
+ * construction time. Call {@link close} for graceful shutdown.
572
+ *
573
+ * @example
574
+ * ```ts
575
+ * const db = createClient('mongodb://localhost:27017', 'myapp')
576
+ * const users = db.use(UsersCollection)
577
+ * await users.native.insertOne({ _id: oid(), name: 'Ada' })
578
+ * await db.close()
579
+ * ```
580
+ */
581
+ declare class Database {
582
+ private readonly _client;
583
+ private readonly _db;
584
+ /** Registered collection definitions, keyed by name. Used by syncIndexes(). */
585
+ private readonly _collections;
586
+ constructor(uri: string, dbName: string, options?: MongoClientOptions);
587
+ /**
588
+ * Register a collection definition and return a typed {@link CollectionHandle}.
589
+ *
590
+ * The handle's `native` property is a MongoDB `Collection<TDoc>` where `TDoc`
591
+ * is the document type inferred from the definition's Zod schema. Calling
592
+ * `use()` multiple times with the same definition is safe — each call returns
593
+ * a new lightweight handle backed by the same underlying driver collection.
594
+ *
595
+ * @param def - A collection definition created by `collection()`.
596
+ * @returns A typed collection handle for CRUD operations.
597
+ */
598
+ use<TShape extends z.core.$ZodShape>(def: CollectionDefinition<TShape>): CollectionHandle<CollectionDefinition<TShape>>;
599
+ /**
600
+ * Synchronize indexes defined in registered collections with MongoDB.
601
+ *
602
+ * Stub — full implementation in TASK-92.
603
+ */
604
+ syncIndexes(): Promise<void>;
605
+ /**
606
+ * Execute a function within a MongoDB transaction with auto-commit/rollback.
607
+ *
608
+ * Stub — full implementation in TASK-106.
609
+ */
610
+ transaction<T>(_fn: () => Promise<T>): Promise<T>;
611
+ /**
612
+ * Close the underlying `MongoClient` connection. Safe to call even if
613
+ * no connection was established (the driver handles this gracefully).
614
+ */
615
+ close(): Promise<void>;
616
+ }
617
+ /**
618
+ * Extract the database name from a MongoDB connection URI.
619
+ *
620
+ * Handles standard URIs, multi-host/replica set, SRV (`mongodb+srv://`),
621
+ * auth credentials, query parameters, and percent-encoded database names.
622
+ * Returns `undefined` when no database name is present.
623
+ */
624
+ declare function extractDbName(uri: string): string | undefined;
625
+ /**
626
+ * Create a new {@link Database} instance wrapping a MongoDB connection.
627
+ *
628
+ * The connection is lazy — the driver connects on the first operation.
629
+ * Pass any `MongoClientOptions` to configure connection pooling, timeouts, etc.
630
+ *
631
+ * When `dbName` is omitted, the database name is extracted from the URI path
632
+ * (e.g. `mongodb://localhost:27017/myapp` → `'myapp'`). If no database name
633
+ * is found in either the arguments or the URI, a warning is logged and
634
+ * MongoDB's default `'test'` database is used.
635
+ *
636
+ * @param uri - MongoDB connection string (e.g. `mongodb://localhost:27017`).
637
+ * @param dbName - The database name to use.
638
+ * @param options - Optional MongoDB driver client options.
639
+ * @returns A new `Database` instance.
640
+ */
641
+ declare function createClient(uri: string, dbName: string, options?: MongoClientOptions): Database;
642
+ declare function createClient(uri: string, options?: MongoClientOptions): Database;
643
+
274
644
  /**
275
645
  * Walk a Zod shape and extract field-level index metadata from each field.
276
646
  *
@@ -361,6 +731,103 @@ declare class IndexBuilder<TKeys extends string> {
361
731
  */
362
732
  declare function index<TKeys extends string>(fields: Record<TKeys, IndexDirection>): IndexBuilder<TKeys>;
363
733
 
734
+ /**
735
+ * Insert a single document into the collection.
736
+ *
737
+ * Validates the input against the collection's Zod schema before writing.
738
+ * Schema defaults (including auto-generated `_id`) are applied during
739
+ * validation. Returns the full document with all defaults filled in.
740
+ *
741
+ * @param handle - The collection handle to insert into.
742
+ * @param doc - The document to insert. Fields with `.default()` are optional.
743
+ * @returns The inserted document with `_id` and all defaults applied.
744
+ * @throws {ZodmonValidationError} When the document fails schema validation.
745
+ *
746
+ * @example
747
+ * ```ts
748
+ * const user = await insertOne(users, { name: 'Ada' })
749
+ * console.log(user._id) // ObjectId (auto-generated)
750
+ * console.log(user.role) // 'user' (schema default)
751
+ * ```
752
+ */
753
+ declare function insertOne<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, doc: InferInsert<TDef>): Promise<InferDocument<TDef>>;
754
+ /**
755
+ * Insert multiple documents into the collection.
756
+ *
757
+ * Validates every document against the collection's Zod schema before
758
+ * writing any to MongoDB. If any document fails validation, none are
759
+ * inserted (fail-fast before the driver call).
760
+ *
761
+ * @param handle - The collection handle to insert into.
762
+ * @param docs - The documents to insert.
763
+ * @returns The inserted documents with `_id` and all defaults applied.
764
+ * @throws {ZodmonValidationError} When any document fails schema validation.
765
+ *
766
+ * @example
767
+ * ```ts
768
+ * const users = await insertMany(handle, [
769
+ * { name: 'Ada' },
770
+ * { name: 'Bob', role: 'admin' },
771
+ * ])
772
+ * ```
773
+ */
774
+ declare function insertMany<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, docs: InferInsert<TDef>[]): Promise<InferDocument<TDef>[]>;
775
+
776
+ /**
777
+ * Thrown when a query expected to find a document returns no results.
778
+ *
779
+ * Used by {@link findOneOrThrow} when no document matches the provided filter.
780
+ * Callers can inspect `.collection` to identify which collection the query targeted.
781
+ *
782
+ * @example
783
+ * ```ts
784
+ * try {
785
+ * await users.findOneOrThrow({ name: 'nonexistent' })
786
+ * } catch (err) {
787
+ * if (err instanceof ZodmonNotFoundError) {
788
+ * console.log(err.message) // => 'Document not found in "users"'
789
+ * console.log(err.collection) // => 'users'
790
+ * }
791
+ * }
792
+ * ```
793
+ */
794
+ declare class ZodmonNotFoundError extends Error {
795
+ readonly name = "ZodmonNotFoundError";
796
+ /** The MongoDB collection name where the query found no results. */
797
+ readonly collection: string;
798
+ constructor(collection: string);
799
+ }
800
+
801
+ /**
802
+ * Thrown when a document fails Zod schema validation before a MongoDB write.
803
+ *
804
+ * Wraps the original `ZodError` with the collection name and a human-readable
805
+ * message listing each invalid field and its error. Callers can inspect
806
+ * `.zodError.issues` for programmatic access to individual failures.
807
+ *
808
+ * @example
809
+ * ```ts
810
+ * try {
811
+ * await users.insertOne({ name: 123 })
812
+ * } catch (err) {
813
+ * if (err instanceof ZodmonValidationError) {
814
+ * console.log(err.message)
815
+ * // => 'Validation failed for "users": name (Expected string, received number)'
816
+ * console.log(err.collection) // => 'users'
817
+ * console.log(err.zodError) // => ZodError with .issues array
818
+ * }
819
+ * }
820
+ * ```
821
+ */
822
+ declare class ZodmonValidationError extends Error {
823
+ readonly name = "ZodmonValidationError";
824
+ /** The MongoDB collection name where the validation failed. */
825
+ readonly collection: string;
826
+ /** The original Zod validation error with detailed issue information. */
827
+ readonly zodError: z.ZodError;
828
+ constructor(collection: string, zodError: z.ZodError);
829
+ }
830
+
364
831
  /**
365
832
  * Create or coerce a MongoDB `ObjectId`.
366
833
  *
@@ -405,6 +872,194 @@ declare function oid(value: ObjectId): ObjectId;
405
872
  */
406
873
  declare function isOid(value: unknown): value is ObjectId;
407
874
 
875
+ /**
876
+ * Matches values equal to the specified value.
877
+ *
878
+ * @example
879
+ * ```ts
880
+ * // Explicit equality (equivalent to { name: 'Alice' })
881
+ * users.find({ name: $eq('Alice') })
882
+ * ```
883
+ */
884
+ declare const $eq: <V>(value: V) => {
885
+ $eq: V;
886
+ };
887
+ /**
888
+ * Matches values not equal to the specified value.
889
+ *
890
+ * @example
891
+ * ```ts
892
+ * users.find({ role: $ne('banned') })
893
+ * ```
894
+ */
895
+ declare const $ne: <V>(value: V) => {
896
+ $ne: V;
897
+ };
898
+ /**
899
+ * Matches values greater than the specified value.
900
+ *
901
+ * @example
902
+ * ```ts
903
+ * users.find({ age: $gt(18) })
904
+ * ```
905
+ */
906
+ declare const $gt: <V>(value: V) => {
907
+ $gt: V;
908
+ };
909
+ /**
910
+ * Matches values greater than or equal to the specified value.
911
+ *
912
+ * @example
913
+ * ```ts
914
+ * users.find({ age: $gte(18) })
915
+ * ```
916
+ */
917
+ declare const $gte: <V>(value: V) => {
918
+ $gte: V;
919
+ };
920
+ /**
921
+ * Matches values less than the specified value.
922
+ *
923
+ * @example
924
+ * ```ts
925
+ * users.find({ age: $lt(65) })
926
+ * ```
927
+ */
928
+ declare const $lt: <V>(value: V) => {
929
+ $lt: V;
930
+ };
931
+ /**
932
+ * Matches values less than or equal to the specified value.
933
+ *
934
+ * @example
935
+ * ```ts
936
+ * users.find({ age: $lte(65) })
937
+ * ```
938
+ */
939
+ declare const $lte: <V>(value: V) => {
940
+ $lte: V;
941
+ };
942
+ /**
943
+ * Matches any value in the specified array.
944
+ *
945
+ * @example
946
+ * ```ts
947
+ * users.find({ role: $in(['admin', 'moderator']) })
948
+ * ```
949
+ */
950
+ declare const $in: <V>(values: V[]) => {
951
+ $in: V[];
952
+ };
953
+ /**
954
+ * Matches none of the values in the specified array.
955
+ *
956
+ * @example
957
+ * ```ts
958
+ * users.find({ role: $nin(['banned', 'suspended']) })
959
+ * ```
960
+ */
961
+ declare const $nin: <V>(values: V[]) => {
962
+ $nin: V[];
963
+ };
964
+ /**
965
+ * Matches documents where the field exists (or does not exist).
966
+ * Defaults to `true` when called with no arguments.
967
+ *
968
+ * @example
969
+ * ```ts
970
+ * // Field must exist
971
+ * users.find({ email: $exists() })
972
+ *
973
+ * // Field must not exist
974
+ * users.find({ deletedAt: $exists(false) })
975
+ * ```
976
+ */
977
+ declare const $exists: (flag?: boolean) => {
978
+ $exists: boolean;
979
+ };
980
+ /**
981
+ * Matches string values against a regular expression pattern.
982
+ * Only valid on string fields.
983
+ *
984
+ * @example
985
+ * ```ts
986
+ * users.find({ name: $regex(/^A/i) })
987
+ * users.find({ email: $regex('^admin@') })
988
+ * ```
989
+ */
990
+ declare const $regex: (pattern: RegExp | string) => {
991
+ $regex: RegExp | string;
992
+ };
993
+ /**
994
+ * Negates a comparison operator. Wraps the given operator object
995
+ * in a `$not` condition.
996
+ *
997
+ * @example
998
+ * ```ts
999
+ * // Age is NOT greater than 65
1000
+ * users.find({ age: $not($gt(65)) })
1001
+ *
1002
+ * // Name does NOT match pattern
1003
+ * users.find({ name: $not($regex(/^test/)) })
1004
+ * ```
1005
+ */
1006
+ declare const $not: <O extends Record<string, unknown>>(op: O) => {
1007
+ $not: O;
1008
+ };
1009
+ /**
1010
+ * Joins filter clauses with a logical OR. Matches documents that satisfy
1011
+ * at least one of the provided filters.
1012
+ *
1013
+ * @example
1014
+ * ```ts
1015
+ * users.find($or({ role: 'admin' }, { age: $gte(18) }))
1016
+ *
1017
+ * // Dynamic composition
1018
+ * const conditions: TypedFilter<User>[] = []
1019
+ * if (name) conditions.push({ name })
1020
+ * if (role) conditions.push({ role })
1021
+ * users.find($or(...conditions))
1022
+ * ```
1023
+ */
1024
+ declare const $or: <T>(...filters: TypedFilter<T>[]) => TypedFilter<T>;
1025
+ /**
1026
+ * Joins filter clauses with a logical AND. Matches documents that satisfy
1027
+ * all of the provided filters. Useful for dynamic filter building where
1028
+ * multiple conditions on the same field would conflict in an object literal.
1029
+ *
1030
+ * @example
1031
+ * ```ts
1032
+ * users.find($and(
1033
+ * $or({ role: 'admin' }, { role: 'moderator' }),
1034
+ * { age: $gte(18) },
1035
+ * { email: $exists() },
1036
+ * ))
1037
+ * ```
1038
+ */
1039
+ declare const $and: <T>(...filters: TypedFilter<T>[]) => TypedFilter<T>;
1040
+ /**
1041
+ * Joins filter clauses with a logical NOR. Matches documents that fail
1042
+ * all of the provided filters.
1043
+ *
1044
+ * @example
1045
+ * ```ts
1046
+ * // Exclude banned and suspended users
1047
+ * users.find($nor({ role: 'banned' }, { role: 'suspended' }))
1048
+ * ```
1049
+ */
1050
+ declare const $nor: <T>(...filters: TypedFilter<T>[]) => TypedFilter<T>;
1051
+ /**
1052
+ * Escape hatch for unsupported or raw MongoDB filter operators.
1053
+ * Wraps an untyped filter object so it can be passed where `TypedFilter<T>` is expected.
1054
+ * Use when you need operators not covered by the type system (e.g., `$text`, `$geoNear`).
1055
+ *
1056
+ * @example
1057
+ * ```ts
1058
+ * users.find(raw({ $text: { $search: 'mongodb tutorial' } }))
1059
+ * ```
1060
+ */
1061
+ declare const raw: <T = any>(filter: Record<string, unknown>) => TypedFilter<T>;
1062
+
408
1063
  /**
409
1064
  * Type-level marker that carries the target collection type through the
410
1065
  * type system. Intersected with the schema return type by `.ref()` so
@@ -489,4 +1144,4 @@ declare function getRefMetadata(schema: unknown): RefMetadata | undefined;
489
1144
  */
490
1145
  declare function installRefExtension(): void;
491
1146
 
492
- export { type AnyCollection, type CollectionDefinition, type CollectionOptions, type CompoundIndexDefinition, type FieldIndexDefinition, IndexBuilder, type IndexMetadata, type IndexOptions, type InferDocument, type RefMarker, type RefMetadata, type ResolvedShape, type ZodObjectId, collection, extractFieldIndexes, getIndexMetadata, getRefMetadata, index, installExtensions, installRefExtension, isOid, objectId, oid };
1147
+ export { $and, $eq, $exists, $gt, $gte, $in, $lt, $lte, $ne, $nin, $nor, $not, $or, $regex, type AnyCollection, type CollectionDefinition, CollectionHandle, type CollectionOptions, type ComparisonOperators, type CompoundIndexDefinition, Database, type DotPathType, type DotPaths, type FieldIndexDefinition, type FindOneOptions, IndexBuilder, type IndexMetadata, type IndexOptions, type InferDocument, type InferInsert, type RefMarker, type RefMetadata, type ResolvedShape, type TypedFilter, type ValidationMode, type ZodObjectId, ZodmonNotFoundError, ZodmonValidationError, collection, createClient, extractDbName, extractFieldIndexes, findOne, findOneOrThrow, getIndexMetadata, getRefMetadata, index, insertMany, insertOne, installExtensions, installRefExtension, isOid, objectId, oid, raw };