import { Db, Collection, AggregationCursor, AggregationCursorResult, CollectionAggregationOptions, MongoCallback, ObjectID } from "mongodb"; import { MongoCollection } from "../MongoCollection"; import { MongoSchemaRegistry } from "../MongoSchemaRegistry"; import { MongoSchema, ERelationType } from "../MongoSchema"; import * as util from "util"; export class MongoQuery { public isLean: boolean = false; public pipeline = []; public populatedFields:string[] = []; constructor(public collection: typeof MongoCollection, public query?: any) { if(query != null) { this.where(query); } } lean(isLean = true): this { this.isLean = isLean; return this; } where(clause?: any): this { this.pipeline.push({ $match: clause, }); return this; } sort(clause?: any): this { this.pipeline.push({ $sort: clause, }); return this; } gt(clause?: object): this { let fields = Object.keys(clause); var query = {}; for(let f of fields) { query[f] = { $gt: clause[f] }; } return this.where(query); } gte(clause?: object): this { let fields = Object.keys(clause); var query = {}; for(let f of fields) { query[f] = { $gte: clause[f] }; } return this.where(query); } lt(clause?: object): this { let fields = Object.keys(clause); var query = {}; for(let f of fields) { query[f] = { $lt: clause[f] }; } return this.where(query); } lte(clause?: object): this { let fields = Object.keys(clause); var query = {}; for(let f of fields) { query[f] = { $lte: clause[f] }; } return this.where(query); } skip(skip:number = 0): this { this.pipeline.push({ $skip: skip }); return this; } limit(limit:number = 0): this { this.pipeline.push({ $limit: limit }); return this; } populate(...fields:string[]): this { let schema = this.collection.getSchema(); for(var field of fields) { this._populate(field, schema);; } return this; } private _populate(fieldName: string, schema: MongoSchema) { let fields = fieldName.split("."); let currentSchema = schema; let fieldChain = []; for(let field of fields) { fieldChain.push(field); let fieldPath = fieldChain.join("."); let localField = currentSchema.getField(field); if(!localField || !localField.options || !localField.getReferencedCollection()) { throw new Error("Cant popoluate '" + field + "', '" + fieldPath + "' doesnt exists on schema: '" + currentSchema.name + "'"); } let foreignSchema = localField.getReferencedCollection().getSchema(); let foreignField = foreignSchema.getField(localField.getForeignFieldName()); if(this.populatedFields.indexOf(fieldPath) <= -1) { this.populatedFields.push(fieldPath); this.pipeline.push({ $lookup: { from: foreignSchema.name, localField: fieldPath, foreignField: foreignField.name, as: fieldPath, } }); // If its a single item then unwind into an object. if(localField.options.relationType == ERelationType.SingleObjectId) { this.pipeline.push({ $unwind: "$" + fieldPath, }); } } currentSchema = foreignSchema; } return this; } cast(): MongoQuery { return null; } aggregate(pipeline: any[] = [], options?: CollectionAggregationOptions, callback?: MongoCallback): AggregationCursor { return this.collection.getCollection().aggregate(pipeline); } cursor(cursorOptions?: { batchSize: number }, explain?: boolean): AggregationCursor { let schema = this.collection.getSchema(); let populateFields = schema.getAutoPopulateFieldNamesRecursive(); this.populate.apply(this, populateFields); return this.aggregate(this.pipeline, { cursor: cursorOptions, explain: explain, }); } };