const { ObjectId } = require('mongodb'); class MongodbTable { constructor(client, provider, opts = {}) { this.client = client; this.provider = provider; this.name = opts.name; } //Data Search find(query, opts = {}) { //opts: { projection: ... } query = this._handleData(query); return new Promise((resolve, reject) => { if(!this.provider._initialized) return reject(new Error('MongoDB is not connected.')); this.collection.find(query, opts, async (error, cursor) => { if(error) return reject(error); return resolve(await cursor.toArray()); }); }); } findOne(query, opts = {}) { //opts: { projection: ..., sort: ... } query = this._handleData(query); return new Promise((resolve, reject) => { if(!this.provider._initialized) return reject(new Error('MongoDB is not connected.')); this.collection.findOne(query, opts, async (error, item) => { if(error) return reject(error); return resolve(item); }); }); } aggregate(query) { query = this._handleData(query); return new Promise((resolve, reject) => { if(!this.provider._initialized) return reject(new Error('MongoDB is not connected.')); this.collection.aggregate(query, (error, item) => { if(error) return reject(error); return resolve(item.toArray()); }); }); } random(query, amount = 1) { query = this._handleData(query); if(amount > 100) amount = 100; return new Promise((resolve, reject) => { if(!this.provider._initialized) return reject(new Error('MongoDB is not connected.')); this.collection.aggregate([{ $match: query }, { $sample: { size: amount } }], (error, item) => { if(error) return reject(error); return resolve(item); }); }); } //Data Manipulation insertOne(data) { data = this._handleData(data); return new Promise((resolve, reject) => { if(!this.provider._initialized) return reject(new Error('MongoDB is not connected.')); this.collection.insertOne(data, (error, result) => { if(error) return reject(error); return resolve(result); }); }); } //NOTE: insertMany? deleteOne(query) { query = this._handleData(query); return new Promise((resolve, reject) => { if(!this.provider._initialized) return reject(new Error('MongoDB is not connected.')); this.collection.deleteOne(query, (error, result) => { if(error) return reject(error); return resolve(result); }); }); } deleteMany(query) { query = this._handleData(query); return new Promise((resolve, reject) => { if(!this.provider._initialized) return reject(new Error('MongoDB is not connected.')); this.collection.deleteMany(query, (error, result) => { if(error) return reject(error); return resolve(result); }); }); } updateOne(query, data, upsert = true) { query = this._handleData(query); return new Promise((resolve, reject) => { if(!this.provider._initialized) return reject(new Error('MongoDB is not connected.')); this.collection.updateOne(query, { $set: data }, { upsert }, async(error, result) => { if(error) return reject(error); const { matchedCount, upsertedCount, modifiedCount } = result; return resolve({ matched: matchedCount, upserted: upsertedCount, modified: modifiedCount }); }); }); } removeProperty(query, data) { query = this._handleData(query); return new Promise((resolve, reject) => { if(!this.provider._initialized) return reject(new Error('MongoDB is not connected.')); const unset = {}; for(const field of data) unset[field] = ''; this.collection.updateOne(query, { $unset: unset }, async (error, result) => { if(error) return reject(error); const { matchedCount, modifiedCount } = result; return resolve({ matched: matchedCount, modified: modifiedCount }); }); }); } push(query, data, upsert = true) { query = this._handleData(query); return new Promise((resolve, reject) => { if(!this.provider._initialized) return reject(new Error('MongoDB is not connected.')); this.collection.updateOne(query, { $push: data }, { upsert }, async(error, result) => { if(error) return reject(error); return resolve(result); }); }); } //Statistics stats(options = {}) { return new Promise((resolve, reject) => { if(!this.provider._initialized) return reject(new Error('MongoDB is not connected.')); this.collection.stats(options, (error, statistics) => { if(error) return reject(error); const { ns, size, count, avgObjSize, freeStorageSize, capped } = statistics; return resolve({ index: ns, averageSize: avgObjSize, currentSize: size, remainingSize: freeStorageSize, maximumSize: size+freeStorageSize, count, capped }); }); }); } count(query, options = {}) { return new Promise((resolve, reject) => { if(!this.provider._initialized) return reject(new Error('MongoDB is not connected.')); this.collection.countDocuments(query, options, (error, result) => { if(error) return reject(error); return resolve(result); }); }); } //Lazy Function _handleData(data) { //Convert data._id to Mongo ObjectIds (gets converted to plaintext through shard communication) if(data._id) { if(typeof data._id === 'string') data._id = ObjectId(data._id); else if(typeof data._id === 'object') data._id = { $in: Object.values(data._id)[0].map((id) => { return ObjectId(id); }) }; } return data; } //Getters get collection() { return this.provider.db.collection(this.name); } } module.exports = MongodbTable;