think-mongo
Version:
132 lines (125 loc) • 3.57 kB
JavaScript
const mongodb = require('mongodb');
const genericPool = require('generic-pool');
const thinkInstance = require('think-instance');
const helper = require('think-helper');
const querystring = require('querystring');
const CREATE_POOL = Symbol('think-mongo-create-pool');
const POOL = Symbol('think-mongo-pool');
const mongoConnect = helper.promisify(mongodb.MongoClient.connect, mongodb.MongoClient);
const defaultOptions = {
host: '127.0.0.1',
port: 27017,
logger: console.log.bind(console), /* eslint no-console: ["error", { allow: ["log"] }] */
logConnect: true
};
class MongoSocket {
constructor(config) {
this.config = Object.assign({}, defaultOptions, config);
if (this.config.logLevel) {
mongodb.Logger.setLevel(this.config.logLevel);
}
}
/**
* get pool
*/
get pool() {
if (this[POOL]) return this[POOL];
this[POOL] = this[CREATE_POOL]();
return this[POOL];
}
/**
* create pool
*/
[CREATE_POOL]() {
const factory = {
create: () => {
let auth = '';
const config = this.config;
// connect with auth
if (config.user) {
auth = `${config.user}:${config.password}@`;
}
// connection options
// http://mongodb.github.io/node-mongodb-native/2.0/tutorials/urls/
let options = '';
if (config.options) {
options = '?' + querystring.stringify(config.options);
}
// many hosts
let hostStr = '';
if (helper.isArray(config.host)) {
hostStr = config.host.map((item, i) => {
return `${item}:${config.port[i] || config.port[0]}`;
}).join(',');
} else {
hostStr = config.host + ':' + config.port;
}
const connectStr = `mongodb://${auth}${hostStr}/${config.database}${options}`;
if (config.logConnect) {
config.logger(connectStr);
}
return mongoConnect(connectStr, { useUnifiedTopology: true });
},
destroy: client => {
client.close();
return Promise.resolve();
}
};
let { connectionLimit, options } = this.config;
if (!connectionLimit && options && (options.poolSize || options.maxPoolSize)) {
connectionLimit = options.poolSize || options.maxPoolSize;
}
if (helper.isTrueEmpty(connectionLimit)) {
connectionLimit = 5;
}
options = {
min: 1,
max: connectionLimit,
acquireTimeoutMillis: this.config.acquireTimeoutMillis || 3000
};
return genericPool.createPool(factory, options);
}
/**
* get connection
*/
getConnection() {
return this.pool.acquire();
}
/**
* release connection
* @param {Object} connection
*/
release(connection) {
this.pool.release(connection);
}
/**
* auto release connection after run function
* @param {Function} fn
*/
autoRelease(fn) {
return this.pool.acquire().then(connection => {
return Promise.resolve(fn(connection.db())).then(data => {
return { data, connection };
}).catch(err => {
this.pool.release(connection);
throw err;
});
}).then(data => {
this.pool.release(data.connection);
return data.data;
});
}
/**
* close connection
* @param {Object} connection
*/
close(connection) {
if (connection) return this.pool.destroy(connection);
return this.pool.drain().then(() => {
return this.pool.clear();
}).then(() => {
this[POOL] = null;
});
}
};
module.exports = thinkInstance(MongoSocket);