think-mongo
Version:
305 lines (291 loc) • 9.02 kB
JavaScript
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
const helper = require('think-helper');
const Socket = require('./socket.js');
const Parser = require('./parser.js');
const SOCKET = Symbol('think-mongo-socket');
const PARSER = Symbol('think-mongo-parser');
module.exports = class Query {
constructor(config) {
this.config = config;
this.lastInsertId = '';
}
/**
* get socket instance
*/
get socket() {
if (this[SOCKET]) return this[SOCKET];
this[SOCKET] = Socket.getInstance(this.config);
return this[SOCKET];
}
/**
* get parser instance
*/
get parser() {
if (this[PARSER]) return this[PARSER];
this[PARSER] = new Parser();
return this[PARSER];
}
/**
* add data
* @param {Object} data
* @param {Object} options
*/
add(data, options) {
var _this = this;
return this.socket.autoRelease((() => {
var _ref = _asyncToGenerator(function* (connection) {
const collection = connection.collection(options.table);
yield collection.insertOne(data, options);
_this.lastInsertId = data._id.toString();
return _this.lastInsertId;
});
return function (_x) {
return _ref.apply(this, arguments);
};
})());
}
/**
* add data list
* @param {Array} dataList
* @param {Object} options
*/
addMany(dataList, options) {
var _this2 = this;
return this.socket.autoRelease((() => {
var _ref2 = _asyncToGenerator(function* (connection) {
const collection = connection.collection(options.table);
yield collection.insertMany(dataList, options);
const insertedIds = dataList.map(function (item) {
return item._id.toString();
});
_this2.lastInsertId = insertedIds;
return _this2.lastInsertId;
});
return function (_x2) {
return _ref2.apply(this, arguments);
};
})());
}
/**
* set collection limit
* @param {Object} collection []
* @param {String} limit []
* @return {Object} []
*/
limit(collection, limit) {
limit = this.parser.parseLimit(limit);
if (limit[0]) {
collection.skip(limit[0]);
}
if (limit[1]) {
collection.limit(limit[1]);
}
return collection;
}
/**
* parse group
* @param {String} group []
* @return {Object} []
*/
group(group) {
group = this.parser.parseGroup(group);
const length = group.length;
if (length === 0) {
return { _id: null };
} else if (length === 1) {
return { _id: `$${group[0]}` };
} else {
const result = {};
group.forEach(item => {
result[item] = `$${item}`;
});
// return result
return { _id: result };
}
}
/**
* select data
* @param {Object} options
*/
select(options) {
const where = this.parser.parseWhere(options.where);
const distinct = this.parser.parseDistinct(options.distinct);
const field = this.parser.parseField(options.field);
const order = this.parser.parseOrder(options.order);
return this.socket.autoRelease(connection => {
let collection = connection.collection(options.table);
if (distinct) {
return collection.distinct(distinct, where);
}
collection = collection.find(where).project(field);
collection = this.limit(collection, options.limit);
collection = collection.sort(order);
return collection.toArray();
});
}
/**
* update data
* @param {Object} data
* @param {Object} options
*/
update(data, options) {
const where = this.parser.parseWhere(options.where);
const limit = this.parser.parseLimit(options.limit);
return this.socket.autoRelease(connection => {
const collection = connection.collection(options.table);
// updates multiple documents that meet the query criteria.
// default only updates one document
if (limit[1] !== 1) {
options.multi = true;
}
// If set to true, creates a new document when no document matches the query criteria.
// The default value is false, which does not insert a new document when no match is found.
if (!options.upsert) {
options.upsert = false;
}
// add $set for data
let flag = true;
for (const key in data) {
if (key[0] !== '$') {
flag = false;
break;
}
}
if (!flag) {
data = { $set: data };
}
// update operator
// http://docs.mongodb.org/manual/reference/operator/update/#id1
return collection.updateMany(where, data, options);
});
}
/**
* delete data
* @param {Object} options
*/
delete(options) {
const where = this.parser.parseWhere(options.where);
const limit = this.parser.parseLimit(options.limit);
// delete one row
const removeOpt = {
session: options.session
};
if (limit[1] === 1) {
removeOpt.justOne = true;
}
return this.socket.autoRelease(connection => {
const collection = connection.collection(options.table);
return collection.deleteMany(where, removeOpt);
});
}
/**
* get data count
* @param {Object} options
*/
count(options) {
const where = this.parser.parseWhere(options.where);
const aggregate = [];
if (!helper.isEmpty(where)) {
aggregate.push({ $match: where });
}
const group = this.group(options.group);
group.total = { $sum: 1 };
aggregate.push({ $group: group });
const order = this.parser.parseOrder(options.order);
if (!helper.isEmpty(order)) {
aggregate.push({ $sort: order });
}
return this.socket.autoRelease(connection => {
const collection = connection.collection(options.table);
// make aggregate method to be a promise
const fn = helper.promisify(collection.aggregate, collection);
return fn(aggregate).then(cursor => {
const toArray = helper.promisify(cursor.toArray, cursor);
return toArray();
}).then(data => {
return options.raw ? data : data[0] && data[0].total || 0;
});
});
}
/**
* get data sum
* @param {Object} options
*/
sum(options) {
const where = this.parser.parseWhere(options.where);
const group = this.group(options.group);
group.total = { $sum: `$${options.field}` };
const order = this.parser.parseOrder(options.order);
const aggregate = [];
if (!helper.isEmpty(where)) {
aggregate.push({ $match: where });
}
aggregate.push({ $group: group });
if (!helper.isEmpty(order)) {
aggregate.push({ $sort: order });
}
return this.socket.autoRelease(connection => {
const collection = connection.collection(options.table);
// make aggregate method to be a promise
const fn = helper.promisify(collection.aggregate, collection);
return fn(aggregate).then(cursor => {
const toArray = helper.promisify(cursor.toArray, cursor);
return toArray();
}).then(data => {
if (group._id) {
const ret = [];
data.forEach(item => {
ret.push({
group: item._id,
total: item.total
});
});
return ret;
}
return options.raw ? data : data[0] && data[0].total || 0;
});
});
}
/**
* create collection indexes
* @param {String} table []
* @param {Object} indexes []
* @return {Promise} []
*/
ensureIndex(table, indexes, options = {}) {
if (options === true) {
options = { unique: true };
}
if (helper.isString(indexes)) {
indexes = indexes.split(/\s*,\s*/);
}
if (helper.isArray(indexes)) {
const result = {};
indexes.forEach(item => {
result[item] = 1;
});
indexes = result;
}
return this.socket.autoRelease(connection => {
const collection = connection.collection(table);
return collection.createIndex(indexes, options);
});
}
/**
* aggregate
* @param {String} table []
* @param {Object} options []
* @return {Promise} []
*/
aggregate(table, pipeline, options) {
return this.socket.autoRelease(connection => {
const collection = connection.collection(table);
const fn = helper.promisify(collection.aggregate, collection);
const curPromise = options ? fn(pipeline, options) : fn(pipeline);
return curPromise.then(cursor => {
const toArray = helper.promisify(cursor.toArray, cursor);
return toArray();
});
});
}
};