UNPKG

@azteam/mongo-model

Version:

N/A

471 lines (413 loc) 12 kB
import _ from 'lodash'; import {AVAILABLE_STATUS} from '@azteam/constant'; import {ErrorException, NOT_INIT_METHOD} from '@azteam/error'; class DataRepository { constructor({activeModel, trashModel, redis}, dummyData = []) { this._model = activeModel; this._trashModel = trashModel; this.redis = redis; this._dummyData(dummyData); } async queryWithCache(cacheConfig, queryBuilder) { if (cacheConfig.key) { const redis = cacheConfig.redis ? cacheConfig.redis : this.redis; if (redis) { const cacheName = `${cacheConfig.trash ? 'trash_' : ''}${cacheConfig.key}`; let data = await redis.get(cacheName); if (!data) { data = await queryBuilder; redis.set(cacheName, data, cacheConfig.ttl ? cacheName.ttl : 300); // default cache 5 minutes } return data; } } return queryBuilder; } getModel() { if (this._model) { return this._model; } throw new ErrorException(NOT_INIT_METHOD); } getTrashModel() { if (this._trashModel) { return this._trashModel; } throw new ErrorException(NOT_INIT_METHOD); } async getUniqueFields() { const indexes = await this.getModel().collection.getIndexes({full: true}); return indexes .filter((index) => index.unique) .map((index) => Object.keys(index.key)) .flat(); } _dummyData(data) { data.map(async (item) => { const obj = await this.findOne(item.query); if (!obj) { const Model = this.getModel(); const model = new Model(); _.map(item.data, (value, key) => { model[key] = value; }); await model.save(); } }); } count(query, options = {}) { const queryBuilder = this.getModel().countDocuments(query, options); return this.queryWithCache( { ...options.cache, trash: false, }, queryBuilder ); } countTrash(query = {}, options = {}) { const queryBuilder = this.getTrashModel().countDocuments(query, options); return this.queryWithCache( { ...options.cache, trash: true, }, queryBuilder ); } find(query = {}, options = {}) { const {force, trash, cache, ...newOpts} = options; if (newOpts.lean !== false) { newOpts.lean = true; newOpts.leanWithId = true; } if (!newOpts.sort) { if (trash) { newOpts.sort = { deleted_at: 'desc', }; } else { newOpts.sort = { _id: 'desc', }; } } const limit = newOpts.limit && newOpts.limit < 10000 ? newOpts.limit : 10000; if (newOpts.page) { if (newOpts.page * limit >= 60000) { newOpts.allowDiskUse = true; } } else { newOpts.page = 1; } let queryBuilder = null; if (trash) { queryBuilder = this.getTrashModel().paginate(query, newOpts); } else { queryBuilder = this.getModel().paginate(query, newOpts); } return this.queryWithCache( { ...cache, trash, }, queryBuilder ); } findTrash(query = {}, options = {}) { return this.find(query, { ...options, trash: true, }); } findAvailable(query = {}, options = {}) { return this.find( { ...query, status: AVAILABLE_STATUS.AVAILABLE, }, options ); } findUnavailable(query = {}, options = {}) { return this.find( { ...query, status: AVAILABLE_STATUS.UNAVAILABLE, }, options ); } findWaiting(query = {}, options = {}) { return this.find( { ...query, status: AVAILABLE_STATUS.WAITING, }, options ); } // findNear(geo = {}, query = {}, options = {}) { // geo = { // name: 'geo', // coords: [], // ...geo, // }; // // if (geo.maxDistance) { // query[geo.name] = { // $nearSphere: { // $geometry: { // type: 'Point', // coordinates: geo.coords, // }, // $maxDistance: geo.maxDistance, // }, // }; // } else { // query[geo.name] = { // $nearSphere: { // $geometry: { // type: 'Point', // coordinates: geo.coords, // }, // }, // }; // } // // return this.find(query, { // ...options, // forceCountFn: true, // }); // } explain(query = {}, options = {}) { const {force, trash, ...newOpts} = options; let queryBuilder = null; if (trash) { queryBuilder = this.getTrashModel().findOne(query, null, { ...newOpts, explain: true, }); } else { queryBuilder = this.getModel().findOne(query, null, { ...newOpts, explain: true, }); } return queryBuilder; } findOne(query = {}, options = {}) { const {force, trash, cache, ...newOpts} = options; let queryBuilder = null; if (trash) { queryBuilder = this.getTrashModel().findOne(query, null, newOpts); } else { queryBuilder = this.getModel().findOne(query, null, newOpts); } return this.queryWithCache( { ...cache, trash, }, queryBuilder ); } findAll(query = {}, options = {}) { const {force, trash, cache, ...newOpts} = options; let queryBuilder = null; if (trash) { queryBuilder = this.getTrashModel().find(query); } else { queryBuilder = this.getModel().find(query); } if (newOpts.sort) { queryBuilder = queryBuilder.sort(newOpts.sort); } if (newOpts.limit) { queryBuilder = queryBuilder.limit(newOpts.limit); } if (newOpts.select) { queryBuilder = queryBuilder.select(newOpts.select); } if (newOpts.select || newOpts.lean) { queryBuilder = queryBuilder.lean({virtuals: true}); } return this.queryWithCache( { ...cache, trash, }, queryBuilder ); } findOneAvailable(query = {}, options = {}) { return this.findOne( { ...query, status: AVAILABLE_STATUS.AVAILABLE, }, options ); } findOneUnavailable(query = {}, options = {}) { return this.findOne( { ...query, status: AVAILABLE_STATUS.UNAVAILABLE, }, options ); } findOneWaiting(query = {}, options = {}) { return this.findOne( { ...query, status: AVAILABLE_STATUS.WAITING, }, options ); } findOneTrash(query = {}, options = {}) { return this.findOne(query, { ...options, trash: true, }); } // findOneNear(geo = {}, query = {}, options = {}) { // geo = { // name: 'geo', // coords: [], // ...geo, // }; // // if (geo.maxDistance) { // query[geo.name] = { // $nearSphere: { // $geometry: { // type: 'Point', // coordinates: geo.coords, // }, // $maxDistance: geo.maxDistance, // }, // }; // } else { // query[geo.name] = { // $nearSphere: { // $geometry: { // type: 'Point', // coordinates: geo.coords, // }, // }, // }; // } // // return this.findOne(query, options); // } findOneById(id, options = {}) { return this.findOne( { _id: id, }, options ); } findOneTrashById(id, options = {}) { return this.findOneTrash( { _id: id, }, options ); } async findOneBySlug(slug, options = {}) { return this.findOne( { $or: [ { slug, }, { related_slugs: slug, }, ], }, options ); } async findOneOrCreate(query, data, options = {}) { let model = await this.findOne(query, options); if (!model) { model = await this.create(data); } return model; } create(data, allow = [], createdId = null) { const Model = this.getModel(); const model = new Model(); if (createdId) { model.created_id = createdId; model.modified_id = createdId; } return model.loadData(data, allow).save(); } createByUser(createdId, data = {}, allow = []) { return this.create(data, allow, createdId); } async update(query, data) { const model = await this.findOne(query); return model.modify(data); } async updateById(id, data) { return this.update({_id: id}, data); } async fix(query, data) { const model = await this.findOne(query); return model.fix(data); } async fixById(id, data) { return this.fix({_id: id}, data); } async updateAll(query, data) { return this.getModel().updateMany(query, data); } async delete(obj, deletedId) { await this.getTrashModel().create({ ...obj.toJSON(), deleted_id: deletedId, deleted_at: Math.floor(Date.now() / 1000), }); await this.getModel().deleteOne({ _id: obj.id, }); } async restore(obj, restoredId) { await this.getModel().create({ ...obj.toJSON(), modified_id: restoredId, }); await this.getTrashModel().deleteOne({ _id: obj.id, }); } async destroy(id) { await this.getModel().deleteOne({ _id: id, }); await this.getTrashModel().deleteOne({ _id: id, }); } async destroyAll(query) { await this.getModel().deleteMany(query); await this.getTrashModel().deleteMany(query); } async cleanTrash(durationDay = 30) { const deletedAt = Math.floor(Date.now() / 1000) - 86400 * durationDay; await this.getTrashModel().deleteMany({ deleted_at: { $lte: deletedAt, }, }); } } export default DataRepository;