| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- "use strict";
- const _ = require("lodash");
- const AbstractConnectionManager = require("../abstract/connection-manager");
- const { logger } = require("../../utils/logger");
- const debug = logger.debugContext("connection:pg");
- const sequelizeErrors = require("../../errors");
- const semver = require("semver");
- const dataTypes = require("../../data-types");
- const momentTz = require("moment-timezone");
- const { promisify } = require("util");
- class ConnectionManager extends AbstractConnectionManager {
- constructor(dialect, sequelize) {
- sequelize.config.port = sequelize.config.port || 5432;
- super(dialect, sequelize);
- const pgLib = this._loadDialectModule("pg");
- this.lib = this.sequelize.config.native ? pgLib.native : pgLib;
- this._clearDynamicOIDs();
- this._clearTypeParser();
- this.refreshTypeParser(dataTypes.postgres);
- }
- _refreshTypeParser(dataType) {
- const arrayParserBuilder = (parser2) => {
- return (value) => this.lib.types.arrayParser.create(value, parser2).parse();
- };
- const rangeParserBuilder = (parser2) => {
- return (value) => dataType.parse(value, { parser: parser2 });
- };
- if (dataType.key.toLowerCase() === "range") {
- for (const name in this.nameOidMap) {
- const entry = this.nameOidMap[name];
- if (!entry.rangeOid)
- continue;
- const rangeParser = rangeParserBuilder(this.getTypeParser(entry.oid));
- const arrayRangeParser = arrayParserBuilder(rangeParser);
- this.oidParserMap.set(entry.rangeOid, rangeParser);
- if (!entry.arrayRangeOid)
- continue;
- this.oidParserMap.set(entry.arrayRangeOid, arrayRangeParser);
- }
- return;
- }
- const parser = (value) => dataType.parse(value);
- const arrayParser = arrayParserBuilder(parser);
- if (dataType.key.toLowerCase() === "enum") {
- this.enumOids.oids.forEach((oid) => {
- this.oidParserMap.set(oid, parser);
- });
- this.enumOids.arrayOids.forEach((arrayOid) => {
- this.oidParserMap.set(arrayOid, arrayParser);
- });
- return;
- }
- dataType.types.postgres.forEach((name) => {
- if (!this.nameOidMap[name])
- return;
- this.oidParserMap.set(this.nameOidMap[name].oid, parser);
- if (!this.nameOidMap[name].arrayOid)
- return;
- this.oidParserMap.set(this.nameOidMap[name].arrayOid, arrayParser);
- });
- }
- _clearTypeParser() {
- this.oidParserMap = /* @__PURE__ */ new Map();
- }
- getTypeParser(oid, ...args) {
- if (this.oidParserMap.get(oid))
- return this.oidParserMap.get(oid);
- return this.lib.types.getTypeParser(oid, ...args);
- }
- async connect(config) {
- config.user = config.username;
- const connectionConfig = _.pick(config, [
- "user",
- "password",
- "host",
- "database",
- "port"
- ]);
- connectionConfig.types = {
- getTypeParser: ConnectionManager.prototype.getTypeParser.bind(this)
- };
- if (config.dialectOptions) {
- _.merge(connectionConfig, _.pick(config.dialectOptions, [
- "application_name",
- "ssl",
- "client_encoding",
- "binary",
- "keepAlive",
- "statement_timeout",
- "query_timeout",
- "idle_in_transaction_session_timeout",
- "lock_timeout",
- "options"
- ]));
- }
- const connection = await new Promise((resolve, reject) => {
- let responded = false;
- const connection2 = new this.lib.Client(connectionConfig);
- const parameterHandler = (message) => {
- switch (message.parameterName) {
- case "server_version":
- if (this.sequelize.options.databaseVersion === 0) {
- const version = semver.coerce(message.parameterValue).version;
- this.sequelize.options.databaseVersion = semver.valid(version) ? version : this.dialect.defaultVersion;
- }
- break;
- case "standard_conforming_strings":
- connection2["standard_conforming_strings"] = message.parameterValue;
- break;
- }
- };
- const endHandler = () => {
- debug("connection timeout");
- if (!responded) {
- reject(new sequelizeErrors.ConnectionTimedOutError(new Error("Connection timed out")));
- }
- };
- connection2.once("end", endHandler);
- if (!this.sequelize.config.native) {
- connection2.connection.on("parameterStatus", parameterHandler);
- }
- connection2.connect((err) => {
- responded = true;
- if (!this.sequelize.config.native) {
- connection2.connection.removeListener("parameterStatus", parameterHandler);
- }
- if (err) {
- if (err.code) {
- switch (err.code) {
- case "ECONNREFUSED":
- reject(new sequelizeErrors.ConnectionRefusedError(err));
- break;
- case "ENOTFOUND":
- reject(new sequelizeErrors.HostNotFoundError(err));
- break;
- case "EHOSTUNREACH":
- reject(new sequelizeErrors.HostNotReachableError(err));
- break;
- case "EINVAL":
- reject(new sequelizeErrors.InvalidConnectionError(err));
- break;
- default:
- reject(new sequelizeErrors.ConnectionError(err));
- break;
- }
- } else {
- reject(new sequelizeErrors.ConnectionError(err));
- }
- } else {
- debug("connection acquired");
- connection2.removeListener("end", endHandler);
- resolve(connection2);
- }
- });
- });
- connection.on("error", (error) => {
- connection._invalid = true;
- debug(`connection error ${error.code || error.message}`);
- this.pool.destroy(connection);
- });
- let query = "";
- if (this.sequelize.options.standardConformingStrings !== false && connection["standard_conforming_strings"] !== "on") {
- query += "SET standard_conforming_strings=on;";
- }
- if (this.sequelize.options.clientMinMessages !== void 0) {
- console.warn('Usage of "options.clientMinMessages" is deprecated and will be removed in v7.');
- console.warn('Please use the sequelize option "dialectOptions.clientMinMessages" instead.');
- }
- if (!(config.dialectOptions && config.dialectOptions.clientMinMessages && config.dialectOptions.clientMinMessages.toLowerCase() === "ignore" || this.sequelize.options.clientMinMessages === false)) {
- const clientMinMessages = config.dialectOptions && config.dialectOptions.clientMinMessages || this.sequelize.options.clientMinMessages || "warning";
- query += `SET client_min_messages TO ${clientMinMessages};`;
- }
- if (!this.sequelize.config.keepDefaultTimezone) {
- const isZone = !!momentTz.tz.zone(this.sequelize.options.timezone);
- if (isZone) {
- query += `SET TIME ZONE '${this.sequelize.options.timezone}';`;
- } else {
- query += `SET TIME ZONE INTERVAL '${this.sequelize.options.timezone}' HOUR TO MINUTE;`;
- }
- }
- if (query) {
- await connection.query(query);
- }
- if (Object.keys(this.nameOidMap).length === 0 && this.enumOids.oids.length === 0 && this.enumOids.arrayOids.length === 0) {
- await this._refreshDynamicOIDs(connection);
- }
- return connection;
- }
- async disconnect(connection) {
- if (connection._ending) {
- debug("connection tried to disconnect but was already at ENDING state");
- return;
- }
- return await promisify((callback) => connection.end(callback))();
- }
- validate(connection) {
- return !connection._invalid && !connection._ending;
- }
- async _refreshDynamicOIDs(connection) {
- const databaseVersion = this.sequelize.options.databaseVersion;
- const supportedVersion = "8.3.0";
- if ((databaseVersion && semver.gte(databaseVersion, supportedVersion)) === false) {
- return;
- }
- const results = await (connection || this.sequelize).query("WITH ranges AS ( SELECT pg_range.rngtypid, pg_type.typname AS rngtypname, pg_type.typarray AS rngtyparray, pg_range.rngsubtype FROM pg_range LEFT OUTER JOIN pg_type ON pg_type.oid = pg_range.rngtypid)SELECT pg_type.typname, pg_type.typtype, pg_type.oid, pg_type.typarray, ranges.rngtypname, ranges.rngtypid, ranges.rngtyparray FROM pg_type LEFT OUTER JOIN ranges ON pg_type.oid = ranges.rngsubtype WHERE (pg_type.typtype IN('b', 'e'));");
- let result = Array.isArray(results) ? results.pop() : results;
- if (Array.isArray(result)) {
- if (result[0].command === "SET") {
- result = result.pop();
- }
- }
- const newNameOidMap = {};
- const newEnumOids = { oids: [], arrayOids: [] };
- for (const row of result.rows) {
- if (row.typtype === "e") {
- newEnumOids.oids.push(row.oid);
- if (row.typarray)
- newEnumOids.arrayOids.push(row.typarray);
- continue;
- }
- newNameOidMap[row.typname] = { oid: row.oid };
- if (row.typarray)
- newNameOidMap[row.typname].arrayOid = row.typarray;
- if (row.rngtypid) {
- newNameOidMap[row.typname].rangeOid = row.rngtypid;
- if (row.rngtyparray)
- newNameOidMap[row.typname].arrayRangeOid = row.rngtyparray;
- }
- }
- this.nameOidMap = newNameOidMap;
- this.enumOids = newEnumOids;
- this.refreshTypeParser(dataTypes.postgres);
- }
- _clearDynamicOIDs() {
- this.nameOidMap = {};
- this.enumOids = { oids: [], arrayOids: [] };
- }
- }
- module.exports = ConnectionManager;
- module.exports.ConnectionManager = ConnectionManager;
- module.exports.default = ConnectionManager;
- //# sourceMappingURL=connection-manager.js.map
|