123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- 'use strict';
- const path = require('path');
- const sleep = require('mz-modules/sleep');
- const AUTH_RETRIES = Symbol('authenticateRetries');
- module.exports = app => {
- const defaultConfig = {
- delegate: 'model',
- baseDir: 'model',
- logging(...args) {
- // if benchmark enabled, log used
- const used = typeof args[1] === 'number' ? `(${args[1]}ms)` : '';
- app.logger.info('[egg-sequelize]%s %s', used, args[0]);
- },
- host: 'localhost',
- port: 3306,
- username: 'root',
- benchmark: true,
- define: {
- freezeTableName: false,
- underscored: true,
- },
- };
- const config = app.config.sequelize;
- // support customize sequelize
- app.Sequelize = config.Sequelize || require('sequelize');
- const databases = [];
- if (!config.datasources) {
- databases.push(loadDatabase(Object.assign({}, defaultConfig, config)));
- } else {
- config.datasources.forEach(datasource => {
- databases.push(loadDatabase(Object.assign({}, defaultConfig, datasource)));
- });
- }
- app.beforeStart(async () => {
- await Promise.all(databases.map(database => authenticate(database)));
- });
- /**
- * load database to app[config.delegate]
- * @param {Object} config config for load
- * - delegate: load model to app[delegate]
- * - baseDir: where model located
- * - other sequelize configures(database username, password, etc...)
- * @return {Object} sequelize instance
- */
- function loadDatabase(config = {}) {
- if (typeof config.ignore === 'string' || Array.isArray(config.ignore)) {
- app.deprecate(`[egg-sequelize] if you want to exclude ${config.ignore} when load models, please set to config.sequelize.exclude instead of config.sequelize.ignore`);
- config.exclude = config.ignore;
- delete config.ignore;
- }
- const sequelize = config.connectionUri ?
- new app.Sequelize(config.connectionUri, config) :
- new app.Sequelize(config.database, config.username, config.password, config);
- const delegate = config.delegate.split('.');
- const len = delegate.length;
- let model = app;
- let context = app.context;
- for (let i = 0; i < len - 1; i++) {
- model = model[delegate[i]] = model[delegate[i]] || {};
- context = context[delegate[i]] = context[delegate[i]] || {};
- }
- if (model[delegate[len - 1]]) {
- throw new Error(`[egg-sequelize] app[${config.delegate}] is already defined`);
- }
- Object.defineProperty(model, delegate[len - 1], {
- value: sequelize,
- writable: false,
- configurable: true,
- });
- const DELEGATE = Symbol(`context#sequelize_${config.delegate}`);
- Object.defineProperty(context, delegate[len - 1], {
- 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(model[delegate[len - 1]]);
- this[DELEGATE].ctx = this;
- }
- return this[DELEGATE];
- },
- configurable: true,
- });
- const modelDir = path.join(app.baseDir, 'app', config.baseDir);
- const models = [];
- const target = Symbol(config.delegate);
- app.loader.loadToApp(modelDir, target, {
- caseStyle: 'upper',
- ignore: config.exclude,
- filter(model) {
- if (!model || !model.sequelize) return false;
- models.push(model);
- return true;
- },
- initializer(factory) {
- if (typeof factory === 'function') {
- return factory(app, sequelize);
- }
- },
- });
- Object.assign(model[delegate[len - 1]], app[target]);
- models.forEach(model => {
- typeof model.associate === 'function' && model.associate();
- });
- return model[delegate[len - 1]];
- }
- /**
- * Authenticate to test Database connection.
- *
- * This method will retry 3 times when database connect fail in temporary, to avoid Egg start failed.
- * @param {Application} database instance of sequelize
- */
- async function authenticate(database) {
- database[AUTH_RETRIES] = database[AUTH_RETRIES] || 0;
- try {
- await database.authenticate();
- } catch (e) {
- if (database[AUTH_RETRIES] >= 3) throw e;
- // sleep 1s to retry, max 3 times
- database[AUTH_RETRIES] += 1;
- app.logger.warn(`Sequelize Error: ${e.message}, sleep 1 seconds to retry...`);
- await sleep(1000);
- await authenticate(database);
- }
- }
- };
|