UNPKG

@hirosystems/api-toolkit

Version:
126 lines 4.55 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.standardizedConnectionArgs = standardizedConnectionArgs; exports.connectPostgres = connectPostgres; exports.getPostgres = getPostgres; const postgres = require("postgres"); const logger_1 = require("../logger"); const errors_1 = require("./errors"); const time_1 = require("../helpers/time"); const types_1 = require("./types"); /** * Takes in connection arguments provided via an object or a connection string and returns them with * a standardized application name format. If no connection args are provided, they are built from * standard postgres ENV vars. * @param args - Connection arguments * @param usage - Usage string * @returns PgConnectionVars */ function standardizedConnectionArgs(args, usage) { const appName = process.env.APPLICATION_NAME ?? process.env.PGAPPNAME ?? 'postgres'; const appUsage = usage ?? 'query'; if (!args) { return { database: process.env.PGDATABASE, user: process.env.PGUSER, password: process.env.PGPASSWORD, host: process.env.PGHOST, port: parseInt(process.env.PGPORT ?? '5432'), ssl: process.env.PGSSLMODE, application_name: `${appName}:${appUsage}`, }; } if (typeof args === 'string') { const uri = new URL(args); uri.searchParams.set('application_name', `${uri.searchParams.get('application_name') ?? appName}:${appUsage}`); return uri.toString(); } return args; } /** * Connects to Postgres. This function will also test the connection first to make sure all * connection parameters were specified correctly. * @param args - Connection options * @returns configured `Pool` object */ async function connectPostgres({ usageName, connectionArgs, connectionConfig, }) { const initTimer = (0, time_1.stopwatch)(); let connectionError; let connectionOkay = false; let lastElapsedLog = 0; do { const testSql = getPostgres({ usageName: `${usageName};conn-poll`, connectionArgs, connectionConfig, }); try { await testSql `SELECT version()`; connectionOkay = true; break; } catch (error) { if ((0, errors_1.isPgConnectionError)(error)) { const timeElapsed = initTimer.getElapsed(); if (timeElapsed - lastElapsedLog > 2000) { lastElapsedLog = timeElapsed; logger_1.logger.error(error, 'Pg connection failed, retrying..'); } connectionError = error; await (0, time_1.timeout)(100); } else { logger_1.logger.error(error, 'Cannot connect to pg'); throw error; } } finally { await testSql.end(); } } while (initTimer.getElapsed() < Number.MAX_SAFE_INTEGER); if (!connectionOkay) { connectionError = connectionError ?? new Error('Error connecting to database'); throw connectionError; } const sql = getPostgres({ usageName: `${usageName};datastore-crud`, connectionArgs, connectionConfig, }); return sql; } /** * Creates a Postgres client based on the provided connection arguments. * @param args - Connection options * @returns PgSqlClient */ function getPostgres({ usageName, connectionArgs, connectionConfig, }) { const args = standardizedConnectionArgs(connectionArgs, usageName); if (typeof args === 'string') { return postgres(args, { idle_timeout: connectionConfig?.idleTimeout, max_lifetime: connectionConfig?.maxLifetime, max: connectionConfig?.poolMax, }); } else { return postgres({ database: args.database, user: args.user, password: args.password, host: args.host, port: args.port, ssl: args.ssl, idle_timeout: connectionConfig?.idleTimeout, max_lifetime: connectionConfig?.maxLifetime, max: connectionConfig?.poolMax, types: types_1.PG_TYPE_MAPPINGS, connection: { application_name: args.application_name, search_path: args.schema, statement_timeout: connectionConfig?.statementTimeout?.toString(), }, }); } } //# sourceMappingURL=connection.js.map