UNPKG

@onesy/mongo

Version:

Utils for easier using of mongodb library.

818 lines (817 loc) 44 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseCollection = void 0; const mongodb = __importStar(require("mongodb")); const is_1 = __importDefault(require("@onesy/utils/is")); const copy_1 = __importDefault(require("@onesy/utils/copy")); const wait_1 = __importDefault(require("@onesy/utils/wait")); const getObjectValue_1 = __importDefault(require("@onesy/utils/getObjectValue")); const setObjectValue_1 = __importDefault(require("@onesy/utils/setObjectValue")); const models_1 = require("@onesy/models"); const errors_1 = require("@onesy/errors"); const OnesyDate_1 = __importDefault(require("@onesy/date/OnesyDate")); const duration_1 = __importDefault(require("@onesy/date/duration")); const Mongo_1 = __importDefault(require("./Mongo")); const OnesyMongo_1 = __importDefault(require("./OnesyMongo")); class BaseCollection { constructor(collectionName, mongo, Model, defaults) { this.collectionName = collectionName; this.mongo = mongo; this.Model = Model; this.defaults = defaults; this.collections = {}; if (!(mongo && mongo instanceof Mongo_1.default)) throw new errors_1.OnesyMongoError(`Mongo instance is required`); if (!collectionName) throw new errors_1.OnesyMongoError(`Collection name is required`); // log inherit from Mongo // so it can be configured on per use basis this.onesyLog = mongo.onesyLog; } get sort() { return { [this.sortProperty]: this.sortAscending }; } get sortProperty() { return 'added_at'; } get sortAscending() { return -1; } get addedProperty() { return 'added_at'; } get updatedProperty() { return 'updated_at'; } get projection() { return; } get db() { return new Promise((async (resolve) => { const db = await this.mongo.connection; return resolve(db); })); } async collection(name = this.collectionName, options = {}) { const db = await this.db; if (!this.collections[name]) this.collections[name] = db.collection(name); const collections = await this.mongo.getCollections(); // Good to create a collection in advance if it doesn't exist atm // as it might fail if you wanna add a document within a transaction // on a non existing mongo collection atm if (!(collections === null || collections === void 0 ? void 0 : collections.find(item => item.name === this.collectionName))) { const collection = await db.createCollection(this.collectionName, options); this.mongo.collections.push({ name: collection.collectionName }); // Add collection to Query model collections models_1.Query.collections.push(collection.collectionName); models_1.Query.keys.allowed.push(collection.collectionName); this.onesyLog.info(`${this.collectionName} collection created`); } return this.collections[name]; } async transaction(method, options = { retries: 5, retriesWait: 140 }) { var _a; if (!(0, is_1.default)('function', method)) throw new errors_1.DeveloperError('First argument has to be a function'); const transactionOptions = { readPreference: mongodb.ReadPreference.primary, readConcern: { level: 'local' }, writeConcern: { w: 'majority' }, }; let response; const retriesTotal = (0, is_1.default)('number', options.retries) ? options.retries : 5; const retriesWait = (0, is_1.default)('number', options.retriesWait) ? options.retriesWait : 140; let retries = retriesTotal; let error; let codeName = 'WriteConflict'; while (codeName === 'WriteConflict' && retries > 0) { error = undefined; codeName = undefined; if (retries < retriesTotal) await (0, wait_1.default)(retriesWait); const session = this.mongo.client.startSession(); try { await session.withTransaction(async () => { response = await method(session); return response; }, transactionOptions); } catch (error_) { error = error_; codeName = error_.codeName || ((_a = error_.message) === null || _a === void 0 ? void 0 : _a.codeName); } finally { await session.endSession(); } retries--; } if (error) throw new errors_1.DeveloperError(error); return response; } async count(query = new models_1.Query(), options = {}) { const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { const defaults = this.getDefaults('count'); const response = await collection.countDocuments(Object.assign(Object.assign({}, defaults), this.query(query)), options); return this.response(start, collection, 'count', response); } catch (error) { this.response(start, collection, 'count'); throw new errors_1.OnesyMongoError(error); } } async exists(query, options = {}) { const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { const defaults = this.getDefaults('exists'); const response = await collection.findOne(Object.assign(Object.assign({}, defaults), this.query(query)), Object.assign({ projection: { _id: 1 } }, options)); return this.response(start, collection, 'exists', !!response); } catch (error) { this.response(start, collection, 'exists'); throw new errors_1.OnesyMongoError(error); } } async find(query, options = {}) { const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { const { total, sort, limit, skip } = options, optionsOther = __rest(options, ["total", "sort", "limit", "skip"]); const defaults = this.getDefaults('find'); const optionsMongo = Object.assign({}, optionsOther); if (!optionsMongo.projection) { optionsMongo.projection = (BaseCollection.isOnesyQuery(query) && query.projection) || this.projection; if (!optionsMongo.projection) delete optionsMongo.projection; } optionsMongo.sort = ((BaseCollection.isOnesyQuery(query) ? query.sort : sort) || this.sort); optionsMongo.skip = (BaseCollection.isOnesyQuery(query) ? query.skip : skip) || 0; optionsMongo.limit = (BaseCollection.isOnesyQuery(query) ? query.limit : limit) || 15; const queryMongo = Object.assign(Object.assign({}, defaults), this.query(query)); const response_ = await collection.find(queryMongo, optionsMongo).toArray(); const response = new models_1.MongoResponse(response_); response.sort = optionsMongo.sort; response.size = response_.length; response.skip = optionsMongo.skip; response.limit = optionsMongo.limit; if (BaseCollection.isOnesyQuery(query) ? query.total : total) { response['total'] = await collection.find(queryMongo, { projection: { _id: 1 } }).count(); } return this.response(start, collection, 'find', response); } catch (error) { this.response(start, collection, 'find'); throw new errors_1.OnesyMongoError(error); } } async findOne(query, options = {}) { const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { const defaults = this.getDefaults('findOne'); if (!options.projection) { options.projection = (BaseCollection.isOnesyQuery(query) && query.projection) || this.projection; if (!options.projection) delete options.projection; } const response = await collection.findOne(Object.assign(Object.assign({}, defaults), this.query(query)), options); return this.response(start, collection, 'findOne', response); } catch (error) { this.response(start, collection, 'findOne'); throw new errors_1.OnesyMongoError(error); } } async aggregate(query = new models_1.Query(), options = {}) { const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { const defaults = this.getDefaults('aggregate'); const response = await collection.aggregate([ // defaults ...(defaults || []), ...this.query(query) ], Object.assign(Object.assign({}, Mongo_1.default.defaults.aggregateOptions), options)).toArray(); return this.response(start, collection, 'aggregate', response); } catch (error) { this.response(start, collection, 'aggregate'); throw new errors_1.OnesyMongoError(error); } } async searchMany(query, additional = { pre: [], prePagination: [], post: [], options: [], lookups: [] }, options = {}) { var _a; const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { const { total: optionsTotal, sort: optionsSort, limit: optionsLimit = 15, skip: optionsSkip, projection: optionsProjection } = options, optionsOther = __rest(options, ["total", "sort", "limit", "skip", "projection"]); const defaults = this.getDefaults('searchMany'); const optionsMongo = Object.assign({}, optionsOther); const projection = (BaseCollection.isOnesyQuery(query) ? query.projection : optionsProjection) || this.projection; const sort = (BaseCollection.isOnesyQuery(query) ? query.sort : optionsSort) || this.sort; const { limit = optionsLimit, skip = optionsSkip, next, previous } = BaseCollection.isOnesyQuery(query) ? query : options; const hasPaginator = next || previous; const paginatorProperty = Object.keys((next || previous || {}))[0]; const pre = additional.pre || []; const pre_pagination = additional.prePagination || []; const post = additional.post || []; const queries = { search: (BaseCollection.isOnesyQuery(query) ? query.queries.search[this.collectionName] : []) || [], api: (BaseCollection.isOnesyQuery(query) ? query.queries.api[this.collectionName] : []) || [], permissions: (BaseCollection.isOnesyQuery(query) ? query.queries.permissions[this.collectionName] : []) || [], aggregate: (BaseCollection.isOnesyQuery(query) ? query.queries.aggregate[this.collectionName] : []) || [] }; const queryMongo = [ // defaults ...(defaults || []), ...((BaseCollection.isOnesyQuery(query) ? query.query : query) || []), ...pre, ...queries.aggregate, // Search ...(queries.search.length ? (0, models_1.getMongoMatch)(queries.search, query.settings.type) : []), // API ...(queries.api.length ? (0, models_1.getMongoMatch)(queries.api) : []), // Permissions ...(queries.permissions.length ? (0, models_1.getMongoMatch)(queries.permissions, '$or') : []), ...pre_pagination, ]; const pipeline = [ ...queryMongo, // Next paginator ...(next ? (0, models_1.getMongoMatch)([next]) : []), // Previous paginator ...(previous ? (0, models_1.getMongoMatch)([previous]) : []), ...(hasPaginator ? [{ $sort: { [paginatorProperty]: next ? -1 : 1 } }] : []), ...(sort && !hasPaginator ? [{ $sort: sort }] : []), // Either skip or a paginator ...(((query === null || query === void 0 ? void 0 : query.skip) !== undefined && !hasPaginator) ? [{ $skip: skip }] : []), // +1 so we know if there's a next page { $limit: limit + 1 }, ...(sort && hasPaginator ? [{ $sort: sort }] : []), ...(projection ? [{ $project: projection }] : []), ...post ]; const response_ = await collection.aggregate(pipeline, Object.assign(Object.assign({}, Mongo_1.default.defaults.aggregateOptions), optionsMongo)).toArray(); // Add results and limit const objects = (!hasPaginator || next || response_.length <= limit) ? response_.slice(0, limit) : response_.slice(1, limit + 1); const first = objects[0]; const last = objects[objects.length - 1]; const response = new models_1.MongoResponse(objects); response.sort = sort; response.skip = skip; response.limit = limit; // Add hasNext, next, previous response['hasNext'] = previous || response_.length > objects.length; response['hasPrevious'] = !hasPaginator ? query.skip > 0 : next || (response_.length > objects.length); if (last) response['next'] = OnesyMongo_1.default.createPaginator(last, [this.sortProperty], sort); if (first) response['previous'] = OnesyMongo_1.default.createPaginator(first, [this.sortProperty], sort, 'previous'); // lookups await this.lookups(response.response, additional.lookups, options.request); // options if (!!((_a = additional.options) === null || _a === void 0 ? void 0 : _a.length)) { const optionsResponse = await collection.aggregate([ ...queryMongo, ...additional.options.map(item => ['array', undefined].includes(item.version) ? ({ $unwind: `$${item.property}` }) : undefined).filter(Boolean), ...additional.options.map(item => ({ $group: { _id: item.name, value: { $addToSet: item.property.startsWith('$') ? item.property : `$${item.property}` } } })) ], Object.assign(Object.assign({}, Mongo_1.default.defaults.aggregateOptions), optionsMongo)).toArray(); const optionsMongoResponse = {}; optionsResponse.forEach(item => { var _a; return optionsMongoResponse[item._id] = ((_a = item.value) === null || _a === void 0 ? void 0 : _a.flatMap(item => item)) || []; }); for (const optionName of Object.keys(optionsMongoResponse)) { const optionRequest = additional.options.find(item => item.name === optionName); if (optionRequest.lookup) await this.lookups(optionsMongoResponse[optionName], [optionRequest.lookup], options.request); } response.options = optionsMongoResponse; } // Count total only if it's requested by the query let total; if (BaseCollection.isOnesyQuery(query) ? query.total : optionsTotal) { const total_ = await collection.aggregate([ ...queryMongo, // Limit count for performance reasons { $limit: Mongo_1.default.defaults.limitCount }, { $group: { _id: null, count: { $sum: 1 } } }, ], Object.assign(Object.assign({}, Mongo_1.default.defaults.aggregateOptions), optionsMongo)).toArray(); total = total_[0] && total_[0].count; response['total'] = total || 0; } return this.response(start, collection, 'searchMany', response); } catch (error) { this.response(start, collection, 'searchMany'); throw new errors_1.OnesyMongoError(error); } } async searchOne(query, additional = { pre: [], post: [], lookups: [] }, options = {}) { const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { const { projection: optionsProjection } = options, optionsOther = __rest(options, ["projection"]); const defaults = this.getDefaults('searchOne'); const optionsMongo = Object.assign({}, optionsOther); const limit = 1; const projection = (BaseCollection.isOnesyQuery(query) ? query.projection : optionsProjection) || this.projection; const pre = additional.pre || []; const post = additional.post || []; const queries = { search: (BaseCollection.isOnesyQuery(query) ? query.queries.search[this.collectionName] : []) || [], api: (BaseCollection.isOnesyQuery(query) ? query.queries.api[this.collectionName] : []) || [], permissions: (BaseCollection.isOnesyQuery(query) ? query.queries.permissions[this.collectionName] : []) || [], aggregate: (BaseCollection.isOnesyQuery(query) ? query.queries.aggregate[this.collectionName] : []) || [] }; const queryMongo = [ // defaults ...(defaults || []), ...((BaseCollection.isOnesyQuery(query) ? query.query : query) || []), ...pre, ...queries.aggregate, // Search ...(queries.search.length ? (0, models_1.getMongoMatch)(queries.search, query.settings.type) : []), // API ...(queries.api.length ? (0, models_1.getMongoMatch)(queries.api) : []), // Permissions ...(queries.permissions.length ? (0, models_1.getMongoMatch)(queries.permissions, '$or') : []), ]; const pipeline = [ ...queryMongo, { $limit: limit }, ...(projection ? [{ $project: projection }] : []), ...post, ]; const response = await collection.aggregate(pipeline, Object.assign(Object.assign({}, Mongo_1.default.defaults.aggregateOptions), optionsMongo)).toArray(); // lookups await this.lookups(response, additional.lookups, options.request); return this.response(start, collection, 'searchOne', response[0]); } catch (error) { this.response(start, collection, 'searchOne'); throw new errors_1.OnesyMongoError(error); } } async addOne(value_, options_ = {}) { const options = Object.assign({ add_date: true }, options_); const { add_date } = options, optionsMongo = __rest(options, ["add_date"]); const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { const value = BaseCollection.value(value_); if (!value) throw new errors_1.OnesyMongoError(`No value provided`); if (add_date) (0, setObjectValue_1.default)(value, this.addedProperty || 'added_at', OnesyDate_1.default.utc.milliseconds); const response = await collection.insertOne(value, optionsMongo); return this.response(start, collection, 'addOne', Object.assign({ _id: response.insertedId }, value)); } catch (error) { this.response(start, collection, 'addOne'); throw new errors_1.OnesyMongoError(error); } } async updateOne(query, value, options_ = { lookups: [] }) { const options = Object.assign({ update_date: true }, options_); const { update_date } = options, optionsMongo = __rest(options, ["update_date"]); const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { const defaults = this.getDefaults('updateOne'); if (value !== undefined && !(0, is_1.default)('object', value)) throw new errors_1.OnesyMongoError(`Value has to be an object with update values`); if ((0, is_1.default)('object', value) && update_date) value[this.updatedProperty || 'updated_at'] = OnesyDate_1.default.utc.milliseconds; const update = {}; const operators = {}; // use both update values // and operator values in the same object Object.keys(value).forEach(item => { if (item.startsWith('$')) operators[item] = value[item]; else update[item] = value[item]; }); const response = await collection.findOneAndUpdate(Object.assign(Object.assign({}, defaults), this.query(query)), Object.assign(Object.assign({}, operators), ((!!Object.keys(update).length || operators['$set']) && { $set: Object.assign(Object.assign({}, operators['$set']), update) })), Object.assign({ returnDocument: 'after' }, optionsMongo)); // lookups await this.lookups(response.value, options.lookups, options.request); return this.response(start, collection, 'updateOne', response.value); } catch (error) { this.response(start, collection, 'updateOne'); throw new errors_1.OnesyMongoError(error); } } async removeOne(query, options = {}) { const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { const defaults = this.getDefaults('removeOne'); const response = await collection.findOneAndDelete(Object.assign(Object.assign({}, defaults), this.query(query)), options); return this.response(start, collection, 'removeOne', response.value); } catch (error) { this.response(start, collection, 'removeOne'); throw new errors_1.OnesyMongoError(error); } } async updateOneOrAdd(query, value, options_ = {}) { const options = Object.assign({ add_date: true, update_date: true }, options_); const { add_date, update_date } = options, optionsMongo = __rest(options, ["add_date", "update_date"]); const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { const defaults = this.getDefaults('updateOneOrAdd'); if (!(0, is_1.default)('object', value)) throw new errors_1.OnesyMongoError(`Value has to be an object with properties and values`); if (update_date) value[this.updatedProperty || 'updated_at'] = OnesyDate_1.default.utc.milliseconds; let setOnInsert; if (add_date) setOnInsert = { [this.addedProperty || 'added_at']: OnesyDate_1.default.utc.milliseconds }; const response = await collection.findOneAndUpdate(Object.assign(Object.assign({}, defaults), this.query(query)), Object.assign({ $set: value }, (setOnInsert && { $setOnInsert: setOnInsert })), Object.assign({ upsert: true, returnDocument: 'after' }, optionsMongo)); return this.response(start, collection, 'updateOneOrAdd', response.value); } catch (error) { this.response(start, collection, 'updateOneOrAdd'); throw new errors_1.OnesyMongoError(error); } } async addMany(values_, options_ = {}) { const options = Object.assign({ add_date: true }, options_); const { add_date } = options, optionsMongo = __rest(options, ["add_date"]); const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { let values = values_.map(item => BaseCollection.value(item)); if (!(values === null || values === void 0 ? void 0 : values.length)) throw new errors_1.OnesyMongoError(`Values have to be a non empty array`); if (add_date) values = values.map(item => { (0, setObjectValue_1.default)(item, this.addedProperty || 'added_at', OnesyDate_1.default.utc.milliseconds); return item; }); let response = await collection.insertMany(values, Object.assign({ ordered: false }, optionsMongo)); if (!options.original) { const ids = Object.keys(response.insertedIds || {}).map(item => { var _a; return (_a = response.insertedIds) === null || _a === void 0 ? void 0 : _a[item]; }); response = values.filter(item => !!ids.find(id => item._id.toString() === id.toString())); } return this.response(start, collection, 'addMany', response); } catch (error) { this.response(start, collection, 'addMany'); throw new errors_1.OnesyMongoError(error); } } async updateMany(query, value, options_ = {}) { const options = Object.assign({ update_date: true }, options_); const { update_date } = options, optionsMongo = __rest(options, ["update_date"]); const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { const defaults = this.getDefaults('updateMany'); if (value !== undefined && !(0, is_1.default)('object', value)) throw new errors_1.OnesyMongoError(`Value has to be an object with properties and values`); if ((0, is_1.default)('object', value) && update_date) value[this.updatedProperty || 'updated_at'] = OnesyDate_1.default.utc.milliseconds; const update = {}; const operators = {}; // use both update values // and operator values in the same object Object.keys(value).forEach(item => { if (item.startsWith('$')) operators[item] = value[item]; else update[item] = value[item]; }); const response = await collection.updateMany(Object.assign(Object.assign({}, defaults), this.query(query)), Object.assign(Object.assign({}, operators), ((!!Object.keys(update).length || operators['$set']) && { $set: Object.assign(Object.assign({}, operators['$set']), update) })), Object.assign({}, optionsMongo)); return this.response(start, collection, 'updateMany', response); } catch (error) { this.response(start, collection, 'updateMany'); throw new errors_1.OnesyMongoError(error); } } async removeMany(query, options = {}) { const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { const defaults = this.getDefaults('removeMany'); const response = await collection.deleteMany(Object.assign(Object.assign({}, defaults), this.query(query)), Object.assign({ ordered: false }, options)); return this.response(start, collection, 'removeMany', response); } catch (error) { this.response(start, collection, 'removeMany'); throw new errors_1.OnesyMongoError(error); } } async bulkWrite(values = [], options_ = {}) { const options = Object.assign({}, options_); const collection = await this.collection(); const start = OnesyDate_1.default.utc.milliseconds; try { if (!(values === null || values === void 0 ? void 0 : values.length)) throw new errors_1.OnesyMongoError(`Values have to be a non empty array`); const response = await collection.bulkWrite(values, Object.assign({ ordered: false }, options)); return this.response(start, collection, 'bulkWrite', response); } catch (error) { this.response(start, collection, 'bulkWrite'); throw new errors_1.OnesyMongoError(error); } } async lookups(value_, lookups, request) { const value = (0, is_1.default)('array', value_) ? value_ : [value_]; if (!!value.length && !!(lookups === null || lookups === void 0 ? void 0 : lookups.length)) { for (const lookup of lookups) { try { if (lookup.objects) { const ids = []; // Get the ids to lookup value.forEach(item => { const valueProperty = !lookup.property ? item : (0, getObjectValue_1.default)(item, lookup.property); ids.push(...this.getLookupIDs(valueProperty)); }); if (!!ids.length) { // Search objects const query = lookup.query || []; if (BaseCollection.isOnesyQuery(query)) { if ((0, is_1.default)('array', query.query)) { query.query.unshift({ $match: { _id: { $in: ids } } }); if (lookup.projection) { query.query.push({ $project: Object.assign({}, lookup.projection) }); } } } else { query.unshift({ $match: { _id: { $in: ids } } }); if (lookup.projection) { query.push({ $project: Object.assign({}, lookup.projection) }); } } const method = lookup.objects.aggregate.bind(lookup.objects); let response = await method(query, lookup.options); if ([true, undefined].includes(lookup.toObjectResponse)) { response = response.map(item => { if (item.toObjectResponse) return item.toObjectResponse(request); return item; }); } const responseMap = {}; response.forEach(item => { responseMap[(item._id || item.id).toString()] = item; }); // Update all the id objects value.forEach((item, index) => { const valueItem = this.updateLookupProperty(item, item, responseMap, lookup); if (!lookup.property && valueItem) value[index] = valueItem; }); } } } catch (error) { console.error(`Lookups error`, error); } } } } updateLookupProperty(mongoObject, object, responseMap, lookup, array = false) { const valueProperty = array ? object : !lookup.property ? object : (0, getObjectValue_1.default)(object, lookup.property); // string if ((0, is_1.default)('string', valueProperty)) { const valueResponse = responseMap[valueProperty]; if (valueResponse !== undefined) { if (lookup.property) (0, setObjectValue_1.default)(mongoObject, lookup.property, valueResponse); else return valueResponse; } } // mongoDB ObjectId else if (mongodb.ObjectId.isValid(valueProperty)) { const valueResponse = responseMap[valueProperty === null || valueProperty === void 0 ? void 0 : valueProperty.toString()]; if (valueResponse !== undefined) { if (lookup.property) (0, setObjectValue_1.default)(mongoObject, lookup.property, valueResponse); else return valueResponse; } } // object else if ((0, is_1.default)('object', valueProperty)) { const id = (valueProperty === null || valueProperty === void 0 ? void 0 : valueProperty.id) || (valueProperty === null || valueProperty === void 0 ? void 0 : valueProperty._id); const valueResponse = responseMap[id === null || id === void 0 ? void 0 : id.toString()]; const previous = (0, copy_1.default)((0, getObjectValue_1.default)(mongoObject, lookup.property)); if (lookup.override) { lookup.override.forEach(item => { (0, setObjectValue_1.default)(valueResponse, item, (0, getObjectValue_1.default)(previous, item)); }); } if (valueResponse !== undefined) { if (lookup.property) (0, setObjectValue_1.default)(mongoObject, lookup.property, valueResponse); else return valueResponse; } } // array else if ((0, is_1.default)('array', valueProperty)) { valueProperty.forEach((valuePropertyItem, index) => { const lookupItem = Object.assign({}, lookup); lookupItem.property = `${lookupItem.property || ''}${lookupItem.property ? '.' : ''}${index}`; this.updateLookupProperty(mongoObject, valuePropertyItem, responseMap, lookupItem, true); }); } } getLookupIDs(value) { const ids = []; if ((0, is_1.default)('string', value) || mongodb.ObjectId.isValid(value) || (0, is_1.default)('array', value) || (0, is_1.default)('object', value)) { if ((0, is_1.default)('string', value)) ids.push(new mongodb.ObjectId(value)); else if (mongodb.ObjectId.isValid(value)) ids.push(value); else if ((0, is_1.default)('object', value)) ids.push(new mongodb.ObjectId((value === null || value === void 0 ? void 0 : value.id) || (value === null || value === void 0 ? void 0 : value._id))); else if ((0, is_1.default)('array', value)) ids.push(...value.flatMap(item => this.getLookupIDs(item))); } return ids; } toModel(value) { if (!this.Model || [null, undefined].includes(value)) return value; return (0, is_1.default)('array', value) ? value.map(item => new this.Model(item, false)) : new this.Model(value, false); } response(start, collection, method, value, req) { if ((0, is_1.default)('number', start)) { const arguments_ = []; if (collection) arguments_.push(`Collection: ${collection.collectionName}`); if (method) arguments_.push(`Method: ${method}`); if (req === null || req === void 0 ? void 0 : req.id) arguments_.push(`Request ID: ${req.id}`); arguments_.push(`Duration: ${(0, duration_1.default)(OnesyDate_1.default.utc.milliseconds - start, true)}`); this.onesyLog.debug(...arguments_); } if (value && this.Model !== undefined) { switch (method) { case 'find': case 'searchMany': value.response = this.toModel(value.response); break; case 'findOne': case 'aggregate': case 'searchOne': case 'addOne': case 'updateOne': case 'removeOne': case 'updateOneOrAdd': return this.toModel(value); default: break; } } return value; } query(query, aggregate = false) { var _a, _b, _c, _d; if (BaseCollection.isOnesyQuery(query)) { if (aggregate) { return [ ...((query === null || query === void 0 ? void 0 : query.query) || []), ...(((_b = (_a = query === null || query === void 0 ? void 0 : query.queries) === null || _a === void 0 ? void 0 : _a.aggregate) === null || _b === void 0 ? void 0 : _b[this.collectionName]) || []) ]; } else { return Object.assign(Object.assign({}, query === null || query === void 0 ? void 0 : query.query), (_d = (_c = query === null || query === void 0 ? void 0 : query.queries) === null || _c === void 0 ? void 0 : _c.find) === null || _d === void 0 ? void 0 : _d[this.collectionName]); } } return aggregate ? (query || []) : query; } getDefaults(method) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z; let value = ['aggregate', 'searchMany', 'searchOne'].includes(method) ? [] : {}; // static if (['aggregate', 'searchMany', 'searchOne'].includes(method)) { // query if ((0, is_1.default)('array', (_a = BaseCollection.defaults) === null || _a === void 0 ? void 0 : _a.query)) value.push(...(_b = BaseCollection.defaults) === null || _b === void 0 ? void 0 : _b.query); // queryArray if ((0, is_1.default)('array', (_c = BaseCollection.defaults) === null || _c === void 0 ? void 0 : _c.queryArray)) value.push(...(_d = BaseCollection.defaults) === null || _d === void 0 ? void 0 : _d.queryArray); // method if ((0, is_1.default)('array', (_e = BaseCollection.defaults) === null || _e === void 0 ? void 0 : _e[method])) value.push(...(_f = BaseCollection.defaults) === null || _f === void 0 ? void 0 : _f[method]); } else { // query if ((0, is_1.default)('object', (_g = BaseCollection.defaults) === null || _g === void 0 ? void 0 : _g.query)) value = Object.assign(Object.assign({}, value), (_h = BaseCollection.defaults) === null || _h === void 0 ? void 0 : _h.query); // queryObject if ((0, is_1.default)('object', (_j = BaseCollection.defaults) === null || _j === void 0 ? void 0 : _j.queryObject)) value = Object.assign(Object.assign({}, value), (_k = BaseCollection.defaults) === null || _k === void 0 ? void 0 : _k.queryObject); // method if ((0, is_1.default)('object', (_l = BaseCollection.defaults) === null || _l === void 0 ? void 0 : _l[method])) value = Object.assign(Object.assign({}, value), (_m = BaseCollection.defaults) === null || _m === void 0 ? void 0 : _m[method]); } // instance if (['aggregate', 'searchMany', 'searchOne'].includes(method)) { // query if ((0, is_1.default)('array', (_o = this.defaults) === null || _o === void 0 ? void 0 : _o.query)) value.push(...(_p = this.defaults) === null || _p === void 0 ? void 0 : _p.query); // queryArray if ((0, is_1.default)('array', (_q = this.defaults) === null || _q === void 0 ? void 0 : _q.queryArray)) value.push(...(_r = this.defaults) === null || _r === void 0 ? void 0 : _r.queryArray); // method if ((0, is_1.default)('array', (_s = this.defaults) === null || _s === void 0 ? void 0 : _s[method])) value.push(...(_t = this.defaults) === null || _t === void 0 ? void 0 : _t[method]); } else { // query if ((0, is_1.default)('object', (_u = this.defaults) === null || _u === void 0 ? void 0 : _u.query)) value = Object.assign(Object.assign({}, value), (_v = this.defaults) === null || _v === void 0 ? void 0 : _v.query); // queryObject if ((0, is_1.default)('object', (_w = this.defaults) === null || _w === void 0 ? void 0 : _w.queryObject)) value = Object.assign(Object.assign({}, value), (_x = this.defaults) === null || _x === void 0 ? void 0 : _x.queryObject); // method if ((0, is_1.default)('object', (_y = this.defaults) === null || _y === void 0 ? void 0 : _y[method])) value = Object.assign(Object.assign({}, value), (_z = this.defaults) === null || _z === void 0 ? void 0 : _z[method]); } } static value(value) { // Getter object method if ((0, is_1.default)('function', value === null || value === void 0 ? void 0 : value.toObject)) return value.toObject(); return Object.assign({}, value); } static isOnesyQuery(value) { return value instanceof models_1.Query || ((value === null || value === void 0 ? void 0 : value.hasOwnProperty('query')) && (value === null || value === void 0 ? void 0 : value.hasOwnProperty('queries'))); } } exports.BaseCollection = BaseCollection; exports.default = BaseCollection;