@zodmon/core 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +155 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +414 -2
- package/dist/index.d.ts +414 -2
- package/dist/index.js +127 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { ObjectId, Document, Collection, MongoClientOptions } from 'mongodb';
|
|
1
2
|
import { ZodPipe, ZodCustom, ZodTransform, z } from 'zod';
|
|
2
|
-
import { ObjectId } from 'mongodb';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Options controlling how a field-level MongoDB index is created.
|
|
@@ -271,6 +271,105 @@ type CollectionDefinition<TShape extends z.core.$ZodShape = z.core.$ZodShape> =
|
|
|
271
271
|
/** Erased collection type for use in generic contexts. */
|
|
272
272
|
type AnyCollection = CollectionDefinition<z.core.$ZodShape>;
|
|
273
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Typed wrapper around a MongoDB driver `Collection`.
|
|
276
|
+
*
|
|
277
|
+
* Created by {@link Database.use}. Holds the original `CollectionDefinition`
|
|
278
|
+
* (for runtime schema validation and index metadata) alongside the native
|
|
279
|
+
* driver collection parameterized with the inferred document type.
|
|
280
|
+
*
|
|
281
|
+
* CRUD methods (insertOne, find, etc.) are added to this class by
|
|
282
|
+
* subsequent modules — the handle itself is intentionally behavior-free.
|
|
283
|
+
*
|
|
284
|
+
* @typeParam TDoc - The document type inferred from the Zod schema
|
|
285
|
+
* (e.g. `{ _id: ObjectId; name: string }`). Defaults to `Document`.
|
|
286
|
+
*/
|
|
287
|
+
declare class CollectionHandle<TDoc extends Document = Document> {
|
|
288
|
+
/** The collection definition containing schema, name, and index metadata. */
|
|
289
|
+
readonly definition: AnyCollection;
|
|
290
|
+
/** The underlying MongoDB driver collection, typed to `TDoc`. */
|
|
291
|
+
readonly native: Collection<TDoc>;
|
|
292
|
+
constructor(definition: AnyCollection, native: Collection<TDoc>);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Wraps a MongoDB `MongoClient` and `Db`, providing typed collection access
|
|
297
|
+
* through {@link CollectionHandle}s.
|
|
298
|
+
*
|
|
299
|
+
* Connection is lazy — the driver connects on the first operation, not at
|
|
300
|
+
* construction time. Call {@link close} for graceful shutdown.
|
|
301
|
+
*
|
|
302
|
+
* @example
|
|
303
|
+
* ```ts
|
|
304
|
+
* const db = createClient('mongodb://localhost:27017', 'myapp')
|
|
305
|
+
* const users = db.use(UsersCollection)
|
|
306
|
+
* await users.native.insertOne({ _id: oid(), name: 'Ada' })
|
|
307
|
+
* await db.close()
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
declare class Database {
|
|
311
|
+
private readonly _client;
|
|
312
|
+
private readonly _db;
|
|
313
|
+
/** Registered collection definitions, keyed by name. Used by syncIndexes(). */
|
|
314
|
+
private readonly _collections;
|
|
315
|
+
constructor(uri: string, dbName: string, options?: MongoClientOptions);
|
|
316
|
+
/**
|
|
317
|
+
* Register a collection definition and return a typed {@link CollectionHandle}.
|
|
318
|
+
*
|
|
319
|
+
* The handle's `native` property is a MongoDB `Collection<TDoc>` where `TDoc`
|
|
320
|
+
* is the document type inferred from the definition's Zod schema. Calling
|
|
321
|
+
* `use()` multiple times with the same definition is safe — each call returns
|
|
322
|
+
* a new lightweight handle backed by the same underlying driver collection.
|
|
323
|
+
*
|
|
324
|
+
* @param def - A collection definition created by `collection()`.
|
|
325
|
+
* @returns A typed collection handle for CRUD operations.
|
|
326
|
+
*/
|
|
327
|
+
use<TShape extends z.core.$ZodShape>(def: CollectionDefinition<TShape>): CollectionHandle<InferDocument<CollectionDefinition<TShape>>>;
|
|
328
|
+
/**
|
|
329
|
+
* Synchronize indexes defined in registered collections with MongoDB.
|
|
330
|
+
*
|
|
331
|
+
* Stub — full implementation in TASK-92.
|
|
332
|
+
*/
|
|
333
|
+
syncIndexes(): Promise<void>;
|
|
334
|
+
/**
|
|
335
|
+
* Execute a function within a MongoDB transaction with auto-commit/rollback.
|
|
336
|
+
*
|
|
337
|
+
* Stub — full implementation in TASK-106.
|
|
338
|
+
*/
|
|
339
|
+
transaction<T>(_fn: () => Promise<T>): Promise<T>;
|
|
340
|
+
/**
|
|
341
|
+
* Close the underlying `MongoClient` connection. Safe to call even if
|
|
342
|
+
* no connection was established (the driver handles this gracefully).
|
|
343
|
+
*/
|
|
344
|
+
close(): Promise<void>;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Extract the database name from a MongoDB connection URI.
|
|
348
|
+
*
|
|
349
|
+
* Handles standard URIs, multi-host/replica set, SRV (`mongodb+srv://`),
|
|
350
|
+
* auth credentials, query parameters, and percent-encoded database names.
|
|
351
|
+
* Returns `undefined` when no database name is present.
|
|
352
|
+
*/
|
|
353
|
+
declare function extractDbName(uri: string): string | undefined;
|
|
354
|
+
/**
|
|
355
|
+
* Create a new {@link Database} instance wrapping a MongoDB connection.
|
|
356
|
+
*
|
|
357
|
+
* The connection is lazy — the driver connects on the first operation.
|
|
358
|
+
* Pass any `MongoClientOptions` to configure connection pooling, timeouts, etc.
|
|
359
|
+
*
|
|
360
|
+
* When `dbName` is omitted, the database name is extracted from the URI path
|
|
361
|
+
* (e.g. `mongodb://localhost:27017/myapp` → `'myapp'`). If no database name
|
|
362
|
+
* is found in either the arguments or the URI, a warning is logged and
|
|
363
|
+
* MongoDB's default `'test'` database is used.
|
|
364
|
+
*
|
|
365
|
+
* @param uri - MongoDB connection string (e.g. `mongodb://localhost:27017`).
|
|
366
|
+
* @param dbName - The database name to use.
|
|
367
|
+
* @param options - Optional MongoDB driver client options.
|
|
368
|
+
* @returns A new `Database` instance.
|
|
369
|
+
*/
|
|
370
|
+
declare function createClient(uri: string, dbName: string, options?: MongoClientOptions): Database;
|
|
371
|
+
declare function createClient(uri: string, options?: MongoClientOptions): Database;
|
|
372
|
+
|
|
274
373
|
/**
|
|
275
374
|
* Walk a Zod shape and extract field-level index metadata from each field.
|
|
276
375
|
*
|
|
@@ -405,6 +504,319 @@ declare function oid(value: ObjectId): ObjectId;
|
|
|
405
504
|
*/
|
|
406
505
|
declare function isOid(value: unknown): value is ObjectId;
|
|
407
506
|
|
|
507
|
+
/**
|
|
508
|
+
* Comparison operators for a field value of type `V`.
|
|
509
|
+
*
|
|
510
|
+
* Maps each MongoDB comparison operator to its expected value type.
|
|
511
|
+
* `$regex` is only available when `V` extends `string`.
|
|
512
|
+
*
|
|
513
|
+
* Used as the operator object that can be assigned to a field in {@link TypedFilter}.
|
|
514
|
+
*
|
|
515
|
+
* @example
|
|
516
|
+
* ```ts
|
|
517
|
+
* // As a raw object (without builder functions)
|
|
518
|
+
* const filter: TypedFilter<User> = { age: { $gt: 25, $lte: 65 } }
|
|
519
|
+
*
|
|
520
|
+
* // $regex only available on string fields
|
|
521
|
+
* const filter: TypedFilter<User> = { name: { $regex: /^A/i } }
|
|
522
|
+
* ```
|
|
523
|
+
*/
|
|
524
|
+
type ComparisonOperators<V> = {
|
|
525
|
+
/** Matches values equal to the specified value. */
|
|
526
|
+
$eq?: V;
|
|
527
|
+
/** Matches values not equal to the specified value. */
|
|
528
|
+
$ne?: V;
|
|
529
|
+
/** Matches values greater than the specified value. */
|
|
530
|
+
$gt?: V;
|
|
531
|
+
/** Matches values greater than or equal to the specified value. */
|
|
532
|
+
$gte?: V;
|
|
533
|
+
/** Matches values less than the specified value. */
|
|
534
|
+
$lt?: V;
|
|
535
|
+
/** Matches values less than or equal to the specified value. */
|
|
536
|
+
$lte?: V;
|
|
537
|
+
/** Matches any value in the specified array. */
|
|
538
|
+
$in?: V[];
|
|
539
|
+
/** Matches none of the values in the specified array. */
|
|
540
|
+
$nin?: V[];
|
|
541
|
+
/** Matches documents where the field exists (`true`) or does not exist (`false`). */
|
|
542
|
+
$exists?: boolean;
|
|
543
|
+
/** Negates a comparison operator. */
|
|
544
|
+
$not?: ComparisonOperators<V>;
|
|
545
|
+
} & (V extends string ? {
|
|
546
|
+
$regex?: RegExp | string;
|
|
547
|
+
} : unknown);
|
|
548
|
+
/** Depth counter for limiting dot-notation recursion. Index = current depth, value = next depth. */
|
|
549
|
+
type Prev = [never, 0, 1, 2];
|
|
550
|
+
/**
|
|
551
|
+
* Generates a union of all valid dot-separated paths for nested object fields in `T`.
|
|
552
|
+
*
|
|
553
|
+
* Recursion is limited to 3 levels deep to prevent TypeScript compilation performance issues.
|
|
554
|
+
* Only plain object fields are traversed — arrays, `Date`, `RegExp`, and `ObjectId` are
|
|
555
|
+
* treated as leaf nodes and do not produce sub-paths.
|
|
556
|
+
*
|
|
557
|
+
* @example
|
|
558
|
+
* ```ts
|
|
559
|
+
* type User = { address: { city: string; geo: { lat: number; lng: number } } }
|
|
560
|
+
*
|
|
561
|
+
* // DotPaths<User> = 'address.city' | 'address.geo' | 'address.geo.lat' | 'address.geo.lng'
|
|
562
|
+
* ```
|
|
563
|
+
*/
|
|
564
|
+
type DotPaths<T, Depth extends number = 3> = Depth extends 0 ? never : {
|
|
565
|
+
[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;
|
|
566
|
+
}[keyof T & string];
|
|
567
|
+
/**
|
|
568
|
+
* Resolves the value type at a dot-separated path `P` within type `T`.
|
|
569
|
+
*
|
|
570
|
+
* Splits `P` on the first `.` and recursively descends into `T`'s nested types.
|
|
571
|
+
* Returns `never` if the path is invalid.
|
|
572
|
+
*
|
|
573
|
+
* @example
|
|
574
|
+
* ```ts
|
|
575
|
+
* type User = { address: { city: string; geo: { lat: number } } }
|
|
576
|
+
*
|
|
577
|
+
* // DotPathType<User, 'address.city'> = string
|
|
578
|
+
* // DotPathType<User, 'address.geo.lat'> = number
|
|
579
|
+
* ```
|
|
580
|
+
*/
|
|
581
|
+
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;
|
|
582
|
+
/**
|
|
583
|
+
* Strict type-safe MongoDB filter query type.
|
|
584
|
+
*
|
|
585
|
+
* Validates filter objects at compile time — rejects nonexistent fields, type mismatches,
|
|
586
|
+
* and invalid operator usage. Unlike the MongoDB driver's `Filter<T>`, does NOT allow
|
|
587
|
+
* arbitrary keys via `& Document`.
|
|
588
|
+
*
|
|
589
|
+
* Supports three forms of filter expressions:
|
|
590
|
+
* - **Direct field values** (implicit `$eq`): `{ name: 'Alice' }`
|
|
591
|
+
* - **Comparison operators**: `{ age: { $gt: 25 } }` or `{ age: $gt(25) }`
|
|
592
|
+
* - **Dot notation** for nested fields up to 3 levels: `{ 'address.city': 'NYC' }`
|
|
593
|
+
*
|
|
594
|
+
* Logical operators `$and`, `$or`, and `$nor` accept arrays of `TypedFilter<T>`
|
|
595
|
+
* for composing complex queries.
|
|
596
|
+
*
|
|
597
|
+
* @example
|
|
598
|
+
* ```ts
|
|
599
|
+
* // Simple equality
|
|
600
|
+
* const filter: TypedFilter<User> = { name: 'Alice' }
|
|
601
|
+
*
|
|
602
|
+
* // Builder functions mixed with object literals
|
|
603
|
+
* const filter: TypedFilter<User> = { age: $gte(18), role: $in(['admin', 'mod']) }
|
|
604
|
+
*
|
|
605
|
+
* // Logical composition
|
|
606
|
+
* const filter = $and<User>(
|
|
607
|
+
* $or<User>({ role: 'admin' }, { role: 'moderator' }),
|
|
608
|
+
* { age: $gte(18) },
|
|
609
|
+
* { email: $exists() },
|
|
610
|
+
* )
|
|
611
|
+
*
|
|
612
|
+
* // Dynamic conditional building
|
|
613
|
+
* const conditions: TypedFilter<User>[] = []
|
|
614
|
+
* if (name) conditions.push({ name })
|
|
615
|
+
* if (minAge) conditions.push({ age: $gte(minAge) })
|
|
616
|
+
* const filter = conditions.length ? $and<User>(...conditions) : {}
|
|
617
|
+
* ```
|
|
618
|
+
*/
|
|
619
|
+
type TypedFilter<T> = {
|
|
620
|
+
[K in keyof T]?: T[K] | ComparisonOperators<T[K]>;
|
|
621
|
+
} & {
|
|
622
|
+
[P in DotPaths<T>]?: DotPathType<T, P> | ComparisonOperators<DotPathType<T, P>>;
|
|
623
|
+
} & {
|
|
624
|
+
/** Joins clauses with a logical AND. Matches documents that satisfy all filters. */
|
|
625
|
+
$and?: TypedFilter<T>[];
|
|
626
|
+
/** Joins clauses with a logical OR. Matches documents that satisfy at least one filter. */
|
|
627
|
+
$or?: TypedFilter<T>[];
|
|
628
|
+
/** Joins clauses with a logical NOR. Matches documents that fail all filters. */
|
|
629
|
+
$nor?: TypedFilter<T>[];
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Matches values equal to the specified value.
|
|
634
|
+
*
|
|
635
|
+
* @example
|
|
636
|
+
* ```ts
|
|
637
|
+
* // Explicit equality (equivalent to { name: 'Alice' })
|
|
638
|
+
* users.find({ name: $eq('Alice') })
|
|
639
|
+
* ```
|
|
640
|
+
*/
|
|
641
|
+
declare const $eq: <V>(value: V) => {
|
|
642
|
+
$eq: V;
|
|
643
|
+
};
|
|
644
|
+
/**
|
|
645
|
+
* Matches values not equal to the specified value.
|
|
646
|
+
*
|
|
647
|
+
* @example
|
|
648
|
+
* ```ts
|
|
649
|
+
* users.find({ role: $ne('banned') })
|
|
650
|
+
* ```
|
|
651
|
+
*/
|
|
652
|
+
declare const $ne: <V>(value: V) => {
|
|
653
|
+
$ne: V;
|
|
654
|
+
};
|
|
655
|
+
/**
|
|
656
|
+
* Matches values greater than the specified value.
|
|
657
|
+
*
|
|
658
|
+
* @example
|
|
659
|
+
* ```ts
|
|
660
|
+
* users.find({ age: $gt(18) })
|
|
661
|
+
* ```
|
|
662
|
+
*/
|
|
663
|
+
declare const $gt: <V>(value: V) => {
|
|
664
|
+
$gt: V;
|
|
665
|
+
};
|
|
666
|
+
/**
|
|
667
|
+
* Matches values greater than or equal to the specified value.
|
|
668
|
+
*
|
|
669
|
+
* @example
|
|
670
|
+
* ```ts
|
|
671
|
+
* users.find({ age: $gte(18) })
|
|
672
|
+
* ```
|
|
673
|
+
*/
|
|
674
|
+
declare const $gte: <V>(value: V) => {
|
|
675
|
+
$gte: V;
|
|
676
|
+
};
|
|
677
|
+
/**
|
|
678
|
+
* Matches values less than the specified value.
|
|
679
|
+
*
|
|
680
|
+
* @example
|
|
681
|
+
* ```ts
|
|
682
|
+
* users.find({ age: $lt(65) })
|
|
683
|
+
* ```
|
|
684
|
+
*/
|
|
685
|
+
declare const $lt: <V>(value: V) => {
|
|
686
|
+
$lt: V;
|
|
687
|
+
};
|
|
688
|
+
/**
|
|
689
|
+
* Matches values less than or equal to the specified value.
|
|
690
|
+
*
|
|
691
|
+
* @example
|
|
692
|
+
* ```ts
|
|
693
|
+
* users.find({ age: $lte(65) })
|
|
694
|
+
* ```
|
|
695
|
+
*/
|
|
696
|
+
declare const $lte: <V>(value: V) => {
|
|
697
|
+
$lte: V;
|
|
698
|
+
};
|
|
699
|
+
/**
|
|
700
|
+
* Matches any value in the specified array.
|
|
701
|
+
*
|
|
702
|
+
* @example
|
|
703
|
+
* ```ts
|
|
704
|
+
* users.find({ role: $in(['admin', 'moderator']) })
|
|
705
|
+
* ```
|
|
706
|
+
*/
|
|
707
|
+
declare const $in: <V>(values: V[]) => {
|
|
708
|
+
$in: V[];
|
|
709
|
+
};
|
|
710
|
+
/**
|
|
711
|
+
* Matches none of the values in the specified array.
|
|
712
|
+
*
|
|
713
|
+
* @example
|
|
714
|
+
* ```ts
|
|
715
|
+
* users.find({ role: $nin(['banned', 'suspended']) })
|
|
716
|
+
* ```
|
|
717
|
+
*/
|
|
718
|
+
declare const $nin: <V>(values: V[]) => {
|
|
719
|
+
$nin: V[];
|
|
720
|
+
};
|
|
721
|
+
/**
|
|
722
|
+
* Matches documents where the field exists (or does not exist).
|
|
723
|
+
* Defaults to `true` when called with no arguments.
|
|
724
|
+
*
|
|
725
|
+
* @example
|
|
726
|
+
* ```ts
|
|
727
|
+
* // Field must exist
|
|
728
|
+
* users.find({ email: $exists() })
|
|
729
|
+
*
|
|
730
|
+
* // Field must not exist
|
|
731
|
+
* users.find({ deletedAt: $exists(false) })
|
|
732
|
+
* ```
|
|
733
|
+
*/
|
|
734
|
+
declare const $exists: (flag?: boolean) => {
|
|
735
|
+
$exists: boolean;
|
|
736
|
+
};
|
|
737
|
+
/**
|
|
738
|
+
* Matches string values against a regular expression pattern.
|
|
739
|
+
* Only valid on string fields.
|
|
740
|
+
*
|
|
741
|
+
* @example
|
|
742
|
+
* ```ts
|
|
743
|
+
* users.find({ name: $regex(/^A/i) })
|
|
744
|
+
* users.find({ email: $regex('^admin@') })
|
|
745
|
+
* ```
|
|
746
|
+
*/
|
|
747
|
+
declare const $regex: (pattern: RegExp | string) => {
|
|
748
|
+
$regex: RegExp | string;
|
|
749
|
+
};
|
|
750
|
+
/**
|
|
751
|
+
* Negates a comparison operator. Wraps the given operator object
|
|
752
|
+
* in a `$not` condition.
|
|
753
|
+
*
|
|
754
|
+
* @example
|
|
755
|
+
* ```ts
|
|
756
|
+
* // Age is NOT greater than 65
|
|
757
|
+
* users.find({ age: $not($gt(65)) })
|
|
758
|
+
*
|
|
759
|
+
* // Name does NOT match pattern
|
|
760
|
+
* users.find({ name: $not($regex(/^test/)) })
|
|
761
|
+
* ```
|
|
762
|
+
*/
|
|
763
|
+
declare const $not: <O extends Record<string, unknown>>(op: O) => {
|
|
764
|
+
$not: O;
|
|
765
|
+
};
|
|
766
|
+
/**
|
|
767
|
+
* Joins filter clauses with a logical OR. Matches documents that satisfy
|
|
768
|
+
* at least one of the provided filters.
|
|
769
|
+
*
|
|
770
|
+
* @example
|
|
771
|
+
* ```ts
|
|
772
|
+
* users.find($or({ role: 'admin' }, { age: $gte(18) }))
|
|
773
|
+
*
|
|
774
|
+
* // Dynamic composition
|
|
775
|
+
* const conditions: TypedFilter<User>[] = []
|
|
776
|
+
* if (name) conditions.push({ name })
|
|
777
|
+
* if (role) conditions.push({ role })
|
|
778
|
+
* users.find($or(...conditions))
|
|
779
|
+
* ```
|
|
780
|
+
*/
|
|
781
|
+
declare const $or: <T>(...filters: TypedFilter<T>[]) => TypedFilter<T>;
|
|
782
|
+
/**
|
|
783
|
+
* Joins filter clauses with a logical AND. Matches documents that satisfy
|
|
784
|
+
* all of the provided filters. Useful for dynamic filter building where
|
|
785
|
+
* multiple conditions on the same field would conflict in an object literal.
|
|
786
|
+
*
|
|
787
|
+
* @example
|
|
788
|
+
* ```ts
|
|
789
|
+
* users.find($and(
|
|
790
|
+
* $or({ role: 'admin' }, { role: 'moderator' }),
|
|
791
|
+
* { age: $gte(18) },
|
|
792
|
+
* { email: $exists() },
|
|
793
|
+
* ))
|
|
794
|
+
* ```
|
|
795
|
+
*/
|
|
796
|
+
declare const $and: <T>(...filters: TypedFilter<T>[]) => TypedFilter<T>;
|
|
797
|
+
/**
|
|
798
|
+
* Joins filter clauses with a logical NOR. Matches documents that fail
|
|
799
|
+
* all of the provided filters.
|
|
800
|
+
*
|
|
801
|
+
* @example
|
|
802
|
+
* ```ts
|
|
803
|
+
* // Exclude banned and suspended users
|
|
804
|
+
* users.find($nor({ role: 'banned' }, { role: 'suspended' }))
|
|
805
|
+
* ```
|
|
806
|
+
*/
|
|
807
|
+
declare const $nor: <T>(...filters: TypedFilter<T>[]) => TypedFilter<T>;
|
|
808
|
+
/**
|
|
809
|
+
* Escape hatch for unsupported or raw MongoDB filter operators.
|
|
810
|
+
* Wraps an untyped filter object so it can be passed where `TypedFilter<T>` is expected.
|
|
811
|
+
* Use when you need operators not covered by the type system (e.g., `$text`, `$geoNear`).
|
|
812
|
+
*
|
|
813
|
+
* @example
|
|
814
|
+
* ```ts
|
|
815
|
+
* users.find(raw({ $text: { $search: 'mongodb tutorial' } }))
|
|
816
|
+
* ```
|
|
817
|
+
*/
|
|
818
|
+
declare const raw: <T = any>(filter: Record<string, unknown>) => TypedFilter<T>;
|
|
819
|
+
|
|
408
820
|
/**
|
|
409
821
|
* Type-level marker that carries the target collection type through the
|
|
410
822
|
* type system. Intersected with the schema return type by `.ref()` so
|
|
@@ -489,4 +901,4 @@ declare function getRefMetadata(schema: unknown): RefMetadata | undefined;
|
|
|
489
901
|
*/
|
|
490
902
|
declare function installRefExtension(): void;
|
|
491
903
|
|
|
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 };
|
|
904
|
+
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, IndexBuilder, type IndexMetadata, type IndexOptions, type InferDocument, type RefMarker, type RefMetadata, type ResolvedShape, type TypedFilter, type ZodObjectId, collection, createClient, extractDbName, extractFieldIndexes, getIndexMetadata, getRefMetadata, index, installExtensions, installRefExtension, isOid, objectId, oid, raw };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,89 @@
|
|
|
1
|
+
// src/client/client.ts
|
|
2
|
+
import { MongoClient } from "mongodb";
|
|
3
|
+
|
|
4
|
+
// src/client/handle.ts
|
|
5
|
+
var CollectionHandle = class {
|
|
6
|
+
/** The collection definition containing schema, name, and index metadata. */
|
|
7
|
+
definition;
|
|
8
|
+
/** The underlying MongoDB driver collection, typed to `TDoc`. */
|
|
9
|
+
native;
|
|
10
|
+
constructor(definition, native) {
|
|
11
|
+
this.definition = definition;
|
|
12
|
+
this.native = native;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/client/client.ts
|
|
17
|
+
var Database = class {
|
|
18
|
+
_client;
|
|
19
|
+
_db;
|
|
20
|
+
/** Registered collection definitions, keyed by name. Used by syncIndexes(). */
|
|
21
|
+
_collections = /* @__PURE__ */ new Map();
|
|
22
|
+
constructor(uri, dbName, options) {
|
|
23
|
+
this._client = new MongoClient(uri, options);
|
|
24
|
+
this._db = this._client.db(dbName);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Register a collection definition and return a typed {@link CollectionHandle}.
|
|
28
|
+
*
|
|
29
|
+
* The handle's `native` property is a MongoDB `Collection<TDoc>` where `TDoc`
|
|
30
|
+
* is the document type inferred from the definition's Zod schema. Calling
|
|
31
|
+
* `use()` multiple times with the same definition is safe — each call returns
|
|
32
|
+
* a new lightweight handle backed by the same underlying driver collection.
|
|
33
|
+
*
|
|
34
|
+
* @param def - A collection definition created by `collection()`.
|
|
35
|
+
* @returns A typed collection handle for CRUD operations.
|
|
36
|
+
*/
|
|
37
|
+
use(def) {
|
|
38
|
+
this._collections.set(def.name, def);
|
|
39
|
+
const native = this._db.collection(def.name);
|
|
40
|
+
return new CollectionHandle(def, native);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Synchronize indexes defined in registered collections with MongoDB.
|
|
44
|
+
*
|
|
45
|
+
* Stub — full implementation in TASK-92.
|
|
46
|
+
*/
|
|
47
|
+
syncIndexes() {
|
|
48
|
+
return Promise.resolve();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Execute a function within a MongoDB transaction with auto-commit/rollback.
|
|
52
|
+
*
|
|
53
|
+
* Stub — full implementation in TASK-106.
|
|
54
|
+
*/
|
|
55
|
+
transaction(_fn) {
|
|
56
|
+
throw new Error("Not implemented");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Close the underlying `MongoClient` connection. Safe to call even if
|
|
60
|
+
* no connection was established (the driver handles this gracefully).
|
|
61
|
+
*/
|
|
62
|
+
async close() {
|
|
63
|
+
await this._client.close();
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
function extractDbName(uri) {
|
|
67
|
+
const withoutProtocol = uri.replace(/^mongodb(?:\+srv)?:\/\//, "");
|
|
68
|
+
const withoutQuery = withoutProtocol.split("?")[0];
|
|
69
|
+
const atIndex = withoutQuery.lastIndexOf("@");
|
|
70
|
+
const hostAndPath = atIndex === -1 ? withoutQuery : withoutQuery.slice(atIndex + 1);
|
|
71
|
+
const slashIndex = hostAndPath.indexOf("/");
|
|
72
|
+
if (slashIndex === -1) return void 0;
|
|
73
|
+
const dbName = decodeURIComponent(hostAndPath.slice(slashIndex + 1));
|
|
74
|
+
return dbName || void 0;
|
|
75
|
+
}
|
|
76
|
+
function createClient(uri, dbNameOrOptions, maybeOptions) {
|
|
77
|
+
if (typeof dbNameOrOptions === "string") {
|
|
78
|
+
return new Database(uri, dbNameOrOptions, maybeOptions);
|
|
79
|
+
}
|
|
80
|
+
const parsed = extractDbName(uri);
|
|
81
|
+
if (!parsed) {
|
|
82
|
+
console.warn('[zodmon] No database name provided \u2014 using MongoDB default "test"');
|
|
83
|
+
}
|
|
84
|
+
return new Database(uri, parsed ?? "test", dbNameOrOptions);
|
|
85
|
+
}
|
|
86
|
+
|
|
1
87
|
// src/collection/collection.ts
|
|
2
88
|
import { z as z4 } from "zod";
|
|
3
89
|
|
|
@@ -221,9 +307,48 @@ function oid(value) {
|
|
|
221
307
|
function isOid(value) {
|
|
222
308
|
return value instanceof ObjectId2;
|
|
223
309
|
}
|
|
310
|
+
|
|
311
|
+
// src/query/operators.ts
|
|
312
|
+
var $eq = (value) => ({ $eq: value });
|
|
313
|
+
var $ne = (value) => ({ $ne: value });
|
|
314
|
+
var $gt = (value) => ({ $gt: value });
|
|
315
|
+
var $gte = (value) => ({ $gte: value });
|
|
316
|
+
var $lt = (value) => ({ $lt: value });
|
|
317
|
+
var $lte = (value) => ({ $lte: value });
|
|
318
|
+
var $in = (values) => ({ $in: values });
|
|
319
|
+
var $nin = (values) => ({ $nin: values });
|
|
320
|
+
var $exists = (flag = true) => ({ $exists: flag });
|
|
321
|
+
var $regex = (pattern) => ({
|
|
322
|
+
$regex: pattern
|
|
323
|
+
});
|
|
324
|
+
var $not = (op) => ({
|
|
325
|
+
$not: op
|
|
326
|
+
});
|
|
327
|
+
var $or = (...filters) => ({ $or: filters });
|
|
328
|
+
var $and = (...filters) => ({ $and: filters });
|
|
329
|
+
var $nor = (...filters) => ({ $nor: filters });
|
|
330
|
+
var raw = (filter) => filter;
|
|
224
331
|
export {
|
|
332
|
+
$and,
|
|
333
|
+
$eq,
|
|
334
|
+
$exists,
|
|
335
|
+
$gt,
|
|
336
|
+
$gte,
|
|
337
|
+
$in,
|
|
338
|
+
$lt,
|
|
339
|
+
$lte,
|
|
340
|
+
$ne,
|
|
341
|
+
$nin,
|
|
342
|
+
$nor,
|
|
343
|
+
$not,
|
|
344
|
+
$or,
|
|
345
|
+
$regex,
|
|
346
|
+
CollectionHandle,
|
|
347
|
+
Database,
|
|
225
348
|
IndexBuilder,
|
|
226
349
|
collection,
|
|
350
|
+
createClient,
|
|
351
|
+
extractDbName,
|
|
227
352
|
extractFieldIndexes,
|
|
228
353
|
getIndexMetadata,
|
|
229
354
|
getRefMetadata,
|
|
@@ -232,6 +357,7 @@ export {
|
|
|
232
357
|
installRefExtension,
|
|
233
358
|
isOid,
|
|
234
359
|
objectId,
|
|
235
|
-
oid
|
|
360
|
+
oid,
|
|
361
|
+
raw
|
|
236
362
|
};
|
|
237
363
|
//# sourceMappingURL=index.js.map
|