import { Model, Document, Types, DocumentQuery, Query, Connection } from 'mongoose'; import { pick, PartialDeep, groupBy } from 'lodash'; import { KeyValue } from '../types/data.types'; const treeify = require('array-to-tree'); export class Repository { static async remove(model: Model, id: string): Promise { const ids = id.split(','); if (ids.length > 1) { return this.removeItems(model, ids); } else { return new Promise((resolve, reject) => { model.findOneAndRemove({ _id: id }).exec((err, res) => { if (err) { reject(err); } else { if (res) resolve(true); else { resolve(false); } } }); }); } } static async removeItems(model: Model, ids: string[]): Promise { return new Promise((resolve, reject) => { model.remove({ _id: { $in: ids } }).exec((err, res) => { if (err) { reject(err); } else { resolve(true); } }); }); } static async get(model: Model, id: string, populates?: any[]): Promise { const option: any = {}; return new Promise((resolve, reject) => { if (populates && populates.length) { option.populate = populates; } model.findOne({ _id: id }, null, option).exec((err, res: any) => { if (err) { reject(err); } else { resolve(res); } }); }); } static async search(model: Model, keyword?: string, id?: string, category = '', limit: number = 10, labelField = 'name', valueField = '_id'): Promise> { const query: any = keyword ? { name: new RegExp(keyword, 'i') } : {}; if (category) { query.category = category; } const fields: any = {}; fields[labelField] = 1; fields[valueField] = 1; const docs = await model.find(query).select(fields) .limit(limit) .exec() || []; if (id && (Types.ObjectId.isValid(id) || valueField !== '_id')) { const conditions: any = {}; conditions[valueField] = id; const selected = await model.findOne(conditions).select(fields); if (selected) { const found = docs.findIndex((doc: any) => doc[valueField] == id); if (found === -1) { docs.push(selected); } } } return docs.map((item: any) => { const result: KeyValue = { label: item[labelField], value: item[valueField] }; return result; }); } static async deeplyFind( query: Model, id: string ): Promise { let current: any = await query.findOne({ _id: id }).select({ _id: 1, parent: 1 }).exec(); if (!current) { return []; } const items = await query.find().select({ _id: 1, parent: 1 }).exec() || []; const currentId = current.toObject()._id; const data = items.map(item => item.toObject()); const cached = groupBy(data, 'parent'); const children = cached[currentId]; if (!Array.isArray(children)) { return [currentId]; } const result: string[] = [currentId]; const stack = []; stack.push(...children); while (stack.length > 0) { const node: any = stack.pop(); result.push(node._id); const items = cached[node._id]; if (Array.isArray(items)) { for (let item of items) { stack.push(item); } } } return result; } static async query( query: DocumentQuery, collection: DocumentQuery, page: number = 1, size: number = 20, fields: string[] ) { page = page - 1; if (page < 0) { page = 0; } const countPromise = collection.count().exec(); const pure = (doc: Document, fields: Array) => { if (fields && Array.isArray(fields)) { return pick(doc, fields); } else { return doc.toJSON(); } } const docsPromise = query.skip(page * size).limit(size).exec(); const result = await Promise.all([countPromise, docsPromise]); let [count, docs] = result; docs = docs || []; const list = docs.map((doc) => pure(doc, fields) as TResponse); return { list: list, total: count } } static mergeProfile(user?: Document) { if (!user) { return null; } const doc = user.toObject(); const instance = Object.assign({}, doc, doc.profile); instance.id = doc._id; delete instance.profile; delete instance._id; delete instance.__v; delete instance.password; instance.createdAt = doc.createdAt; return instance; } }