import type { WithId, Filter, UpdateFilter, InsertOneResult, UpdateResult, DeleteResult, ObjectId, } from "mongodb"; /** * Flattens a complex type into a simpler object type for better readability in tooltips. */ export type Prettify = { [K in keyof T]: T[K]; } & {}; /** * Type for document creation - excludes _id which is auto-generated by MongoDB */ type CreateDocument = Omit; /** * Represents the options that can be passed to the populate method. */ export interface PopulateOptions { strategy?: "multiple" | "aggregation"; } /** * Utility type to replace a field's type in a document. * It correctly handles optional properties. * * @template Doc The base document type. * @template K The key of the field to replace. * @template T The new type for the field. */ export type Populate = Omit & { [P in K]: Doc[P] extends readonly unknown[] ? T[] | Extract : T | Extract; }; // QueryBuilder that's directly awaitable and supports type-safe populate export interface QueryBuilder extends PromiseLike[]> { populate( field: K, options?: PopulateOptions, ): QueryBuilder>>; // Make it thenable (awaitable) then[], TResult2 = never>( onfulfilled?: | ((value: WithId[]) => TResult1 | PromiseLike) | undefined | null, onrejected?: | ((reason: unknown) => TResult2 | PromiseLike) | undefined | null, ): PromiseLike; toJSON(): Promise>>[]>; } export interface SingleQueryBuilder extends PromiseLike | null> { populate( field: K, options?: PopulateOptions, ): SingleQueryBuilder>>; // Make it thenable (awaitable) then | null, TResult2 = never>( onfulfilled?: | ((value: WithId | null) => TResult1 | PromiseLike) | undefined | null, onrejected?: | ((reason: unknown) => TResult2 | PromiseLike) | undefined | null, ): PromiseLike; toJSON(): Promise>> | null>; } /** * Serializes a document type for JSON transport. * It converts types like ObjectId and Date to strings. */ type Primitives = string | number | boolean | null | undefined; export type JSONSerialized = T extends Primitives ? T : T extends ObjectId ? string : T extends Date ? string : T extends (infer U)[] ? JSONSerialized[] : T extends ReadonlyArray ? ReadonlyArray> : T extends object ? { [K in keyof T]: JSONSerialized } : T; export interface Model { find(filter?: Filter): QueryBuilder; findOne(filter: Filter): SingleQueryBuilder; create(doc: CreateDocument): Promise>; update(filter: Filter, update: UpdateFilter): Promise; delete(filter: Filter): Promise; toJSON(doc: WithId): Prettify>>; }