import { Db, ObjectId, WithId } from 'mongodb'; import { FFBProduction } from 'src/FFB/ffb-production.schema'; export class FFBProductionRepository { private readonly collectionName = 'FFB Production'; constructor(private readonly db: Db) { } private get collection() { return this.db.collection(this.collectionName); } async init() { const collections = await this.db.listCollections({ name: this.collectionName }).toArray(); if (collections.length === 0) { await this.db.createCollection(this.collectionName); console.log(`✅ Created collection: ${this.collectionName}`); } } async create(ffb: FFBProduction & { vector?: number[] }): Promise { const result = await this.collection.insertOne({ ...ffb, productionDate: new Date(ffb.productionDate), vector: ffb.vector, // optional vector }); return { ...ffb, _id: result.insertedId.toString() }; } async findAll(filter: Record = {}, options: { page?: number, limit?: number } = {}): Promise<{ data: (FFBProduction & { vector?: number[] })[], total: number }> { const { page = 1, limit = 10 } = options; const skip = (page - 1) * limit; const [results, total] = await Promise.all([ this.collection.find(filter).skip(skip).limit(limit).toArray(), this.collection.countDocuments(filter) ]); const data = results.map((r: WithId) => ({ ...r, _id: r._id?.toString(), })); return { data, total }; } async findById(id: string): Promise<(FFBProduction & { vector?: number[] }) | null> { const result = await this.collection.findOne({ _id: new ObjectId(id) as any }); return result ? { ...result, _id: result._id.toString() } : null; } async delete(id: string) { return this.collection.deleteOne({ _id: new ObjectId(id) as any }); } async deleteMany(filter: Record) { return this.collection.deleteMany(filter); } async update(id: string, update: Partial): Promise { await this.collection.updateOne( { _id: new ObjectId(id) as any }, { $set: update } ); } async findOne(filter: Record = {}): Promise { const result = await this.collection.findOne(filter); return result ? { ...result, _id: result._id.toString() } : null; } async distinct(field: string, filter: Record = {}): Promise { return this.collection.distinct(field, filter); } /** Optional: helper for vector search via aggregation */ async vectorSearch(vector: number[], k = 5, numCandidates = 50, filter: Record = {}) { return this.collection .aggregate([ { $vectorSearch: { index: 'vector_index', queryVector: vector, path: 'vector', numCandidates, limit: k, filter // Add filter here } }, { $project: { _id: 1, productionDate: 1, site: 1, phase: 1, block: 1, quantity: 1, quantityUom: 1, weight: 1, weightUom: 1, remarks: 1, score: { "$meta": "vectorSearchScore" } // correctly get the score } } ]) .toArray(); } async aggregate(pipeline: Array>): Promise { // Optional: log the pipeline for debugging // console.log('Executing aggregation pipeline:', JSON.stringify(pipeline, null, 2)); const pipelineWithDates = pipeline.map(stage => { if ('$match' in stage && 'productionDate' in stage.$match) { const pd = stage.$match.productionDate; if (pd.$gte) pd.$gte = new Date(pd.$gte); if (pd.$lte) pd.$lte = new Date(pd.$lte); } return stage; }); // Execute aggregation const results = await this.collection.aggregate(pipelineWithDates).toArray(); // console.log('Aggregation results:', results); // Optional: strip out any internal vector fields if accidentally included return results.map(r => { const { vector, ...rest } = r; return rest; }); } }