@hirosystems/api-toolkit
Version:
API development toolkit
126 lines • 4.55 kB
JavaScript
;
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