UNPKG

@vinka/repo

Version:

Database and repo utilities

205 lines 8.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const defaultOptions = { dialect: 'postgres', logging: false, }; class SequelizeConnector { /** * Constructs a SequelizeConnector. Provides convenience for creating Sequelize clients and performing migrations. * Use createClient to create a Sequelize client. After that you can use this connector's migration methods to * perform migrations on a database. * * @param sequelizeConstructor a Sequelize constructor function. * @param poolConstructor a Postgres Pool constructor function. * @param config the database configuration adapted for Sequelize and Postgres. * @param logger a Logger object. */ constructor(sequelizeConstructor, poolConstructor, config, logger) { this.SequelizeConstructor = sequelizeConstructor; this.PoolConstructor = poolConstructor; this.logger = logger; // take shallow copy this.config = Object.assign({}, config); this.config.options = Object.assign(Object.assign({}, defaultOptions), config.options); } /** * Creates a Sequelize client connected to database specified in config, * creates the database if it does not exist, and sets the created client to * an internal member variable. * * @param [modelMap] the models to associate with the client. If not * provided, the caller needs to initialize models separately. */ connect(modelMap) { return __awaiter(this, void 0, void 0, function* () { try { yield this.testDbExistsOrThrow(this.config); const client = this.createSequelizeClient(this.config, modelMap); this.sequelizeClient = client; return client; } catch (err) { if (err.message.match(new RegExp(`"${this.config.db}" does not exist`))) { this.logger.debug(`failed to connect to database ${this.config.db}, trying to create it`); yield this.createDatabase(this.config); return this.connect(modelMap); } else { throw err; } } }); } /** * Creates a new database with name from config.db. Uses database with name * from config.masterDb to create the new database. The master database must * already exist. * * @param config the configuration for the postgres pool used internally. */ createDatabase(config) { return __awaiter(this, void 0, void 0, function* () { const pool = yield this.createPgPool(config, config.masterDb); try { yield pool.query(`CREATE DATABASE "${config.db}"`); this.logger.debug(`created database ${config.db}`); } catch (err) { this.logger.error(`encountered error when creating database ${config.db}, message: ${err.message}`); throw err; } finally { yield pool.end(); } }); } /** * Creates postgres connection pool, which can be used to connect to a database. * @param config the configuration for the pool. * @param dbName the name of the database the pool is connected to. Default is taken from config.db. */ createPgPool(config, dbName = config.db) { const options = { user: config.user, password: config.pass, host: config.options.host, port: config.options.port, database: dbName, max: 1, ssl: config.ssl ? { rejectUnauthorized: false } : false, }; return new this.PoolConstructor(options); } /** * Creates a Sequelize client and associates user defined models with the * client. * * @param config the configuration for the client. * @param [modelMap] the models to associate with the client. If not * provided, the caller needs to initialize models separately. */ createSequelizeClient(config, modelMap) { const options = Object.assign(Object.assign({}, config.options), { ssl: config.ssl, // Ref.: https://github.com/brianc/node-postgres/issues/2009 // reject unauthorized dialectOptions: { ssl: config.ssl ? { require: config.ssl, rejectUnauthorized: false, } : false, } }); if (config.options.logging && this.logger.debug) { options.logging = (...args) => this.logger.debug(args.join(' ')); } this.logger.debug(`connecting to database with options ${JSON.stringify(options)}`); const sequelize = new this.SequelizeConstructor(config.db, config.user, config.pass, options); if (modelMap) { modelMap.init(sequelize); } this.logger.info(`connected to database ${config.db}`); return sequelize; } /** * Migrates a database down with Umzug. * @param umzugConstructor the constructor for Umzug. * @param to 0 (default) to revert all migrations, or the name of the migration to migrate down to. * @param client the sequelize client used for the migration. Optional if createClient has been called. */ migrateDown(umzugConstructor, to = 0, client = this.sequelizeClient) { return __awaiter(this, void 0, void 0, function* () { if (client) { return yield this.createUmzug(umzugConstructor, client).down({ to }); } else { throw Error('trying to migrate before client is initialized. method createClient not called succesfully?'); } }); } /** * Migrates a database up with Umzug. * @param umzugConstructor the constructor for Umzug. * @param client the sequelize client used for the migration. Optional if createClient has been called. */ migrateUp(umzugConstructor, client = this.sequelizeClient) { return __awaiter(this, void 0, void 0, function* () { if (client) { return yield this.createUmzug(umzugConstructor, client).up(); } else { throw Error('trying to migrate before client is initialized. method createClient not called succesfully?'); } }); } /** * Tests that a client can be created from a Pool with config or throws. * @param config the config to create the pool with. The pool provides the client. */ testDbExistsOrThrow(config) { return __awaiter(this, void 0, void 0, function* () { this.logger.debug(`trying to connect to database ${config.db}`); const pool = yield this.createPgPool(config); try { (yield pool.connect()).release(); } catch (err) { throw err; } finally { pool.end(); } }); } /** * Creates an Umzug instance. * @param umzugConstructor the Umzug constructor. * @param client the sequelize client used in the Umzug. */ createUmzug(umzugConstructor, client) { return new umzugConstructor({ storage: 'sequelize', storageOptions: { sequelize: client, }, logging: (...args) => this.logger.debug(args.join(' ')), migrations: { path: 'migrations', pattern: /\.js/, params: [client.getQueryInterface(), this.SequelizeConstructor], }, }); } } exports.default = SequelizeConnector; //# sourceMappingURL=index.js.map