@onewalker/egg-mongoose
Version:
egg mongoose plugin advanced by @oneWalker
142 lines (115 loc) • 4.12 kB
JavaScript
;
const assert = require('assert');
const path = require('path');
const mongoose = require('mongoose');
const awaitFirst = require('await-first');
const filterURLPassword = require('./filterURLPassword');
let count = 0;
const globalPlugins = [];
module.exports = app => {
const { client, clients, url, options, defaultDB, customPromise, loadModel, plugins, delegate } = app.config.mongoose;
// compatibility
if (!client && !clients && url) {
app.config.mongoose.client = {
url,
options,
};
}
mongoose.Promise = customPromise ? customPromise : Promise;
if (Array.isArray(plugins)) {
plugins.forEach(plugin => {
mongoose.plugin.apply(mongoose, Array.isArray(plugin) ? plugin : [ plugin ]);
});
}
globalPlugins.push(...mongoose.plugins || []);
// TODO addSingleton support config[this.configName]?
app.addSingleton('mongoose', createOneClient);
app.mongooseDB = app.mongoose;
// set default connection(ref models has fixed in mongoose 4.13.7)
if (app.mongooseDB instanceof mongoose.Connection) {
mongoose.connection = app.mongooseDB;
} else if (defaultDB && app.mongooseDB.get(defaultDB) instanceof mongoose.Connection) {
mongoose.connection = app.mongooseDB.get(defaultDB);
}
app.mongoose = mongoose;
/* deprecated, next primary version remove */
app.__mongoose = mongoose;
app.mongoose.loadModel = () => loadModelToApp(app);
const ctx = app.context;
const DELEGATE = Symbol(`context#mongoose_${delegate}`);
Object.defineProperty(ctx, delegate,
{
get() {
// context.model is different with app.model
// so we can change the properties of ctx.model.xxx
if (!this[DELEGATE]) {
this[DELEGATE] = Object.create(app[delegate]);
this[DELEGATE].ctx = this;
}
return this[DELEGATE];
},
configurable: true,
});
if (loadModel) {
app.beforeStart(() => {
loadModelToApp(app);
});
}
};
function createOneClient(config, app) {
const { url, options, plugins } = config;
const filteredURL = filterURLPassword(url);
assert(url, '[egg-mongoose] url is required on config');
app.coreLogger.info('[egg-mongoose] connecting %s', filteredURL);
// remove all plugins
const length = Array.isArray(mongoose.plugins) ? mongoose.plugins.length : 0;
for (let index = length; index > 0; index--) {
mongoose.plugins.pop();
}
// combine clients plugins and public plugins
[].concat(plugins || [], globalPlugins).forEach(plugin => {
mongoose.plugin.apply(mongoose, Array.isArray(plugin) ? plugin : [ plugin ]);
});
const db = mongoose.createConnection(url, options);
/* istanbul ignore next */
db.on('error', err => {
err.message = `[egg-mongoose]${err.message}`;
app.coreLogger.error(err);
});
/* istanbul ignore next */
db.on('disconnected', () => {
app.coreLogger.error(`[egg-mongoose] ${filteredURL} disconnected`);
});
db.on('connected', () => {
app.coreLogger.info(`[egg-mongoose] ${filteredURL} connected successfully`);
});
/* istanbul ignore next */
db.on('reconnected', () => {
app.coreLogger.info(`[egg-mongoose] ${filteredURL} reconnected successfully`);
});
app.beforeStart(function* () {
app.coreLogger.info('[egg-mongoose] starting...');
yield awaitFirst(db, [ 'connected', 'error' ]);
const index = count++;
/*
*remove heartbeat to avoid no authentication
const serverStatus = yield db.db.command({
serverStatus: 1,
});
assert(serverStatus.ok === 1, '[egg-mongoose] server status is not ok, please check mongodb service!');
*/
app.coreLogger.info(`[egg-mongoose] instance[${index}] start successfully`);
});
return db;
}
function loadModelToApp(app) {
const config = app.config.mongoose;
const dir = path.join(app.config.baseDir, 'app', config.baseDir);
app.loader.loadToApp(dir, config.delegate, {
inject: app,
caseStyle: 'upper',
filter(model) {
return typeof model === 'function' && model.prototype instanceof app.mongoose.Model;
},
});
}