import type { SchemaDefinition } from "../schemas/defineSchema"; import type { MonkkoClient } from "../connections/createConnection"; import type { Filter, Document, UpdateFilter, WithId } from "mongodb"; import type { Model, QueryBuilder, SingleQueryBuilder } from "./types"; // Type for document creation - excludes _id which is auto-generated by MongoDB type CreateDocument = Omit; import { QueryBuilderImpl, SingleQueryBuilderImpl, registerSchema, } from "./query-builder"; export function createModel< Doc extends Document, S extends SchemaDefinition = SchemaDefinition, >(schema: S, monkkoClient: MonkkoClient): Model { const coll = monkkoClient.client.db(schema.db).collection(schema.collection); // Register the schema for populate functionality registerSchema(schema); const toJSON = (doc: WithId) => { return JSON.parse(JSON.stringify(doc)); }; return { find(filter: Filter = {}): QueryBuilder { return new QueryBuilderImpl( coll, schema, monkkoClient, filter, toJSON, ); }, findOne(filter: Filter): SingleQueryBuilder { return new SingleQueryBuilderImpl( coll, schema, monkkoClient, filter, toJSON, ); }, update(filter: Filter, update: UpdateFilter) { // Note: Timestamp functionality is currently limited by MongoDB's strict TypeScript definitions // The user's Doc type should include createdAt/updatedAt fields when timestamps are enabled // but MongoDB's UpdateFilter type doesn't recognize dynamically added fields // For now, we disable timestamps in update operations to maintain type safety // TODO: Implement proper timestamp support when MongoDB's types are more flexible return coll.updateOne(filter, update); }, create(doc: CreateDocument) { // Apply field transformations (e.g., convert strings to ObjectIds for objectId fields) const transformedDoc = { ...doc } as Record; for (const [fieldName, fieldDef] of Object.entries(schema.fields)) { if (fieldDef.transform && transformedDoc[fieldName] !== undefined) { const value = transformedDoc[fieldName]; // Apply transform if value is a string (as expected by transform function) if (typeof value === 'string') { transformedDoc[fieldName] = fieldDef.transform(value); } } } // Use untyped collection to avoid type assertion issues const untypedColl = monkkoClient.client.db(schema.db).collection(schema.collection); return untypedColl.insertOne(transformedDoc); }, delete(filter: Filter) { return coll.deleteOne(filter); }, toJSON, }; }