@zodmon/core 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +703 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1375 -444
- package/dist/index.d.ts +1375 -444
- package/dist/index.js +686 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
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
|
|
@@ -278,135 +252,132 @@ type InferInsert<TDef extends {
|
|
|
278
252
|
/**
|
|
279
253
|
* The immutable definition object returned by collection().
|
|
280
254
|
* Holds everything needed to later create a live collection handle.
|
|
255
|
+
*
|
|
256
|
+
* @typeParam TShape - The Zod shape defining document fields.
|
|
257
|
+
* @typeParam TIndexes - The compound indexes array type, preserving literal name types.
|
|
281
258
|
*/
|
|
282
|
-
type CollectionDefinition<TShape extends z.core.$ZodShape = z.core.$ZodShape> = {
|
|
259
|
+
type CollectionDefinition<TShape extends z.core.$ZodShape = z.core.$ZodShape, TIndexes extends readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[] = readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[]> = {
|
|
283
260
|
readonly name: string;
|
|
284
261
|
readonly schema: z.ZodObject<ResolvedShape<TShape>>;
|
|
285
262
|
readonly shape: TShape;
|
|
286
263
|
readonly fieldIndexes: FieldIndexDefinition[];
|
|
287
|
-
readonly compoundIndexes:
|
|
264
|
+
readonly compoundIndexes: TIndexes;
|
|
288
265
|
readonly options: Required<Pick<CollectionOptions, 'validation'>> & Omit<CollectionOptions, 'indexes' | 'validation'>;
|
|
289
266
|
};
|
|
290
267
|
/** Erased collection type for use in generic contexts. */
|
|
291
268
|
type AnyCollection = CollectionDefinition<z.core.$ZodShape>;
|
|
292
|
-
|
|
293
269
|
/**
|
|
294
|
-
*
|
|
270
|
+
* Extract declared index names from a collection definition.
|
|
295
271
|
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
272
|
+
* Walks the `compoundIndexes` tuple and extracts the literal `name` string
|
|
273
|
+
* from each index that declared one via `.name()`. Falls back to `string`
|
|
274
|
+
* when no compound indexes have names, allowing any string as a hint.
|
|
298
275
|
*
|
|
299
276
|
* @example
|
|
300
277
|
* ```ts
|
|
301
|
-
* const
|
|
278
|
+
* const Users = collection('users', { email: z.string() }, {
|
|
279
|
+
* indexes: [
|
|
280
|
+
* index({ email: 1 }).name('email_idx'),
|
|
281
|
+
* ],
|
|
282
|
+
* })
|
|
283
|
+
* type Names = IndexNames<typeof Users> // 'email_idx'
|
|
302
284
|
* ```
|
|
303
285
|
*/
|
|
304
|
-
type
|
|
286
|
+
type IndexNames<TDef extends {
|
|
287
|
+
readonly compoundIndexes: readonly {
|
|
288
|
+
options?: {
|
|
289
|
+
name?: string;
|
|
290
|
+
};
|
|
291
|
+
}[];
|
|
292
|
+
}> = ExtractNames<TDef['compoundIndexes']> extends never ? string : ExtractNames<TDef['compoundIndexes']>;
|
|
293
|
+
/** @internal Helper that extracts the `name` literal from each index in a tuple. */
|
|
294
|
+
type ExtractNames<T extends readonly {
|
|
295
|
+
options?: {
|
|
296
|
+
name?: string;
|
|
297
|
+
};
|
|
298
|
+
}[]> = {
|
|
299
|
+
[K in keyof T]: T[K] extends {
|
|
300
|
+
readonly options: {
|
|
301
|
+
readonly name: infer N;
|
|
302
|
+
};
|
|
303
|
+
} ? N extends string ? N : never : never;
|
|
304
|
+
}[number];
|
|
305
|
+
|
|
305
306
|
/**
|
|
306
|
-
*
|
|
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.
|
|
307
|
+
* Options controlling how {@link syncIndexes} behaves.
|
|
316
308
|
*
|
|
317
309
|
* @example
|
|
318
310
|
* ```ts
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
* .limit(10)
|
|
322
|
-
* .toArray()
|
|
311
|
+
* await users.syncIndexes({ dryRun: true })
|
|
312
|
+
* await users.syncIndexes({ dropOrphaned: true })
|
|
323
313
|
* ```
|
|
324
314
|
*/
|
|
325
|
-
|
|
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;
|
|
315
|
+
type SyncIndexesOptions = {
|
|
375
316
|
/**
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
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
|
-
* ```
|
|
317
|
+
* When `true`, compute the diff without actually creating, dropping, or
|
|
318
|
+
* modifying any indexes. The returned {@link SyncIndexesResult} shows what
|
|
319
|
+
* *would* happen.
|
|
388
320
|
*/
|
|
389
|
-
|
|
321
|
+
dryRun?: boolean;
|
|
390
322
|
/**
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
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
|
-
* ```
|
|
323
|
+
* When `true`, drop indexes that exist in MongoDB but are not declared in
|
|
324
|
+
* the schema. Also drops and recreates stale indexes (same key, different
|
|
325
|
+
* options). When `false` (the default), orphaned and stale indexes are
|
|
326
|
+
* reported but left untouched.
|
|
405
327
|
*/
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
328
|
+
dropOrphaned?: boolean;
|
|
329
|
+
};
|
|
330
|
+
/**
|
|
331
|
+
* Describes an index whose key matches a desired index but whose options differ.
|
|
332
|
+
*
|
|
333
|
+
* Returned in {@link SyncIndexesResult.stale} so the caller can decide whether
|
|
334
|
+
* to manually reconcile or re-run with `dropOrphaned: true`.
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* ```ts
|
|
338
|
+
* const result = await users.syncIndexes()
|
|
339
|
+
* for (const s of result.stale) {
|
|
340
|
+
* console.log(`${s.name}: key=${JSON.stringify(s.key)}`)
|
|
341
|
+
* console.log(` existing=${JSON.stringify(s.existing)}`)
|
|
342
|
+
* console.log(` desired=${JSON.stringify(s.desired)}`)
|
|
343
|
+
* }
|
|
344
|
+
* ```
|
|
345
|
+
*/
|
|
346
|
+
type StaleIndex = {
|
|
347
|
+
/** The MongoDB index name (e.g. `'email_1'`). */
|
|
348
|
+
name: string;
|
|
349
|
+
/** The index key spec (e.g. `{ email: 1 }`). */
|
|
350
|
+
key: Record<string, 1 | -1 | 'text'>;
|
|
351
|
+
/** The relevant options currently set on the existing index. */
|
|
352
|
+
existing: Record<string, unknown>;
|
|
353
|
+
/** The options the schema declares for this index. */
|
|
354
|
+
desired: Record<string, unknown>;
|
|
355
|
+
};
|
|
356
|
+
/**
|
|
357
|
+
* The result of a {@link syncIndexes} call.
|
|
358
|
+
*
|
|
359
|
+
* Every array contains index names. `stale` contains full details so the
|
|
360
|
+
* caller can inspect the mismatch.
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```ts
|
|
364
|
+
* const result = await users.syncIndexes()
|
|
365
|
+
* console.log('created:', result.created)
|
|
366
|
+
* console.log('dropped:', result.dropped)
|
|
367
|
+
* console.log('skipped:', result.skipped)
|
|
368
|
+
* console.log('stale:', result.stale.map(s => s.name))
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
type SyncIndexesResult = {
|
|
372
|
+
/** Names of indexes that were created (or would be created in dryRun mode). */
|
|
373
|
+
created: string[];
|
|
374
|
+
/** Names of indexes that were dropped (or would be dropped in dryRun mode). */
|
|
375
|
+
dropped: string[];
|
|
376
|
+
/** Names of indexes that already existed with matching options — no action taken. */
|
|
377
|
+
skipped: string[];
|
|
378
|
+
/** Indexes whose key matches a desired spec but whose options differ. */
|
|
379
|
+
stale: StaleIndex[];
|
|
380
|
+
};
|
|
410
381
|
|
|
411
382
|
/**
|
|
412
383
|
* Comparison operators for a field value of type `V`.
|
|
@@ -533,136 +504,785 @@ type TypedFilter<T> = {
|
|
|
533
504
|
};
|
|
534
505
|
|
|
535
506
|
/**
|
|
536
|
-
* Options for {@link
|
|
507
|
+
* Options for {@link findOneAndDelete}.
|
|
537
508
|
*/
|
|
538
|
-
type
|
|
539
|
-
/** MongoDB projection — include (`1`) or exclude (`0`) fields. Typed projections deferred to v1.0. */
|
|
540
|
-
project?: Record<string, 0 | 1>;
|
|
509
|
+
type FindOneAndDeleteOptions = {
|
|
541
510
|
/** Override the collection-level validation mode, or `false` to skip validation entirely. */
|
|
542
511
|
validate?: ValidationMode | false;
|
|
543
512
|
};
|
|
544
513
|
/**
|
|
545
|
-
*
|
|
514
|
+
* Delete a single document matching the filter.
|
|
546
515
|
*
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
*
|
|
516
|
+
* Removes the first document that matches the filter from the collection.
|
|
517
|
+
* No validation is performed — the document is deleted directly through
|
|
518
|
+
* the MongoDB driver.
|
|
550
519
|
*
|
|
551
|
-
* @param handle - The collection handle to
|
|
520
|
+
* @param handle - The collection handle to delete from.
|
|
552
521
|
* @param filter - Type-safe filter to match documents.
|
|
553
|
-
* @
|
|
554
|
-
* @returns The matched document, or `null` if no document matches.
|
|
555
|
-
* @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
|
|
522
|
+
* @returns The MongoDB `DeleteResult` with the deleted count.
|
|
556
523
|
*
|
|
557
524
|
* @example
|
|
558
525
|
* ```ts
|
|
559
|
-
* const
|
|
560
|
-
*
|
|
526
|
+
* const result = await deleteOne(users, { name: 'Ada' })
|
|
527
|
+
* console.log(result.deletedCount) // 1
|
|
561
528
|
* ```
|
|
562
529
|
*/
|
|
563
|
-
declare function
|
|
530
|
+
declare function deleteOne<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>): Promise<DeleteResult>;
|
|
564
531
|
/**
|
|
565
|
-
*
|
|
532
|
+
* Delete all documents matching the filter.
|
|
566
533
|
*
|
|
567
|
-
*
|
|
568
|
-
*
|
|
534
|
+
* Removes every document that matches the filter from the collection.
|
|
535
|
+
* No validation is performed — documents are deleted directly through
|
|
536
|
+
* the MongoDB driver.
|
|
569
537
|
*
|
|
570
|
-
* @param handle - The collection handle to
|
|
538
|
+
* @param handle - The collection handle to delete from.
|
|
571
539
|
* @param filter - Type-safe filter to match documents.
|
|
572
|
-
* @
|
|
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.
|
|
540
|
+
* @returns The MongoDB `DeleteResult` with the deleted count.
|
|
576
541
|
*
|
|
577
542
|
* @example
|
|
578
543
|
* ```ts
|
|
579
|
-
* const
|
|
580
|
-
* console.log(
|
|
544
|
+
* const result = await deleteMany(users, { role: 'guest' })
|
|
545
|
+
* console.log(result.deletedCount) // number of guests removed
|
|
581
546
|
* ```
|
|
582
547
|
*/
|
|
583
|
-
declare function
|
|
548
|
+
declare function deleteMany<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>): Promise<DeleteResult>;
|
|
584
549
|
/**
|
|
585
|
-
*
|
|
550
|
+
* Find a single document matching the filter, delete it, and return the document.
|
|
551
|
+
*
|
|
552
|
+
* Returns the deleted document, or `null` if no document matches the filter.
|
|
553
|
+
* The returned document is validated against the collection's Zod schema
|
|
554
|
+
* using the same resolution logic as {@link findOne}.
|
|
555
|
+
*
|
|
556
|
+
* @param handle - The collection handle to delete from.
|
|
557
|
+
* @param filter - Type-safe filter to match documents.
|
|
558
|
+
* @param options - Optional settings: `validate`.
|
|
559
|
+
* @returns The deleted document, or `null` if no document matches.
|
|
560
|
+
* @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
|
|
561
|
+
*
|
|
562
|
+
* @example
|
|
563
|
+
* ```ts
|
|
564
|
+
* const user = await findOneAndDelete(users, { name: 'Ada' })
|
|
565
|
+
* if (user) console.log(user.name) // 'Ada' (the deleted document)
|
|
566
|
+
* ```
|
|
567
|
+
*
|
|
568
|
+
* @example
|
|
569
|
+
* ```ts
|
|
570
|
+
* const user = await findOneAndDelete(
|
|
571
|
+
* users,
|
|
572
|
+
* { role: 'guest' },
|
|
573
|
+
* { validate: false },
|
|
574
|
+
* )
|
|
575
|
+
* ```
|
|
586
576
|
*/
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
validate?: ValidationMode | false;
|
|
590
|
-
};
|
|
577
|
+
declare function findOneAndDelete<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOneAndDeleteOptions): Promise<InferDocument<TDef> | null>;
|
|
578
|
+
|
|
591
579
|
/**
|
|
592
|
-
*
|
|
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.
|
|
580
|
+
* Options for offset-based pagination.
|
|
597
581
|
*
|
|
598
|
-
*
|
|
599
|
-
*
|
|
582
|
+
* @example
|
|
583
|
+
* ```ts
|
|
584
|
+
* await users.find({}).sort({ name: 1 }).paginate({ page: 2, perPage: 10 })
|
|
585
|
+
* ```
|
|
586
|
+
*/
|
|
587
|
+
type OffsetPaginateOptions = {
|
|
588
|
+
/** The page number to retrieve (1-indexed). */
|
|
589
|
+
page: number;
|
|
590
|
+
/** The number of documents per page. */
|
|
591
|
+
perPage: number;
|
|
592
|
+
};
|
|
593
|
+
/**
|
|
594
|
+
* Options for cursor-based pagination.
|
|
600
595
|
*
|
|
601
|
-
* @
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
*
|
|
596
|
+
* @example
|
|
597
|
+
* ```ts
|
|
598
|
+
* const first = await users.find({}).sort({ name: 1 }).paginate({ limit: 10 })
|
|
599
|
+
* const next = await users.find({}).sort({ name: 1 }).paginate({ cursor: first.endCursor, limit: 10 })
|
|
600
|
+
* ```
|
|
601
|
+
*/
|
|
602
|
+
type CursorPaginateOptions = {
|
|
603
|
+
/** Maximum number of documents to return. */
|
|
604
|
+
limit: number;
|
|
605
|
+
/** Opaque cursor string from a previous `startCursor` or `endCursor`. */
|
|
606
|
+
cursor?: string | null;
|
|
607
|
+
};
|
|
608
|
+
/**
|
|
609
|
+
* Result of offset-based pagination.
|
|
605
610
|
*
|
|
606
611
|
* @example
|
|
607
612
|
* ```ts
|
|
608
|
-
* const
|
|
609
|
-
*
|
|
610
|
-
* .limit(10)
|
|
611
|
-
* .toArray()
|
|
613
|
+
* const page = await users.find({}).paginate({ page: 1, perPage: 10 })
|
|
614
|
+
* console.log(page.total, page.totalPages, page.hasNext)
|
|
612
615
|
* ```
|
|
616
|
+
*/
|
|
617
|
+
type OffsetPage<TDoc> = {
|
|
618
|
+
/** The documents for this page. */
|
|
619
|
+
docs: TDoc[];
|
|
620
|
+
/** Total number of matching documents. */
|
|
621
|
+
total: number;
|
|
622
|
+
/** Current page number (1-indexed). */
|
|
623
|
+
page: number;
|
|
624
|
+
/** Number of documents per page. */
|
|
625
|
+
perPage: number;
|
|
626
|
+
/** Total number of pages (`Math.ceil(total / perPage)`). */
|
|
627
|
+
totalPages: number;
|
|
628
|
+
/** Whether there is a next page. */
|
|
629
|
+
hasNext: boolean;
|
|
630
|
+
/** Whether there is a previous page. */
|
|
631
|
+
hasPrev: boolean;
|
|
632
|
+
};
|
|
633
|
+
/**
|
|
634
|
+
* Result of cursor-based pagination.
|
|
613
635
|
*
|
|
614
636
|
* @example
|
|
615
637
|
* ```ts
|
|
616
|
-
*
|
|
617
|
-
*
|
|
638
|
+
* const page = await users.find({}).paginate({ limit: 10 })
|
|
639
|
+
* if (page.hasNext) {
|
|
640
|
+
* const next = await users.find({}).paginate({ cursor: page.endCursor, limit: 10 })
|
|
618
641
|
* }
|
|
619
642
|
* ```
|
|
620
643
|
*/
|
|
621
|
-
|
|
644
|
+
type CursorPage<TDoc> = {
|
|
645
|
+
/** The documents for this page. */
|
|
646
|
+
docs: TDoc[];
|
|
647
|
+
/** Whether there are more documents after this page. */
|
|
648
|
+
hasNext: boolean;
|
|
649
|
+
/** Whether there are documents before this page. */
|
|
650
|
+
hasPrev: boolean;
|
|
651
|
+
/** Cursor for the first document (pass to `cursor` to go backward). `null` when empty. */
|
|
652
|
+
startCursor: string | null;
|
|
653
|
+
/** Cursor for the last document (pass to `cursor` to go forward). `null` when empty. */
|
|
654
|
+
endCursor: string | null;
|
|
655
|
+
};
|
|
622
656
|
|
|
623
657
|
/**
|
|
624
|
-
*
|
|
658
|
+
* Type-safe sort specification for a document type.
|
|
625
659
|
*
|
|
626
|
-
*
|
|
627
|
-
*
|
|
628
|
-
* driver collection parameterized with the inferred document type.
|
|
660
|
+
* Constrains sort keys to top-level fields of `T` with direction `1` (ascending)
|
|
661
|
+
* or `-1` (descending). Dot-path sorts deferred to v1.0.
|
|
629
662
|
*
|
|
630
|
-
* @
|
|
631
|
-
*
|
|
663
|
+
* @example
|
|
664
|
+
* ```ts
|
|
665
|
+
* const sort: TypedSort<User> = { name: 1, createdAt: -1 }
|
|
666
|
+
* ```
|
|
632
667
|
*/
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
668
|
+
type TypedSort<T> = Partial<Record<keyof T & string, 1 | -1>>;
|
|
669
|
+
/**
|
|
670
|
+
* Type-safe cursor wrapping MongoDB's `FindCursor`.
|
|
671
|
+
*
|
|
672
|
+
* Provides chainable query modifiers (`sort`, `skip`, `limit`, `hint`) that return
|
|
673
|
+
* `this` for fluent chaining, and terminal methods (`toArray`,
|
|
674
|
+
* `[Symbol.asyncIterator]`) that validate each document against the
|
|
675
|
+
* collection's Zod schema before returning.
|
|
676
|
+
*
|
|
677
|
+
* Created by {@link find} — do not construct directly.
|
|
678
|
+
*
|
|
679
|
+
* @typeParam TDef - The collection definition type, used to infer the document type.
|
|
680
|
+
* @typeParam TIndexNames - Union of declared index names accepted by `.hint()`.
|
|
681
|
+
*
|
|
682
|
+
* @example
|
|
683
|
+
* ```ts
|
|
684
|
+
* const docs = await find(users, { role: 'admin' })
|
|
685
|
+
* .sort({ name: 1 })
|
|
686
|
+
* .limit(10)
|
|
687
|
+
* .toArray()
|
|
688
|
+
* ```
|
|
689
|
+
*/
|
|
690
|
+
declare class TypedFindCursor<TDef extends AnyCollection, TIndexNames extends string = string> {
|
|
691
|
+
/** @internal */
|
|
692
|
+
private cursor;
|
|
693
|
+
/** @internal */
|
|
694
|
+
private schema;
|
|
695
|
+
/** @internal */
|
|
696
|
+
private collectionName;
|
|
697
|
+
/** @internal */
|
|
698
|
+
private mode;
|
|
699
|
+
/** @internal */
|
|
700
|
+
private readonly nativeCollection;
|
|
701
|
+
/** @internal */
|
|
702
|
+
private readonly filter;
|
|
703
|
+
/** @internal */
|
|
704
|
+
private sortSpec;
|
|
705
|
+
/** @internal */
|
|
706
|
+
constructor(cursor: FindCursor<InferDocument<TDef>>, definition: TDef, mode: ValidationMode | false, nativeCollection: Collection<InferDocument<TDef>>, filter: any);
|
|
707
|
+
/**
|
|
708
|
+
* Set the sort order for the query.
|
|
709
|
+
*
|
|
710
|
+
* Only top-level document fields are accepted as sort keys.
|
|
711
|
+
* Values must be `1` (ascending) or `-1` (descending).
|
|
712
|
+
*
|
|
713
|
+
* @param spec - Sort specification mapping field names to sort direction.
|
|
714
|
+
* @returns `this` for chaining.
|
|
715
|
+
*
|
|
716
|
+
* @example
|
|
717
|
+
* ```ts
|
|
718
|
+
* find(users, {}).sort({ name: 1, age: -1 }).toArray()
|
|
719
|
+
* ```
|
|
720
|
+
*/
|
|
721
|
+
sort(spec: TypedSort<InferDocument<TDef>>): this;
|
|
722
|
+
/**
|
|
723
|
+
* Skip the first `n` documents in the result set.
|
|
724
|
+
*
|
|
725
|
+
* @param n - Number of documents to skip.
|
|
726
|
+
* @returns `this` for chaining.
|
|
727
|
+
*
|
|
728
|
+
* @example
|
|
729
|
+
* ```ts
|
|
730
|
+
* find(users, {}).skip(10).limit(10).toArray() // page 2
|
|
731
|
+
* ```
|
|
732
|
+
*/
|
|
733
|
+
skip(n: number): this;
|
|
734
|
+
/**
|
|
735
|
+
* Limit the number of documents returned.
|
|
736
|
+
*
|
|
737
|
+
* @param n - Maximum number of documents to return.
|
|
738
|
+
* @returns `this` for chaining.
|
|
739
|
+
*
|
|
740
|
+
* @example
|
|
741
|
+
* ```ts
|
|
742
|
+
* find(users, {}).limit(10).toArray() // at most 10 docs
|
|
743
|
+
* ```
|
|
744
|
+
*/
|
|
745
|
+
limit(n: number): this;
|
|
746
|
+
/**
|
|
747
|
+
* Force the query optimizer to use the specified index.
|
|
748
|
+
*
|
|
749
|
+
* Only accepts index names that were declared via `.name()` in the
|
|
750
|
+
* collection definition. If no named indexes exist, any string is accepted.
|
|
751
|
+
*
|
|
752
|
+
* @param indexName - The name of a declared compound index.
|
|
753
|
+
* @returns `this` for chaining.
|
|
754
|
+
*
|
|
755
|
+
* @example
|
|
756
|
+
* ```ts
|
|
757
|
+
* const Users = collection('users', { email: z.string(), role: z.string() }, {
|
|
758
|
+
* indexes: [index({ email: 1, role: -1 }).name('email_role_idx')],
|
|
759
|
+
* })
|
|
760
|
+
* const admins = await users.find({ role: 'admin' })
|
|
761
|
+
* .hint('email_role_idx')
|
|
762
|
+
* .toArray()
|
|
763
|
+
* ```
|
|
764
|
+
*/
|
|
765
|
+
hint(indexName: TIndexNames): this;
|
|
766
|
+
/**
|
|
767
|
+
* Execute the query with offset-based pagination, returning a page of documents
|
|
768
|
+
* with total count and navigation metadata.
|
|
769
|
+
*
|
|
770
|
+
* Runs `countDocuments` and `find` in parallel for performance. Ignores any
|
|
771
|
+
* `.skip()` or `.limit()` already set on the cursor — issues a fresh query.
|
|
772
|
+
*
|
|
773
|
+
* @param opts - Offset pagination options: `page` (1-indexed) and `perPage`.
|
|
774
|
+
* @returns A page with `docs`, `total`, `totalPages`, `hasNext`, `hasPrev`.
|
|
775
|
+
* @throws {ZodmonValidationError} When a document fails schema validation.
|
|
776
|
+
*
|
|
777
|
+
* @example
|
|
778
|
+
* ```ts
|
|
779
|
+
* const page = await users.find({ role: 'admin' })
|
|
780
|
+
* .sort({ createdAt: -1 })
|
|
781
|
+
* .paginate({ page: 2, perPage: 10 })
|
|
782
|
+
* console.log(page.total, page.totalPages, page.hasNext)
|
|
783
|
+
* ```
|
|
784
|
+
*/
|
|
785
|
+
paginate(opts: OffsetPaginateOptions): Promise<OffsetPage<InferDocument<TDef>>>;
|
|
786
|
+
/**
|
|
787
|
+
* Execute the query with cursor-based pagination, returning a page of documents
|
|
788
|
+
* with opaque cursors for forward/backward navigation.
|
|
789
|
+
*
|
|
790
|
+
* Uses the `limit + 1` trick to determine `hasNext`/`hasPrev` without extra queries.
|
|
791
|
+
* Direction is encoded in the cursor — pass `endCursor` to go forward, `startCursor`
|
|
792
|
+
* to go backward.
|
|
793
|
+
*
|
|
794
|
+
* @param opts - Cursor pagination options: `limit` and optional `cursor`.
|
|
795
|
+
* @returns A page with `docs`, `hasNext`, `hasPrev`, `startCursor`, `endCursor`.
|
|
796
|
+
* @throws {ZodmonValidationError} When a document fails schema validation.
|
|
797
|
+
* @throws {Error} When the cursor string is malformed.
|
|
798
|
+
*
|
|
799
|
+
* @example
|
|
800
|
+
* ```ts
|
|
801
|
+
* const first = await users.find({}).sort({ name: 1 }).paginate({ limit: 10 })
|
|
802
|
+
* const next = await users.find({}).sort({ name: 1 })
|
|
803
|
+
* .paginate({ cursor: first.endCursor, limit: 10 })
|
|
804
|
+
* ```
|
|
805
|
+
*/
|
|
806
|
+
paginate(opts: CursorPaginateOptions): Promise<CursorPage<InferDocument<TDef>>>;
|
|
807
|
+
/** @internal Offset pagination implementation. */
|
|
808
|
+
private offsetPaginate;
|
|
809
|
+
/** @internal Cursor pagination implementation. */
|
|
810
|
+
private cursorPaginate;
|
|
811
|
+
/**
|
|
812
|
+
* Execute the query and return all matching documents as an array.
|
|
813
|
+
*
|
|
814
|
+
* Each document is validated against the collection's Zod schema
|
|
815
|
+
* according to the resolved validation mode.
|
|
816
|
+
*
|
|
817
|
+
* @returns Array of validated documents.
|
|
818
|
+
* @throws {ZodmonValidationError} When a document fails schema validation in strict/strip mode.
|
|
819
|
+
*
|
|
820
|
+
* @example
|
|
821
|
+
* ```ts
|
|
822
|
+
* const admins = await find(users, { role: 'admin' }).toArray()
|
|
823
|
+
* ```
|
|
824
|
+
*/
|
|
825
|
+
toArray(): Promise<InferDocument<TDef>[]>;
|
|
826
|
+
/**
|
|
827
|
+
* Async iterator for streaming documents one at a time.
|
|
828
|
+
*
|
|
829
|
+
* Each yielded document is validated against the collection's Zod schema.
|
|
830
|
+
* Memory-efficient for large result sets.
|
|
831
|
+
*
|
|
832
|
+
* @yields Validated documents one at a time.
|
|
833
|
+
* @throws {ZodmonValidationError} When a document fails schema validation.
|
|
834
|
+
*
|
|
835
|
+
* @example
|
|
836
|
+
* ```ts
|
|
837
|
+
* for await (const user of find(users, {})) {
|
|
838
|
+
* console.log(user.name)
|
|
839
|
+
* }
|
|
840
|
+
* ```
|
|
841
|
+
*/
|
|
842
|
+
[Symbol.asyncIterator](): AsyncGenerator<InferDocument<TDef>>;
|
|
843
|
+
/** @internal Validate a single raw document against the schema. */
|
|
844
|
+
private validateDoc;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Options for {@link findOne} and {@link findOneOrThrow}.
|
|
849
|
+
*/
|
|
850
|
+
type FindOneOptions = {
|
|
851
|
+
/** MongoDB projection — include (`1`) or exclude (`0`) fields. Typed projections deferred to v1.0. */
|
|
852
|
+
project?: Record<string, 0 | 1>;
|
|
853
|
+
/** Override the collection-level validation mode, or `false` to skip validation entirely. */
|
|
854
|
+
validate?: ValidationMode | false;
|
|
855
|
+
};
|
|
856
|
+
/**
|
|
857
|
+
* Find a single document matching the filter.
|
|
858
|
+
*
|
|
859
|
+
* Queries MongoDB, then validates the fetched document against the collection's
|
|
860
|
+
* Zod schema. Validation mode is resolved from the per-query option, falling
|
|
861
|
+
* back to the collection-level default (which defaults to `'strict'`).
|
|
862
|
+
*
|
|
863
|
+
* @param handle - The collection handle to query.
|
|
864
|
+
* @param filter - Type-safe filter to match documents.
|
|
865
|
+
* @param options - Optional projection and validation overrides.
|
|
866
|
+
* @returns The matched document, or `null` if no document matches.
|
|
867
|
+
* @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
|
|
868
|
+
*
|
|
869
|
+
* @example
|
|
870
|
+
* ```ts
|
|
871
|
+
* const user = await findOne(users, { name: 'Ada' })
|
|
872
|
+
* if (user) console.log(user.role) // typed as 'admin' | 'user'
|
|
873
|
+
* ```
|
|
874
|
+
*/
|
|
875
|
+
declare function findOne<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOneOptions): Promise<InferDocument<TDef> | null>;
|
|
876
|
+
/**
|
|
877
|
+
* Find a single document matching the filter, or throw if none exists.
|
|
878
|
+
*
|
|
879
|
+
* Behaves identically to {@link findOne} but throws {@link ZodmonNotFoundError}
|
|
880
|
+
* instead of returning `null` when no document matches the filter.
|
|
881
|
+
*
|
|
882
|
+
* @param handle - The collection handle to query.
|
|
883
|
+
* @param filter - Type-safe filter to match documents.
|
|
884
|
+
* @param options - Optional projection and validation overrides.
|
|
885
|
+
* @returns The matched document (never null).
|
|
886
|
+
* @throws {ZodmonNotFoundError} When no document matches the filter.
|
|
887
|
+
* @throws {ZodmonValidationError} When the fetched document fails schema validation in strict mode.
|
|
888
|
+
*
|
|
889
|
+
* @example
|
|
890
|
+
* ```ts
|
|
891
|
+
* const user = await findOneOrThrow(users, { name: 'Ada' })
|
|
892
|
+
* console.log(user.role) // typed as 'admin' | 'user', guaranteed non-null
|
|
893
|
+
* ```
|
|
894
|
+
*/
|
|
895
|
+
declare function findOneOrThrow<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOneOptions): Promise<InferDocument<TDef>>;
|
|
896
|
+
/**
|
|
897
|
+
* Options for {@link find}.
|
|
898
|
+
*/
|
|
899
|
+
type FindOptions = {
|
|
900
|
+
/** Override the collection-level validation mode, or `false` to skip validation entirely. */
|
|
901
|
+
validate?: ValidationMode | false;
|
|
902
|
+
};
|
|
903
|
+
/**
|
|
904
|
+
* Find all documents matching the filter, returning a chainable typed cursor.
|
|
905
|
+
*
|
|
906
|
+
* The cursor is lazy — no query is executed until a terminal method
|
|
907
|
+
* (`toArray`, `for await`) is called. Use `sort`, `skip`, and `limit`
|
|
908
|
+
* to shape the query before executing.
|
|
909
|
+
*
|
|
910
|
+
* Each document is validated against the collection's Zod schema when
|
|
911
|
+
* a terminal method consumes it.
|
|
912
|
+
*
|
|
913
|
+
* @param handle - The collection handle to query.
|
|
914
|
+
* @param filter - Type-safe filter to match documents.
|
|
915
|
+
* @param options - Optional validation overrides.
|
|
916
|
+
* @returns A typed cursor for chaining query modifiers.
|
|
917
|
+
*
|
|
918
|
+
* @example
|
|
919
|
+
* ```ts
|
|
920
|
+
* const admins = await find(users, { role: 'admin' })
|
|
921
|
+
* .sort({ name: 1 })
|
|
922
|
+
* .limit(10)
|
|
923
|
+
* .toArray()
|
|
924
|
+
* ```
|
|
925
|
+
*
|
|
926
|
+
* @example
|
|
927
|
+
* ```ts
|
|
928
|
+
* for await (const user of find(users, {})) {
|
|
929
|
+
* console.log(user.name)
|
|
930
|
+
* }
|
|
931
|
+
* ```
|
|
932
|
+
*/
|
|
933
|
+
declare function find<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, options?: FindOptions): TypedFindCursor<TDef, IndexNames<TDef>>;
|
|
934
|
+
|
|
935
|
+
/**
|
|
936
|
+
* Extracts the element type from an array type.
|
|
937
|
+
*
|
|
938
|
+
* @example
|
|
939
|
+
* ```ts
|
|
940
|
+
* type E = ArrayElement<string[]> // string
|
|
941
|
+
* type N = ArrayElement<number[]> // number
|
|
942
|
+
* ```
|
|
943
|
+
*/
|
|
944
|
+
type ArrayElement<T> = T extends ReadonlyArray<infer E> ? E : never;
|
|
945
|
+
/**
|
|
946
|
+
* Fields valid for `$set`, `$setOnInsert`, `$min`, and `$max` operators.
|
|
947
|
+
*
|
|
948
|
+
* Allows top-level fields with matching value types plus dot-notation paths
|
|
949
|
+
* for nested field updates.
|
|
950
|
+
*
|
|
951
|
+
* @example
|
|
952
|
+
* ```ts
|
|
953
|
+
* const set: SetFields<User> = { name: 'Alice', 'address.city': 'NYC' }
|
|
954
|
+
* ```
|
|
955
|
+
*/
|
|
956
|
+
type SetFields<T> = {
|
|
957
|
+
[K in keyof T]?: T[K];
|
|
958
|
+
} & {
|
|
959
|
+
[P in DotPaths<T>]?: DotPathType<T, P>;
|
|
960
|
+
};
|
|
961
|
+
/**
|
|
962
|
+
* Fields valid for the `$inc` operator — only number-typed fields.
|
|
963
|
+
*
|
|
964
|
+
* Includes dot-notation paths that resolve to number types.
|
|
965
|
+
*
|
|
966
|
+
* @example
|
|
967
|
+
* ```ts
|
|
968
|
+
* const inc: IncFields<User> = { age: 1, 'stats.views': 5 }
|
|
969
|
+
* ```
|
|
970
|
+
*/
|
|
971
|
+
type IncFields<T> = {
|
|
972
|
+
[K in keyof T as NonNullable<T[K]> extends number ? K : never]?: number;
|
|
973
|
+
} & {
|
|
974
|
+
[P in DotPaths<T> as DotPathType<T, P> extends number ? P : never]?: number;
|
|
975
|
+
};
|
|
976
|
+
/**
|
|
977
|
+
* Modifiers for the `$push` operator.
|
|
978
|
+
*
|
|
979
|
+
* Use with `$push` to insert multiple elements and control array position/size.
|
|
980
|
+
*
|
|
981
|
+
* @example
|
|
982
|
+
* ```ts
|
|
983
|
+
* const push = { tags: { $each: ['a', 'b'], $position: 0, $slice: 10 } }
|
|
984
|
+
* ```
|
|
985
|
+
*/
|
|
986
|
+
type PushModifiers<E> = {
|
|
987
|
+
/** Array of elements to push. */
|
|
988
|
+
$each: E[];
|
|
989
|
+
/** Position at which to insert elements. */
|
|
990
|
+
$position?: number;
|
|
991
|
+
/** Maximum array length after push. */
|
|
992
|
+
$slice?: number;
|
|
993
|
+
/** Sort order applied after push. */
|
|
994
|
+
$sort?: 1 | -1 | Record<string, 1 | -1>;
|
|
995
|
+
};
|
|
996
|
+
/**
|
|
997
|
+
* Fields valid for the `$push` operator — only array-typed fields.
|
|
998
|
+
*
|
|
999
|
+
* Accepts a single element value or a modifier object with `$each`.
|
|
1000
|
+
*
|
|
1001
|
+
* @example
|
|
1002
|
+
* ```ts
|
|
1003
|
+
* const push: PushFields<User> = { tags: 'dev' }
|
|
1004
|
+
* const pushMany: PushFields<User> = { tags: { $each: ['a', 'b'] } }
|
|
1005
|
+
* ```
|
|
1006
|
+
*/
|
|
1007
|
+
type PushFields<T> = {
|
|
1008
|
+
[K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: ArrayElement<NonNullable<T[K]>> | PushModifiers<ArrayElement<NonNullable<T[K]>>>;
|
|
1009
|
+
};
|
|
1010
|
+
/**
|
|
1011
|
+
* Fields valid for the `$pull` operator — only array-typed fields.
|
|
1012
|
+
*
|
|
1013
|
+
* For primitive arrays: accepts a value or comparison operators.
|
|
1014
|
+
* For object arrays: also accepts a `TypedFilter` on the element type.
|
|
1015
|
+
*
|
|
1016
|
+
* @example
|
|
1017
|
+
* ```ts
|
|
1018
|
+
* const pull: PullFields<User> = { tags: 'old' }
|
|
1019
|
+
* const pullQuery: PullFields<User> = { scores: { $lt: 50 } }
|
|
1020
|
+
* const pullObj: PullFields<User> = { comments: { author: 'spam' } }
|
|
1021
|
+
* ```
|
|
1022
|
+
*/
|
|
1023
|
+
type PullFields<T> = {
|
|
1024
|
+
[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);
|
|
1025
|
+
};
|
|
1026
|
+
/**
|
|
1027
|
+
* Modifier for the `$addToSet` operator's `$each` syntax.
|
|
1028
|
+
*
|
|
1029
|
+
* @example
|
|
1030
|
+
* ```ts
|
|
1031
|
+
* const addToSet = { tags: { $each: ['a', 'b'] } }
|
|
1032
|
+
* ```
|
|
1033
|
+
*/
|
|
1034
|
+
type AddToSetEach<E> = {
|
|
1035
|
+
$each: E[];
|
|
1036
|
+
};
|
|
1037
|
+
/**
|
|
1038
|
+
* Fields valid for the `$addToSet` operator — only array-typed fields.
|
|
1039
|
+
*
|
|
1040
|
+
* Accepts a single element value or `{ $each: [...] }` for multiple elements.
|
|
1041
|
+
*
|
|
1042
|
+
* @example
|
|
1043
|
+
* ```ts
|
|
1044
|
+
* const add: AddToSetFields<User> = { tags: 'dev' }
|
|
1045
|
+
* const addMany: AddToSetFields<User> = { tags: { $each: ['a', 'b'] } }
|
|
1046
|
+
* ```
|
|
1047
|
+
*/
|
|
1048
|
+
type AddToSetFields<T> = {
|
|
1049
|
+
[K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: ArrayElement<NonNullable<T[K]>> | AddToSetEach<ArrayElement<NonNullable<T[K]>>>;
|
|
1050
|
+
};
|
|
1051
|
+
/**
|
|
1052
|
+
* Fields valid for the `$pop` operator — only array-typed fields.
|
|
1053
|
+
*
|
|
1054
|
+
* Value `1` removes the last element, `-1` removes the first.
|
|
1055
|
+
*
|
|
1056
|
+
* @example
|
|
1057
|
+
* ```ts
|
|
1058
|
+
* const pop: PopFields<User> = { tags: -1 } // remove first
|
|
1059
|
+
* ```
|
|
1060
|
+
*/
|
|
1061
|
+
type PopFields<T> = {
|
|
1062
|
+
[K in keyof T as NonNullable<T[K]> extends ReadonlyArray<unknown> ? K : never]?: 1 | -1;
|
|
1063
|
+
};
|
|
1064
|
+
/**
|
|
1065
|
+
* Fields valid for the `$unset` operator — any existing field.
|
|
1066
|
+
*
|
|
1067
|
+
* Value is `''`, `true`, or `1` (all mean "remove this field").
|
|
1068
|
+
*
|
|
1069
|
+
* @example
|
|
1070
|
+
* ```ts
|
|
1071
|
+
* const unset: UnsetFields<User> = { middleName: '' }
|
|
1072
|
+
* ```
|
|
1073
|
+
*/
|
|
1074
|
+
type UnsetFields<T> = {
|
|
1075
|
+
[K in keyof T]?: '' | true | 1;
|
|
1076
|
+
};
|
|
1077
|
+
/**
|
|
1078
|
+
* Fields valid for the `$currentDate` operator — only Date-typed fields.
|
|
1079
|
+
*
|
|
1080
|
+
* Sets the field to the current date. Value is `true` or `{ $type: 'date' }`.
|
|
1081
|
+
*
|
|
1082
|
+
* @example
|
|
1083
|
+
* ```ts
|
|
1084
|
+
* const cd: CurrentDateFields<User> = { createdAt: true }
|
|
1085
|
+
* ```
|
|
1086
|
+
*/
|
|
1087
|
+
type CurrentDateFields<T> = {
|
|
1088
|
+
[K in keyof T as NonNullable<T[K]> extends Date ? K : never]?: true | {
|
|
1089
|
+
$type: 'date';
|
|
1090
|
+
};
|
|
1091
|
+
};
|
|
1092
|
+
/**
|
|
1093
|
+
* Fields valid for the `$rename` operator.
|
|
1094
|
+
*
|
|
1095
|
+
* Renames an existing field to a new name. Key is the current field name,
|
|
1096
|
+
* value is the new name as a string.
|
|
1097
|
+
*
|
|
1098
|
+
* @example
|
|
1099
|
+
* ```ts
|
|
1100
|
+
* const rename: RenameFields<User> = { name: 'fullName' }
|
|
1101
|
+
* ```
|
|
1102
|
+
*/
|
|
1103
|
+
type RenameFields<T> = {
|
|
1104
|
+
[K in keyof T & string]?: string;
|
|
1105
|
+
};
|
|
1106
|
+
/**
|
|
1107
|
+
* Strict type-safe MongoDB update filter.
|
|
1108
|
+
*
|
|
1109
|
+
* Validates update operators against field types at compile time. Each operator
|
|
1110
|
+
* constrains which fields it accepts (e.g. `$inc` only on numbers, `$push` only
|
|
1111
|
+
* on arrays). Supports dot-notation paths for nested field access.
|
|
1112
|
+
*
|
|
1113
|
+
* @example
|
|
1114
|
+
* ```ts
|
|
1115
|
+
* const update: TypedUpdateFilter<User> = {
|
|
1116
|
+
* $set: { name: 'Alice' },
|
|
1117
|
+
* $inc: { age: 1 },
|
|
1118
|
+
* }
|
|
1119
|
+
* ```
|
|
1120
|
+
*/
|
|
1121
|
+
type TypedUpdateFilter<T> = {
|
|
1122
|
+
/** Sets the value of one or more fields. */
|
|
1123
|
+
$set?: SetFields<T>;
|
|
1124
|
+
/** Sets fields only when inserting (upsert). Same typing as `$set`. */
|
|
1125
|
+
$setOnInsert?: SetFields<T>;
|
|
1126
|
+
/** Increments numeric fields by the given amount. Only accepts number-typed fields. */
|
|
1127
|
+
$inc?: IncFields<T>;
|
|
1128
|
+
/** Updates the field if the given value is less than the current value. */
|
|
1129
|
+
$min?: SetFields<T>;
|
|
1130
|
+
/** Updates the field if the given value is greater than the current value. */
|
|
1131
|
+
$max?: SetFields<T>;
|
|
1132
|
+
/** Appends a value to an array field. Supports `$each`, `$position`, `$slice`, `$sort`. */
|
|
1133
|
+
$push?: PushFields<T>;
|
|
1134
|
+
/** Removes matching values from an array field. */
|
|
1135
|
+
$pull?: PullFields<T>;
|
|
1136
|
+
/** Adds a value to an array only if it doesn't already exist. */
|
|
1137
|
+
$addToSet?: AddToSetFields<T>;
|
|
1138
|
+
/** Removes the first (`-1`) or last (`1`) element of an array. */
|
|
1139
|
+
$pop?: PopFields<T>;
|
|
1140
|
+
/** Removes the specified fields from the document. */
|
|
1141
|
+
$unset?: UnsetFields<T>;
|
|
1142
|
+
/** Sets the field to the current date. Only accepts Date-typed fields. */
|
|
1143
|
+
$currentDate?: CurrentDateFields<T>;
|
|
1144
|
+
/** Renames a field. */
|
|
1145
|
+
$rename?: RenameFields<T>;
|
|
1146
|
+
};
|
|
1147
|
+
|
|
1148
|
+
/**
|
|
1149
|
+
* Options for {@link updateOne} and {@link updateMany}.
|
|
1150
|
+
*/
|
|
1151
|
+
type UpdateOptions = {
|
|
1152
|
+
/** When `true`, inserts a new document if no document matches the filter. */
|
|
1153
|
+
upsert?: boolean;
|
|
1154
|
+
};
|
|
1155
|
+
/**
|
|
1156
|
+
* Options for {@link findOneAndUpdate}.
|
|
1157
|
+
*/
|
|
1158
|
+
type FindOneAndUpdateOptions = {
|
|
1159
|
+
/** Whether to return the document before or after the update. Defaults to `'after'`. */
|
|
1160
|
+
returnDocument?: 'before' | 'after';
|
|
1161
|
+
/** When `true`, inserts a new document if no document matches the filter. */
|
|
1162
|
+
upsert?: boolean;
|
|
1163
|
+
/** Override the collection-level validation mode, or `false` to skip validation entirely. */
|
|
1164
|
+
validate?: ValidationMode | false;
|
|
1165
|
+
};
|
|
1166
|
+
/**
|
|
1167
|
+
* Update a single document matching the filter.
|
|
1168
|
+
*
|
|
1169
|
+
* Applies the update operators to the first document that matches the filter.
|
|
1170
|
+
* Does not validate the update against the Zod schema — validation happens
|
|
1171
|
+
* at the field-operator level through {@link TypedUpdateFilter}.
|
|
1172
|
+
*
|
|
1173
|
+
* @param handle - The collection handle to update in.
|
|
1174
|
+
* @param filter - Type-safe filter to match documents.
|
|
1175
|
+
* @param update - Type-safe update operators to apply.
|
|
1176
|
+
* @param options - Optional settings such as `upsert`.
|
|
1177
|
+
* @returns The MongoDB `UpdateResult` with match/modify counts.
|
|
1178
|
+
*
|
|
1179
|
+
* @example
|
|
1180
|
+
* ```ts
|
|
1181
|
+
* const result = await updateOne(users, { name: 'Ada' }, { $set: { role: 'admin' } })
|
|
1182
|
+
* console.log(result.modifiedCount) // 1
|
|
1183
|
+
* ```
|
|
1184
|
+
*/
|
|
1185
|
+
declare function updateOne<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: UpdateOptions): Promise<UpdateResult>;
|
|
1186
|
+
/**
|
|
1187
|
+
* Update all documents matching the filter.
|
|
1188
|
+
*
|
|
1189
|
+
* Applies the update operators to every document that matches the filter.
|
|
1190
|
+
* Does not validate the update against the Zod schema — validation happens
|
|
1191
|
+
* at the field-operator level through {@link TypedUpdateFilter}.
|
|
1192
|
+
*
|
|
1193
|
+
* @param handle - The collection handle to update in.
|
|
1194
|
+
* @param filter - Type-safe filter to match documents.
|
|
1195
|
+
* @param update - Type-safe update operators to apply.
|
|
1196
|
+
* @param options - Optional settings such as `upsert`.
|
|
1197
|
+
* @returns The MongoDB `UpdateResult` with match/modify counts.
|
|
1198
|
+
*
|
|
1199
|
+
* @example
|
|
1200
|
+
* ```ts
|
|
1201
|
+
* const result = await updateMany(users, { role: 'guest' }, { $set: { role: 'user' } })
|
|
1202
|
+
* console.log(result.modifiedCount) // number of guests promoted
|
|
1203
|
+
* ```
|
|
1204
|
+
*/
|
|
1205
|
+
declare function updateMany<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: UpdateOptions): Promise<UpdateResult>;
|
|
1206
|
+
/**
|
|
1207
|
+
* Find a single document matching the filter, apply an update, and return the document.
|
|
1208
|
+
*
|
|
1209
|
+
* By default, returns the document **after** the update is applied. Set
|
|
1210
|
+
* `returnDocument: 'before'` to get the pre-update snapshot. The returned
|
|
1211
|
+
* document is validated against the collection's Zod schema using the same
|
|
1212
|
+
* resolution logic as {@link findOne}.
|
|
1213
|
+
*
|
|
1214
|
+
* @param handle - The collection handle to update in.
|
|
1215
|
+
* @param filter - Type-safe filter to match documents.
|
|
1216
|
+
* @param update - Type-safe update operators to apply.
|
|
1217
|
+
* @param options - Optional settings: `returnDocument`, `upsert`, `validate`.
|
|
1218
|
+
* @returns The matched document (before or after update), or `null` if no document matches.
|
|
1219
|
+
* @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
|
|
1220
|
+
*
|
|
1221
|
+
* @example
|
|
1222
|
+
* ```ts
|
|
1223
|
+
* const user = await findOneAndUpdate(
|
|
1224
|
+
* users,
|
|
1225
|
+
* { name: 'Ada' },
|
|
1226
|
+
* { $set: { role: 'admin' } },
|
|
1227
|
+
* )
|
|
1228
|
+
* if (user) console.log(user.role) // 'admin' (returned after update)
|
|
1229
|
+
* ```
|
|
1230
|
+
*
|
|
1231
|
+
* @example
|
|
1232
|
+
* ```ts
|
|
1233
|
+
* const before = await findOneAndUpdate(
|
|
1234
|
+
* users,
|
|
1235
|
+
* { name: 'Ada' },
|
|
1236
|
+
* { $inc: { loginCount: 1 } },
|
|
1237
|
+
* { returnDocument: 'before' },
|
|
1238
|
+
* )
|
|
1239
|
+
* ```
|
|
1240
|
+
*/
|
|
1241
|
+
declare function findOneAndUpdate<TDef extends AnyCollection>(handle: CollectionHandle<TDef>, filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: FindOneAndUpdateOptions): Promise<InferDocument<TDef> | null>;
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* Typed wrapper around a MongoDB driver `Collection`.
|
|
1245
|
+
*
|
|
1246
|
+
* Created by {@link Database.use}. Holds the original `CollectionDefinition`
|
|
1247
|
+
* (for runtime schema validation and index metadata) alongside the native
|
|
1248
|
+
* driver collection parameterized with the inferred document type.
|
|
1249
|
+
*
|
|
1250
|
+
* @typeParam TDef - The collection definition type. Used to derive both
|
|
1251
|
+
* the document type (`InferDocument`) and the insert type (`InferInsert`).
|
|
1252
|
+
*/
|
|
1253
|
+
declare class CollectionHandle<TDef extends AnyCollection = AnyCollection> {
|
|
1254
|
+
/** The collection definition containing schema, name, and index metadata. */
|
|
1255
|
+
readonly definition: TDef;
|
|
1256
|
+
/** The underlying MongoDB driver collection, typed to the inferred document type. */
|
|
1257
|
+
readonly native: Collection<InferDocument<TDef>>;
|
|
1258
|
+
constructor(definition: TDef, native: Collection<InferDocument<TDef>>);
|
|
1259
|
+
/**
|
|
1260
|
+
* Insert a single document into the collection.
|
|
1261
|
+
*
|
|
1262
|
+
* Validates the input against the collection's Zod schema before writing.
|
|
1263
|
+
* Schema defaults (including auto-generated `_id`) are applied during
|
|
1264
|
+
* validation. Returns the full document with all defaults filled in.
|
|
1265
|
+
*
|
|
1266
|
+
* @param doc - The document to insert. Fields with `.default()` are optional.
|
|
1267
|
+
* @returns The inserted document with `_id` and all defaults applied.
|
|
1268
|
+
* @throws {ZodmonValidationError} When the document fails schema validation.
|
|
1269
|
+
*
|
|
1270
|
+
* @example
|
|
1271
|
+
* ```ts
|
|
1272
|
+
* const users = db.use(Users)
|
|
1273
|
+
* const user = await users.insertOne({ name: 'Ada' })
|
|
1274
|
+
* console.log(user._id) // ObjectId (auto-generated)
|
|
1275
|
+
* console.log(user.role) // 'user' (schema default)
|
|
1276
|
+
* ```
|
|
1277
|
+
*/
|
|
1278
|
+
insertOne(doc: InferInsert<TDef>): Promise<InferDocument<TDef>>;
|
|
1279
|
+
/**
|
|
1280
|
+
* Insert multiple documents into the collection.
|
|
1281
|
+
*
|
|
1282
|
+
* Validates every document against the collection's Zod schema before
|
|
1283
|
+
* writing any to MongoDB. If any document fails validation, none are
|
|
1284
|
+
* inserted (fail-fast before the driver call).
|
|
1285
|
+
*
|
|
666
1286
|
* @param docs - The documents to insert.
|
|
667
1287
|
* @returns The inserted documents with `_id` and all defaults applied.
|
|
668
1288
|
* @throws {ZodmonValidationError} When any document fails schema validation.
|
|
@@ -736,7 +1356,156 @@ declare class CollectionHandle<TDef extends AnyCollection = AnyCollection> {
|
|
|
736
1356
|
* .toArray()
|
|
737
1357
|
* ```
|
|
738
1358
|
*/
|
|
739
|
-
find(filter: TypedFilter<InferDocument<TDef>>, options?: FindOptions): TypedFindCursor<TDef
|
|
1359
|
+
find(filter: TypedFilter<InferDocument<TDef>>, options?: FindOptions): TypedFindCursor<TDef, IndexNames<TDef>>;
|
|
1360
|
+
/**
|
|
1361
|
+
* Update a single document matching the filter.
|
|
1362
|
+
*
|
|
1363
|
+
* Applies the update operators to the first document that matches the filter.
|
|
1364
|
+
* Does not validate the update against the Zod schema — validation happens
|
|
1365
|
+
* at the field-operator level through {@link TypedUpdateFilter}.
|
|
1366
|
+
*
|
|
1367
|
+
* @param filter - Type-safe filter to match documents.
|
|
1368
|
+
* @param update - Type-safe update operators to apply.
|
|
1369
|
+
* @param options - Optional settings such as `upsert`.
|
|
1370
|
+
* @returns The MongoDB `UpdateResult` with match/modify counts.
|
|
1371
|
+
*
|
|
1372
|
+
* @example
|
|
1373
|
+
* ```ts
|
|
1374
|
+
* const users = db.use(Users)
|
|
1375
|
+
* const result = await users.updateOne({ name: 'Ada' }, { $set: { role: 'admin' } })
|
|
1376
|
+
* console.log(result.modifiedCount) // 1
|
|
1377
|
+
* ```
|
|
1378
|
+
*/
|
|
1379
|
+
updateOne(filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: UpdateOptions): Promise<UpdateResult>;
|
|
1380
|
+
/**
|
|
1381
|
+
* Update all documents matching the filter.
|
|
1382
|
+
*
|
|
1383
|
+
* Applies the update operators to every document that matches the filter.
|
|
1384
|
+
* Does not validate the update against the Zod schema — validation happens
|
|
1385
|
+
* at the field-operator level through {@link TypedUpdateFilter}.
|
|
1386
|
+
*
|
|
1387
|
+
* @param filter - Type-safe filter to match documents.
|
|
1388
|
+
* @param update - Type-safe update operators to apply.
|
|
1389
|
+
* @param options - Optional settings such as `upsert`.
|
|
1390
|
+
* @returns The MongoDB `UpdateResult` with match/modify counts.
|
|
1391
|
+
*
|
|
1392
|
+
* @example
|
|
1393
|
+
* ```ts
|
|
1394
|
+
* const users = db.use(Users)
|
|
1395
|
+
* const result = await users.updateMany({ role: 'guest' }, { $set: { role: 'user' } })
|
|
1396
|
+
* console.log(result.modifiedCount) // number of guests promoted
|
|
1397
|
+
* ```
|
|
1398
|
+
*/
|
|
1399
|
+
updateMany(filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: UpdateOptions): Promise<UpdateResult>;
|
|
1400
|
+
/**
|
|
1401
|
+
* Find a single document matching the filter, apply an update, and return the document.
|
|
1402
|
+
*
|
|
1403
|
+
* By default, returns the document **after** the update is applied. Set
|
|
1404
|
+
* `returnDocument: 'before'` to get the pre-update snapshot. The returned
|
|
1405
|
+
* document is validated against the collection's Zod schema using the same
|
|
1406
|
+
* resolution logic as {@link findOne}.
|
|
1407
|
+
*
|
|
1408
|
+
* @param filter - Type-safe filter to match documents.
|
|
1409
|
+
* @param update - Type-safe update operators to apply.
|
|
1410
|
+
* @param options - Optional settings: `returnDocument`, `upsert`, `validate`.
|
|
1411
|
+
* @returns The matched document (before or after update), or `null` if no document matches.
|
|
1412
|
+
* @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
|
|
1413
|
+
*
|
|
1414
|
+
* @example
|
|
1415
|
+
* ```ts
|
|
1416
|
+
* const users = db.use(Users)
|
|
1417
|
+
* const user = await users.findOneAndUpdate(
|
|
1418
|
+
* { name: 'Ada' },
|
|
1419
|
+
* { $set: { role: 'admin' } },
|
|
1420
|
+
* )
|
|
1421
|
+
* if (user) console.log(user.role) // 'admin' (returned after update)
|
|
1422
|
+
* ```
|
|
1423
|
+
*/
|
|
1424
|
+
findOneAndUpdate(filter: TypedFilter<InferDocument<TDef>>, update: TypedUpdateFilter<InferDocument<TDef>>, options?: FindOneAndUpdateOptions): Promise<InferDocument<TDef> | null>;
|
|
1425
|
+
/**
|
|
1426
|
+
* Delete a single document matching the filter.
|
|
1427
|
+
*
|
|
1428
|
+
* Removes the first document that matches the filter from the collection.
|
|
1429
|
+
* No validation is performed — the document is deleted directly through
|
|
1430
|
+
* the MongoDB driver.
|
|
1431
|
+
*
|
|
1432
|
+
* @param filter - Type-safe filter to match documents.
|
|
1433
|
+
* @returns The MongoDB `DeleteResult` with the deleted count.
|
|
1434
|
+
*
|
|
1435
|
+
* @example
|
|
1436
|
+
* ```ts
|
|
1437
|
+
* const users = db.use(Users)
|
|
1438
|
+
* const result = await users.deleteOne({ name: 'Ada' })
|
|
1439
|
+
* console.log(result.deletedCount) // 1
|
|
1440
|
+
* ```
|
|
1441
|
+
*/
|
|
1442
|
+
deleteOne(filter: TypedFilter<InferDocument<TDef>>): Promise<DeleteResult>;
|
|
1443
|
+
/**
|
|
1444
|
+
* Delete all documents matching the filter.
|
|
1445
|
+
*
|
|
1446
|
+
* Removes every document that matches the filter from the collection.
|
|
1447
|
+
* No validation is performed — documents are deleted directly through
|
|
1448
|
+
* the MongoDB driver.
|
|
1449
|
+
*
|
|
1450
|
+
* @param filter - Type-safe filter to match documents.
|
|
1451
|
+
* @returns The MongoDB `DeleteResult` with the deleted count.
|
|
1452
|
+
*
|
|
1453
|
+
* @example
|
|
1454
|
+
* ```ts
|
|
1455
|
+
* const users = db.use(Users)
|
|
1456
|
+
* const result = await users.deleteMany({ role: 'guest' })
|
|
1457
|
+
* console.log(result.deletedCount) // number of guests removed
|
|
1458
|
+
* ```
|
|
1459
|
+
*/
|
|
1460
|
+
deleteMany(filter: TypedFilter<InferDocument<TDef>>): Promise<DeleteResult>;
|
|
1461
|
+
/**
|
|
1462
|
+
* Find a single document matching the filter, delete it, and return the document.
|
|
1463
|
+
*
|
|
1464
|
+
* Returns the deleted document, or `null` if no document matches the filter.
|
|
1465
|
+
* The returned document is validated against the collection's Zod schema
|
|
1466
|
+
* using the same resolution logic as {@link findOne}.
|
|
1467
|
+
*
|
|
1468
|
+
* @param filter - Type-safe filter to match documents.
|
|
1469
|
+
* @param options - Optional settings: `validate`.
|
|
1470
|
+
* @returns The deleted document, or `null` if no document matches.
|
|
1471
|
+
* @throws {ZodmonValidationError} When the returned document fails schema validation in strict mode.
|
|
1472
|
+
*
|
|
1473
|
+
* @example
|
|
1474
|
+
* ```ts
|
|
1475
|
+
* const users = db.use(Users)
|
|
1476
|
+
* const user = await users.findOneAndDelete({ name: 'Ada' })
|
|
1477
|
+
* if (user) console.log(user.name) // 'Ada' (the deleted document)
|
|
1478
|
+
* ```
|
|
1479
|
+
*/
|
|
1480
|
+
findOneAndDelete(filter: TypedFilter<InferDocument<TDef>>, options?: FindOneAndDeleteOptions): Promise<InferDocument<TDef> | null>;
|
|
1481
|
+
/**
|
|
1482
|
+
* Synchronize the indexes declared in this collection's schema with MongoDB.
|
|
1483
|
+
*
|
|
1484
|
+
* Compares the desired indexes (from field-level `.index()` / `.unique()` /
|
|
1485
|
+
* `.text()` / `.expireAfter()` and compound `indexes` in collection options)
|
|
1486
|
+
* with the indexes that currently exist in MongoDB, then creates, drops, or
|
|
1487
|
+
* reports differences depending on the options.
|
|
1488
|
+
*
|
|
1489
|
+
* @param options - Optional sync behavior (dryRun, dropOrphaned).
|
|
1490
|
+
* @returns A summary of created, dropped, skipped, and stale indexes.
|
|
1491
|
+
*
|
|
1492
|
+
* @example
|
|
1493
|
+
* ```ts
|
|
1494
|
+
* const users = db.use(Users)
|
|
1495
|
+
* const result = await users.syncIndexes()
|
|
1496
|
+
* console.log('Created:', result.created)
|
|
1497
|
+
* console.log('Stale:', result.stale.map(s => s.name))
|
|
1498
|
+
* ```
|
|
1499
|
+
*
|
|
1500
|
+
* @example
|
|
1501
|
+
* ```ts
|
|
1502
|
+
* // Dry run to preview changes without modifying the database
|
|
1503
|
+
* const diff = await users.syncIndexes({ dryRun: true })
|
|
1504
|
+
* console.log('Would create:', diff.created)
|
|
1505
|
+
* console.log('Would drop:', diff.dropped)
|
|
1506
|
+
* ```
|
|
1507
|
+
*/
|
|
1508
|
+
syncIndexes(options?: SyncIndexesOptions): Promise<SyncIndexesResult>;
|
|
740
1509
|
}
|
|
741
1510
|
|
|
742
1511
|
/**
|
|
@@ -771,13 +1540,28 @@ declare class Database {
|
|
|
771
1540
|
* @param def - A collection definition created by `collection()`.
|
|
772
1541
|
* @returns A typed collection handle for CRUD operations.
|
|
773
1542
|
*/
|
|
774
|
-
use<TShape extends z.core.$ZodShape>(def: CollectionDefinition<TShape>): CollectionHandle<CollectionDefinition<TShape>>;
|
|
1543
|
+
use<TShape extends z.core.$ZodShape, TIndexes extends readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[] = readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[]>(def: CollectionDefinition<TShape, TIndexes>): CollectionHandle<CollectionDefinition<TShape, TIndexes>>;
|
|
775
1544
|
/**
|
|
776
|
-
* Synchronize indexes
|
|
1545
|
+
* Synchronize indexes for all registered collections with MongoDB.
|
|
1546
|
+
*
|
|
1547
|
+
* Iterates every collection registered via {@link use} and calls
|
|
1548
|
+
* {@link syncIndexes} on each one. Returns a record keyed by collection
|
|
1549
|
+
* name with the sync result for each.
|
|
1550
|
+
*
|
|
1551
|
+
* @param options - Optional sync behavior (dryRun, dropOrphaned).
|
|
1552
|
+
* @returns A record mapping collection names to their sync results.
|
|
777
1553
|
*
|
|
778
|
-
*
|
|
1554
|
+
* @example
|
|
1555
|
+
* ```ts
|
|
1556
|
+
* const db = createClient('mongodb://localhost:27017', 'myapp')
|
|
1557
|
+
* db.use(Users)
|
|
1558
|
+
* db.use(Posts)
|
|
1559
|
+
* const results = await db.syncIndexes()
|
|
1560
|
+
* console.log(results['users'].created) // ['email_1']
|
|
1561
|
+
* console.log(results['posts'].created) // ['title_1']
|
|
1562
|
+
* ```
|
|
779
1563
|
*/
|
|
780
|
-
syncIndexes(): Promise<
|
|
1564
|
+
syncIndexes(options?: SyncIndexesOptions): Promise<Record<string, SyncIndexesResult>>;
|
|
781
1565
|
/**
|
|
782
1566
|
* Execute a function within a MongoDB transaction with auto-commit/rollback.
|
|
783
1567
|
*
|
|
@@ -852,7 +1636,9 @@ declare function extractFieldIndexes(shape: z.core.$ZodShape): FieldIndexDefinit
|
|
|
852
1636
|
* })
|
|
853
1637
|
* ```
|
|
854
1638
|
*/
|
|
855
|
-
declare function collection<TShape extends z.core.$ZodShape>(name: string, shape: TShape, options?: CollectionOptions<Extract<keyof TShape, string
|
|
1639
|
+
declare function collection<TShape extends z.core.$ZodShape, const TIndexes extends readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[] = readonly CompoundIndexDefinition<Extract<keyof TShape, string>>[]>(name: string, shape: TShape, options?: Omit<CollectionOptions<Extract<keyof TShape, string>>, 'indexes'> & {
|
|
1640
|
+
indexes?: TIndexes;
|
|
1641
|
+
}): CollectionDefinition<TShape, [...TIndexes]>;
|
|
856
1642
|
|
|
857
1643
|
type IndexDirection = 1 | -1;
|
|
858
1644
|
type CompoundIndexOptions = NonNullable<CompoundIndexDefinition['options']>;
|
|
@@ -880,9 +1666,27 @@ declare class IndexBuilder<TKeys extends string> {
|
|
|
880
1666
|
readonly options: CompoundIndexOptions;
|
|
881
1667
|
constructor(fields: Record<TKeys, IndexDirection>);
|
|
882
1668
|
private _clone;
|
|
883
|
-
unique():
|
|
884
|
-
sparse():
|
|
885
|
-
|
|
1669
|
+
unique(): this;
|
|
1670
|
+
sparse(): this;
|
|
1671
|
+
/**
|
|
1672
|
+
* Set a custom name for this index, preserving the literal type.
|
|
1673
|
+
*
|
|
1674
|
+
* The returned builder carries the literal name type via an intersection,
|
|
1675
|
+
* enabling type-safe `.hint()` on cursors that only accepts declared names.
|
|
1676
|
+
*
|
|
1677
|
+
* @param name - The index name.
|
|
1678
|
+
* @returns A new IndexBuilder with the name recorded at the type level.
|
|
1679
|
+
*
|
|
1680
|
+
* @example
|
|
1681
|
+
* ```ts
|
|
1682
|
+
* index({ email: 1, role: -1 }).name('email_role_idx')
|
|
1683
|
+
* ```
|
|
1684
|
+
*/
|
|
1685
|
+
name<TName extends string>(name: TName): IndexBuilder<TKeys> & {
|
|
1686
|
+
readonly options: {
|
|
1687
|
+
readonly name: TName;
|
|
1688
|
+
};
|
|
1689
|
+
};
|
|
886
1690
|
}
|
|
887
1691
|
/**
|
|
888
1692
|
* Create a compound index definition with a fluent builder API.
|
|
@@ -1047,6 +1851,287 @@ declare function oid(value: ObjectId): ObjectId;
|
|
|
1047
1851
|
*/
|
|
1048
1852
|
declare function isOid(value: unknown): value is ObjectId;
|
|
1049
1853
|
|
|
1854
|
+
/**
|
|
1855
|
+
* A normalized index specification ready for comparison and creation.
|
|
1856
|
+
*
|
|
1857
|
+
* `key` maps field paths to direction (`1`, `-1`, or `'text'`).
|
|
1858
|
+
* `options` holds MongoDB index options (`unique`, `sparse`, etc.).
|
|
1859
|
+
*
|
|
1860
|
+
* @example
|
|
1861
|
+
* ```ts
|
|
1862
|
+
* const spec: IndexSpec = {
|
|
1863
|
+
* key: { email: 1 },
|
|
1864
|
+
* options: { unique: true },
|
|
1865
|
+
* }
|
|
1866
|
+
* ```
|
|
1867
|
+
*/
|
|
1868
|
+
type IndexSpec = {
|
|
1869
|
+
key: Record<string, 1 | -1 | 'text'>;
|
|
1870
|
+
options: Record<string, unknown>;
|
|
1871
|
+
};
|
|
1872
|
+
/**
|
|
1873
|
+
* Convert a field-level index definition to a normalized {@link IndexSpec}.
|
|
1874
|
+
*
|
|
1875
|
+
* Maps schema metadata (`text`, `descending`, `unique`, `sparse`, `expireAfter`,
|
|
1876
|
+
* `partial`) to their MongoDB driver equivalents.
|
|
1877
|
+
*
|
|
1878
|
+
* @param def - A field index definition extracted from schema metadata.
|
|
1879
|
+
* @returns A normalized index spec with key and options.
|
|
1880
|
+
*
|
|
1881
|
+
* @example
|
|
1882
|
+
* ```ts
|
|
1883
|
+
* const spec = toFieldIndexSpec({ field: 'email', indexed: true, unique: true })
|
|
1884
|
+
* // => { key: { email: 1 }, options: { unique: true } }
|
|
1885
|
+
*
|
|
1886
|
+
* const ttl = toFieldIndexSpec({ field: 'expiresAt', indexed: true, expireAfter: 3600 })
|
|
1887
|
+
* // => { key: { expiresAt: 1 }, options: { expireAfterSeconds: 3600 } }
|
|
1888
|
+
* ```
|
|
1889
|
+
*/
|
|
1890
|
+
declare function toFieldIndexSpec(def: FieldIndexDefinition): IndexSpec;
|
|
1891
|
+
/**
|
|
1892
|
+
* Convert a compound index definition to a normalized {@link IndexSpec}.
|
|
1893
|
+
*
|
|
1894
|
+
* Copies the `fields` map directly to `key` and maps builder options
|
|
1895
|
+
* (`unique`, `sparse`, `name`, `partial`) to MongoDB driver equivalents.
|
|
1896
|
+
*
|
|
1897
|
+
* @param def - A compound index definition from the collection options.
|
|
1898
|
+
* @returns A normalized index spec with key and options.
|
|
1899
|
+
*
|
|
1900
|
+
* @example
|
|
1901
|
+
* ```ts
|
|
1902
|
+
* const spec = toCompoundIndexSpec({
|
|
1903
|
+
* fields: { email: 1, role: -1 },
|
|
1904
|
+
* options: { unique: true, name: 'email_role_idx' },
|
|
1905
|
+
* })
|
|
1906
|
+
* // => { key: { email: 1, role: -1 }, options: { unique: true, name: 'email_role_idx' } }
|
|
1907
|
+
* ```
|
|
1908
|
+
*/
|
|
1909
|
+
declare function toCompoundIndexSpec(def: CompoundIndexDefinition): IndexSpec;
|
|
1910
|
+
/**
|
|
1911
|
+
* Produce a stable, deterministic string from an index key for comparison.
|
|
1912
|
+
*
|
|
1913
|
+
* Entries are sorted alphabetically by field name and formatted as
|
|
1914
|
+
* `field:direction` pairs joined by commas. Two index keys that should be
|
|
1915
|
+
* considered the same will always produce the same string.
|
|
1916
|
+
*
|
|
1917
|
+
* @param key - An index key mapping field names to direction.
|
|
1918
|
+
* @returns A string like `'email:1,role:-1'`.
|
|
1919
|
+
*
|
|
1920
|
+
* @example
|
|
1921
|
+
* ```ts
|
|
1922
|
+
* serializeIndexKey({ email: 1, role: -1 })
|
|
1923
|
+
* // => 'email:1,role:-1'
|
|
1924
|
+
*
|
|
1925
|
+
* serializeIndexKey({ name: 'text' })
|
|
1926
|
+
* // => 'name:text'
|
|
1927
|
+
* ```
|
|
1928
|
+
*/
|
|
1929
|
+
declare function serializeIndexKey(key: Record<string, 1 | -1 | 'text'>): string;
|
|
1930
|
+
|
|
1931
|
+
/**
|
|
1932
|
+
* Structural constraint for the handle argument of {@link syncIndexes}.
|
|
1933
|
+
*
|
|
1934
|
+
* Uses a structural type rather than `CollectionHandle<AnyCollection>` to avoid
|
|
1935
|
+
* TypeScript variance issues with `exactOptionalPropertyTypes`. Any collection
|
|
1936
|
+
* handle returned by `db.use()` satisfies this constraint.
|
|
1937
|
+
*/
|
|
1938
|
+
type SyncableHandle = {
|
|
1939
|
+
readonly definition: {
|
|
1940
|
+
readonly fieldIndexes: FieldIndexDefinition[];
|
|
1941
|
+
readonly compoundIndexes: readonly CompoundIndexDefinition[];
|
|
1942
|
+
};
|
|
1943
|
+
readonly native: Collection<any>;
|
|
1944
|
+
};
|
|
1945
|
+
/**
|
|
1946
|
+
* Extract the comparable options from a MongoDB index info object.
|
|
1947
|
+
*
|
|
1948
|
+
* Pulls only the keys listed in {@link COMPARABLE_OPTION_KEYS} from the raw
|
|
1949
|
+
* index info returned by `listIndexes()`. Keys whose value is `undefined`
|
|
1950
|
+
* are omitted so that JSON comparison works correctly.
|
|
1951
|
+
*
|
|
1952
|
+
* @param info - A raw MongoDB index info object.
|
|
1953
|
+
* @returns A plain object with only the relevant option keys.
|
|
1954
|
+
*
|
|
1955
|
+
* @example
|
|
1956
|
+
* ```ts
|
|
1957
|
+
* const opts = extractComparableOptions({ v: 2, unique: true, key: { email: 1 } })
|
|
1958
|
+
* // => { unique: true }
|
|
1959
|
+
* ```
|
|
1960
|
+
*/
|
|
1961
|
+
declare function extractComparableOptions(info: Record<string, unknown>): Record<string, unknown>;
|
|
1962
|
+
/**
|
|
1963
|
+
* Generate the default MongoDB index name from a key spec.
|
|
1964
|
+
*
|
|
1965
|
+
* MongoDB names indexes by joining `field_direction` pairs with underscores.
|
|
1966
|
+
* For example, `{ email: 1, role: -1 }` becomes `'email_1_role_-1'`.
|
|
1967
|
+
*
|
|
1968
|
+
* @param key - An index key mapping field names to direction.
|
|
1969
|
+
* @returns The generated index name string.
|
|
1970
|
+
*
|
|
1971
|
+
* @example
|
|
1972
|
+
* ```ts
|
|
1973
|
+
* generateIndexName({ email: 1 })
|
|
1974
|
+
* // => 'email_1'
|
|
1975
|
+
*
|
|
1976
|
+
* generateIndexName({ email: 1, role: -1 })
|
|
1977
|
+
* // => 'email_1_role_-1'
|
|
1978
|
+
* ```
|
|
1979
|
+
*/
|
|
1980
|
+
declare function generateIndexName(key: Record<string, 1 | -1 | 'text'>): string;
|
|
1981
|
+
/**
|
|
1982
|
+
* Synchronize the indexes declared in a collection's schema with MongoDB.
|
|
1983
|
+
*
|
|
1984
|
+
* Compares the desired indexes (from field-level and compound index definitions)
|
|
1985
|
+
* with the indexes that currently exist in MongoDB, then creates, drops, or
|
|
1986
|
+
* reports differences depending on the options.
|
|
1987
|
+
*
|
|
1988
|
+
* **Algorithm:**
|
|
1989
|
+
* 1. Build desired specs from field indexes and compound indexes.
|
|
1990
|
+
* 2. Fetch existing indexes from MongoDB via `listIndexes()`.
|
|
1991
|
+
* 3. For each desired spec, compare against existing:
|
|
1992
|
+
* - Missing → create (unless `dryRun`).
|
|
1993
|
+
* - Present with same options → skip.
|
|
1994
|
+
* - Present with different options → stale (or drop+recreate if `dropOrphaned`).
|
|
1995
|
+
* 4. For each existing index not in desired set (excluding `_id_`):
|
|
1996
|
+
* - If `dropOrphaned` → drop (unless `dryRun`).
|
|
1997
|
+
* 5. Return a summary of all actions taken.
|
|
1998
|
+
*
|
|
1999
|
+
* @param handle - A collection handle created by `db.use()`.
|
|
2000
|
+
* @param options - Optional sync behavior (dryRun, dropOrphaned).
|
|
2001
|
+
* @returns A summary of created, dropped, skipped, and stale indexes.
|
|
2002
|
+
*
|
|
2003
|
+
* @example
|
|
2004
|
+
* ```ts
|
|
2005
|
+
* import { syncIndexes } from '@zodmon/core'
|
|
2006
|
+
*
|
|
2007
|
+
* const users = db.use(Users)
|
|
2008
|
+
* const result = await syncIndexes(users)
|
|
2009
|
+
* console.log('Created:', result.created)
|
|
2010
|
+
* console.log('Stale:', result.stale.map(s => s.name))
|
|
2011
|
+
* ```
|
|
2012
|
+
*
|
|
2013
|
+
* @example
|
|
2014
|
+
* ```ts
|
|
2015
|
+
* // Dry run — no changes made
|
|
2016
|
+
* const diff = await syncIndexes(users, { dryRun: true })
|
|
2017
|
+
* console.log('Would create:', diff.created)
|
|
2018
|
+
* console.log('Would drop:', diff.dropped)
|
|
2019
|
+
* ```
|
|
2020
|
+
*/
|
|
2021
|
+
declare function syncIndexes(handle: SyncableHandle, options?: SyncIndexesOptions): Promise<SyncIndexesResult>;
|
|
2022
|
+
|
|
2023
|
+
/**
|
|
2024
|
+
* Structural constraint for the definition argument of {@link checkUnindexedFields}.
|
|
2025
|
+
*
|
|
2026
|
+
* Uses a structural type rather than `CollectionDefinition<z.core.$ZodShape>` to avoid
|
|
2027
|
+
* TypeScript variance issues with `exactOptionalPropertyTypes`. Any collection
|
|
2028
|
+
* definition returned by `collection()` satisfies this constraint.
|
|
2029
|
+
*/
|
|
2030
|
+
type WarnableDefinition = {
|
|
2031
|
+
readonly name: string;
|
|
2032
|
+
readonly fieldIndexes: FieldIndexDefinition[];
|
|
2033
|
+
readonly compoundIndexes: readonly CompoundIndexDefinition[];
|
|
2034
|
+
readonly options: {
|
|
2035
|
+
warnUnindexedQueries?: boolean;
|
|
2036
|
+
};
|
|
2037
|
+
};
|
|
2038
|
+
/**
|
|
2039
|
+
* Warn about unindexed fields used in a query filter.
|
|
2040
|
+
*
|
|
2041
|
+
* When `warnUnindexedQueries` is enabled on a collection definition, this
|
|
2042
|
+
* function checks each top-level field in the filter against the collection's
|
|
2043
|
+
* declared indexes. Fields that are not covered by any index produce a
|
|
2044
|
+
* `console.warn` message to help identify queries that may cause full
|
|
2045
|
+
* collection scans in development.
|
|
2046
|
+
*
|
|
2047
|
+
* **Covered fields:**
|
|
2048
|
+
* - `_id` (always indexed by MongoDB)
|
|
2049
|
+
* - Fields with `.index()`, `.unique()`, `.text()`, or `.expireAfter()` (field-level indexes)
|
|
2050
|
+
* - The **first** field of each compound index (prefix matching)
|
|
2051
|
+
*
|
|
2052
|
+
* **Skipped keys:**
|
|
2053
|
+
* - MongoDB operators: `$or`, `$and`, `$nor`, `$text`, `$where`, `$expr`, `$comment`
|
|
2054
|
+
*
|
|
2055
|
+
* This function is a no-op (zero overhead) when `warnUnindexedQueries` is not
|
|
2056
|
+
* explicitly set to `true`.
|
|
2057
|
+
*
|
|
2058
|
+
* @param definition - The collection definition containing index metadata.
|
|
2059
|
+
* @param filter - The query filter to check for unindexed fields.
|
|
2060
|
+
*
|
|
2061
|
+
* @example
|
|
2062
|
+
* ```ts
|
|
2063
|
+
* import { collection, checkUnindexedFields } from '@zodmon/core'
|
|
2064
|
+
*
|
|
2065
|
+
* const Users = collection('users', {
|
|
2066
|
+
* email: z.string().unique(),
|
|
2067
|
+
* name: z.string(),
|
|
2068
|
+
* }, { warnUnindexedQueries: true })
|
|
2069
|
+
*
|
|
2070
|
+
* // No warning — email is indexed
|
|
2071
|
+
* checkUnindexedFields(Users, { email: 'ada@example.com' })
|
|
2072
|
+
*
|
|
2073
|
+
* // Warns: "[zodmon] warn: query on 'users' uses unindexed field 'name'"
|
|
2074
|
+
* checkUnindexedFields(Users, { name: 'Ada' })
|
|
2075
|
+
* ```
|
|
2076
|
+
*/
|
|
2077
|
+
declare function checkUnindexedFields(definition: WarnableDefinition, filter: Record<string, unknown>): void;
|
|
2078
|
+
|
|
2079
|
+
/**
|
|
2080
|
+
* Convenience namespace that groups all query operators under a single import.
|
|
2081
|
+
*
|
|
2082
|
+
* Property names strip the `$` prefix since the namespace itself is `$`.
|
|
2083
|
+
* Individual operator exports (`$or`, `$gt`, etc.) remain available for
|
|
2084
|
+
* tree-shaking — this namespace is the ergonomic alternative.
|
|
2085
|
+
*
|
|
2086
|
+
* @example
|
|
2087
|
+
* ```ts
|
|
2088
|
+
* import { $ } from '@zodmon/core'
|
|
2089
|
+
*
|
|
2090
|
+
* users.find($.or({ role: 'admin' }, { age: $.gte(25) }))
|
|
2091
|
+
* users.find({ name: $.regex(/^A/i), age: $.gt(18) })
|
|
2092
|
+
* users.find($.and({ published: true }, { views: $.gte(100) }))
|
|
2093
|
+
* ```
|
|
2094
|
+
*/
|
|
2095
|
+
declare const $: {
|
|
2096
|
+
readonly eq: <V>(value: V) => {
|
|
2097
|
+
$eq: V;
|
|
2098
|
+
};
|
|
2099
|
+
readonly ne: <V>(value: V) => {
|
|
2100
|
+
$ne: V;
|
|
2101
|
+
};
|
|
2102
|
+
readonly gt: <V>(value: V) => {
|
|
2103
|
+
$gt: V;
|
|
2104
|
+
};
|
|
2105
|
+
readonly gte: <V>(value: V) => {
|
|
2106
|
+
$gte: V;
|
|
2107
|
+
};
|
|
2108
|
+
readonly lt: <V>(value: V) => {
|
|
2109
|
+
$lt: V;
|
|
2110
|
+
};
|
|
2111
|
+
readonly lte: <V>(value: V) => {
|
|
2112
|
+
$lte: V;
|
|
2113
|
+
};
|
|
2114
|
+
readonly in: <V>(values: V[]) => {
|
|
2115
|
+
$in: V[];
|
|
2116
|
+
};
|
|
2117
|
+
readonly nin: <V>(values: V[]) => {
|
|
2118
|
+
$nin: V[];
|
|
2119
|
+
};
|
|
2120
|
+
readonly exists: (flag?: boolean) => {
|
|
2121
|
+
$exists: boolean;
|
|
2122
|
+
};
|
|
2123
|
+
readonly regex: (pattern: RegExp | string) => {
|
|
2124
|
+
$regex: RegExp | string;
|
|
2125
|
+
};
|
|
2126
|
+
readonly not: <O extends Record<string, unknown>>(op: O) => {
|
|
2127
|
+
$not: O;
|
|
2128
|
+
};
|
|
2129
|
+
readonly or: <T>(...filters: NoInfer<TypedFilter<T>>[]) => TypedFilter<T>;
|
|
2130
|
+
readonly and: <T>(...filters: NoInfer<TypedFilter<T>>[]) => TypedFilter<T>;
|
|
2131
|
+
readonly nor: <T>(...filters: NoInfer<TypedFilter<T>>[]) => TypedFilter<T>;
|
|
2132
|
+
readonly raw: <T = any>(filter: Record<string, unknown>) => TypedFilter<T>;
|
|
2133
|
+
};
|
|
2134
|
+
|
|
1050
2135
|
/**
|
|
1051
2136
|
* Matches values equal to the specified value.
|
|
1052
2137
|
*
|
|
@@ -1234,219 +2319,6 @@ declare const $nor: <T>(...filters: NoInfer<TypedFilter<T>>[]) => TypedFilter<T>
|
|
|
1234
2319
|
*/
|
|
1235
2320
|
declare const raw: <T = any>(filter: Record<string, unknown>) => TypedFilter<T>;
|
|
1236
2321
|
|
|
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
2322
|
/**
|
|
1451
2323
|
* Type-level marker that carries the target collection type through the
|
|
1452
2324
|
* type system. Intersected with the schema return type by `.ref()` so
|
|
@@ -1524,11 +2396,70 @@ declare module 'zod' {
|
|
|
1524
2396
|
* ```
|
|
1525
2397
|
*/
|
|
1526
2398
|
declare function getRefMetadata(schema: unknown): RefMetadata | undefined;
|
|
2399
|
+
|
|
2400
|
+
/**
|
|
2401
|
+
* Shorthand for `CollectionHandle<TDef>`.
|
|
2402
|
+
*
|
|
2403
|
+
* Reduces boilerplate in function signatures that accept a collection handle.
|
|
2404
|
+
*
|
|
2405
|
+
* @example
|
|
2406
|
+
* ```ts
|
|
2407
|
+
* import { type HandleOf } from '@zodmon/core'
|
|
2408
|
+
*
|
|
2409
|
+
* const Users = collection('users', { name: z.string() })
|
|
2410
|
+
*
|
|
2411
|
+
* async function seed(users: HandleOf<typeof Users>) {
|
|
2412
|
+
* await users.insertOne({ name: 'Ada' })
|
|
2413
|
+
* }
|
|
2414
|
+
* ```
|
|
2415
|
+
*/
|
|
2416
|
+
type HandleOf<TDef extends AnyCollection> = CollectionHandle<TDef>;
|
|
2417
|
+
/**
|
|
2418
|
+
* Shorthand for `TypedFilter<InferDocument<TDef>>`.
|
|
2419
|
+
*
|
|
2420
|
+
* Derives the filter type directly from a collection definition,
|
|
2421
|
+
* removing the need to compose `TypedFilter` and `InferDocument` manually.
|
|
2422
|
+
*
|
|
2423
|
+
* @example
|
|
2424
|
+
* ```ts
|
|
2425
|
+
* import { type FilterOf } from '@zodmon/core'
|
|
2426
|
+
*
|
|
2427
|
+
* const Users = collection('users', { name: z.string(), age: z.number() })
|
|
2428
|
+
*
|
|
2429
|
+
* const conditions: FilterOf<typeof Users>[] = []
|
|
2430
|
+
* conditions.push({ age: { $gte: 18 } })
|
|
2431
|
+
* ```
|
|
2432
|
+
*/
|
|
2433
|
+
type FilterOf<TDef extends AnyCollection> = TypedFilter<InferDocument<TDef>>;
|
|
2434
|
+
/**
|
|
2435
|
+
* Shorthand for `TypedUpdateFilter<InferDocument<TDef>>`.
|
|
2436
|
+
*
|
|
2437
|
+
* Derives the update filter type directly from a collection definition.
|
|
2438
|
+
*
|
|
2439
|
+
* @example
|
|
2440
|
+
* ```ts
|
|
2441
|
+
* import { type UpdateFilterOf } from '@zodmon/core'
|
|
2442
|
+
*
|
|
2443
|
+
* const Users = collection('users', { name: z.string(), role: z.string() })
|
|
2444
|
+
*
|
|
2445
|
+
* const update: UpdateFilterOf<typeof Users> = { $set: { role: 'admin' } }
|
|
2446
|
+
* ```
|
|
2447
|
+
*/
|
|
2448
|
+
type UpdateFilterOf<TDef extends AnyCollection> = TypedUpdateFilter<InferDocument<TDef>>;
|
|
1527
2449
|
/**
|
|
1528
|
-
*
|
|
2450
|
+
* Shorthand for `TypedSort<InferDocument<TDef>>`.
|
|
2451
|
+
*
|
|
2452
|
+
* Derives the sort specification type directly from a collection definition.
|
|
2453
|
+
*
|
|
2454
|
+
* @example
|
|
2455
|
+
* ```ts
|
|
2456
|
+
* import { type SortOf } from '@zodmon/core'
|
|
1529
2457
|
*
|
|
1530
|
-
*
|
|
2458
|
+
* const Users = collection('users', { name: z.string(), age: z.number() })
|
|
2459
|
+
*
|
|
2460
|
+
* const sort: SortOf<typeof Users> = { age: -1, name: 1 }
|
|
2461
|
+
* ```
|
|
1531
2462
|
*/
|
|
1532
|
-
|
|
2463
|
+
type SortOf<TDef extends AnyCollection> = TypedSort<InferDocument<TDef>>;
|
|
1533
2464
|
|
|
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,
|
|
2465
|
+
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 IndexNames, type IndexOptions, type IndexSpec, 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 StaleIndex, type SyncIndexesOptions, type SyncIndexesResult, type TypedFilter, TypedFindCursor, type TypedSort, type TypedUpdateFilter, type UnsetFields, type UpdateFilterOf, type UpdateOptions, type ValidationMode, type ZodObjectId, ZodmonNotFoundError, ZodmonValidationError, checkUnindexedFields, collection, createClient, deleteMany, deleteOne, extractComparableOptions, extractDbName, extractFieldIndexes, find, findOne, findOneAndDelete, findOneAndUpdate, findOneOrThrow, generateIndexName, getIndexMetadata, getRefMetadata, index, insertMany, insertOne, isOid, objectId, oid, raw, serializeIndexKey, syncIndexes, toCompoundIndexSpec, toFieldIndexSpec, updateMany, updateOne };
|