import { Db, Collection, ObjectId, Filter, UpdateFilter, Sort } from 'mongodb' import { getMongoDb } from '#providers/mongodb_provider' export abstract class BaseModel { static collectionName: string _id?: ObjectId createdAt?: Date updatedAt?: Date static getDb(): Db { return getMongoDb() } static getCollection(this: { collectionName: string; getDb(): Db }): Collection { return this.getDb().collection(this.collectionName) } static async find(this: { collectionName: string; getDb(): Db }, filter: Filter = {}): Promise { const collection = this.getDb().collection(this.collectionName) return collection.find(filter).toArray() } static async findById(this: { collectionName: string; getDb(): Db }, id: string | ObjectId): Promise { const collection = this.getDb().collection(this.collectionName) const objectId = typeof id === 'string' ? new ObjectId(id) : id return collection.findOne({ _id: objectId }) } static async findOne(this: { collectionName: string; getDb(): Db }, filter: Filter): Promise { const collection = this.getDb().collection(this.collectionName) return collection.findOne(filter) } static async create(this: { collectionName: string; getDb(): Db }, data: Partial): Promise { const collection = this.getDb().collection(this.collectionName) const now = new Date() const doc = { ...data, createdAt: now, updatedAt: now } const result = await collection.insertOne(doc) return { ...doc, _id: result.insertedId } } static async createMany(this: { collectionName: string; getDb(): Db }, data: Partial[]): Promise { const collection = this.getDb().collection(this.collectionName) const now = new Date() const docs = data.map((d) => ({ ...d, createdAt: now, updatedAt: now })) const result = await collection.insertMany(docs) return docs.map((doc, i) => ({ ...doc, _id: result.insertedIds[i] })) } static async updateOne( this: { collectionName: string; getDb(): Db }, filter: Filter, update: UpdateFilter | Partial ): Promise { const collection = this.getDb().collection(this.collectionName) const updateDoc = '$set' in update ? update : { $set: { ...update, updatedAt: new Date() } } return collection.updateOne(filter, updateDoc) } static async updateMany( this: { collectionName: string; getDb(): Db }, filter: Filter, update: UpdateFilter | Partial ): Promise { const collection = this.getDb().collection(this.collectionName) const updateDoc = '$set' in update ? update : { $set: { ...update, updatedAt: new Date() } } return collection.updateMany(filter, updateDoc) } static async deleteOne(this: { collectionName: string; getDb(): Db }, filter: Filter): Promise { const collection = this.getDb().collection(this.collectionName) const result = await collection.deleteOne(filter) return result.deletedCount === 1 } static async deleteMany(this: { collectionName: string; getDb(): Db }, filter: Filter): Promise { const collection = this.getDb().collection(this.collectionName) const result = await collection.deleteMany(filter) return result.deletedCount } static async paginate( this: { collectionName: string; getDb(): Db }, page: number, perPage: number, filter: Filter = {}, sort: Sort = {} ): Promise<{ data: any[]; total: number; page: number; perPage: number; lastPage: number }> { const collection = this.getDb().collection(this.collectionName) const total = await collection.countDocuments(filter) const lastPage = Math.max(1, Math.ceil(total / perPage)) const skip = (page - 1) * perPage const data = await collection.find(filter).sort(sort).skip(skip).limit(perPage).toArray() return { data, total, page, perPage, lastPage } } static query(this: { collectionName: string; getDb(): Db }) { const collection = this.getDb().collection(this.collectionName) return collection } async save(): Promise { const constructor = this.constructor as typeof BaseModel const collection = constructor.getDb().collection(constructor.collectionName) this.updatedAt = new Date() if (!this.createdAt) { this.createdAt = new Date() } const { _id, ...data } = this as any if (_id) { await collection.updateOne({ _id }, { $set: data }) } else { const result = await collection.insertOne(data) this._id = result.insertedId } } async delete(): Promise { const constructor = this.constructor as typeof BaseModel const collection = constructor.getDb().collection(constructor.collectionName) if (!this._id) return false const result = await collection.deleteOne({ _id: this._id }) return result.deletedCount === 1 } async refresh(): Promise { const constructor = this.constructor as typeof BaseModel const collection = constructor.getDb().collection(constructor.collectionName) if (!this._id) return const doc = await collection.findOne({ _id: this._id }) if (doc) { Object.assign(this, doc) } } }