@starbemtech/star-db-query-builder
Version:
A query builder to be used with mysql or postgres
224 lines • 8.94 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPgClient = void 0;
const promise_retry_1 = __importDefault(require("promise-retry"));
const monitor_1 = require("../monitor/monitor");
const transientErrorCodes = new Set(['ECONNRESET', 'ETIMEDOUT', 'ECONNREFUSED']);
/**
* Checks if the given error is a transient error that can be retried
*
* Transient errors are temporary network or connection issues that typically
* resolve themselves and can be safely retried. This function checks if the
* error code matches known transient error patterns for PostgreSQL connections.
*
* @param error - The error object to check
* @returns boolean - True if the error is transient and can be retried, false otherwise
*
* @example
* try {
* const result = await pool.query(sql, params);
* } catch (error) {
* if (isTransientError(error)) {
* // Retry the operation
* console.log('Transient error detected, retrying...');
* } else {
* // Handle permanent error
* throw error;
* }
* }
*/
function isTransientError(error) {
return error && error.code && transientErrorCodes.has(error.code);
}
/**
* Ensures that the unaccent extension is installed in the PostgreSQL database
*
* This function checks if the unaccent extension is installed in the database
* and installs it if it is not. It also emits a connection created event to
* the monitor.
*
* @param pool - The PostgreSQL pool instance
* @returns Promise<void> - Resolves when the unaccent extension is installed or already exists
*
* @example
* await ensureUnaccentExtension(pool);
*/
async function ensureUnaccentExtension(pool) {
try {
const checkResult = await pool.query(`
SELECT 1 FROM pg_extension WHERE extname = 'unaccent'
`);
if (checkResult.rows.length === 0) {
await pool.query('CREATE EXTENSION IF NOT EXISTS unaccent');
monitor_1.monitor.emit(monitor_1.MonitorEvents.CONNECTION_CREATED, {
clientType: 'pg',
extension: 'unaccent',
status: 'installed',
});
console.info('@starbemtech/star-db-query-builder: Extensão unaccent instalada com sucesso.');
}
}
catch (error) {
monitor_1.monitor.emit(monitor_1.MonitorEvents.QUERY_ERROR, {
clientType: 'pg',
action: 'install_unaccent',
error,
});
throw new Error(`@starbemtech/star-db-query-builder: Não foi possível instalar a extensão unaccent:
${error}`);
}
}
/**
* Creates a PostgreSQL database client
*
* This function initializes a PostgreSQL database client with the provided pool configuration
* and optional retry options. It sets up monitoring for connection events and query operations.
*
* @param pool - The PostgreSQL pool instance
* @param retryOptions - Optional retry options for failed queries
* @param poolConfig - Optional pool configuration
* @param installUnaccentExtension - Optional flag to install unaccent extension
* @returns IDatabaseClient - The PostgreSQL database client instance
*
* @example
* const pgClient = await createPgClient(pool, { retries: 3, factor: 2, minTimeout: 1000 });
*
* @example
* const pgClient = await createPgClient(pool, { retries: 3, factor: 2, minTimeout: 1000 });
*
* @example
* const pgClient = await createPgClient(pool, { retries: 3, factor: 2, minTimeout: 1000 });
*/
const createPgClient = async (pool, retryOptions, poolConfig, installUnaccentExtension) => {
if (installUnaccentExtension) {
await ensureUnaccentExtension(pool);
}
monitor_1.monitor.emit(monitor_1.MonitorEvents.CONNECTION_CREATED, {
clientType: 'pg',
poolOptions: poolConfig,
});
return {
clientType: 'pg',
query: async (sql, params) => {
return (0, promise_retry_1.default)(async (retry, attempt) => {
const startTime = Date.now();
try {
monitor_1.monitor.emit(monitor_1.MonitorEvents.QUERY_START, {
clientType: 'pg',
sql,
params,
attempt,
});
const { rows } = await pool.query(sql, params);
const elapsedTime = Date.now() - startTime;
monitor_1.monitor.emit(monitor_1.MonitorEvents.QUERY_END, {
clientType: 'pg',
sql,
params,
attempt,
elapsedTime,
});
return rows;
}
catch (error) {
const elapsedTime = Date.now() - startTime;
monitor_1.monitor.emit(monitor_1.MonitorEvents.QUERY_ERROR, {
clientType: 'pg',
sql,
params,
attempt,
elapsedTime,
error,
});
if (isTransientError(error)) {
console.warn(`Postgres query attempt ${attempt} failed, retrying...`, error);
monitor_1.monitor.emit(monitor_1.MonitorEvents.RETRY_ATTEMPT, {
clientType: 'pg',
sql,
params,
attempt,
error,
});
return retry(error);
}
throw error;
}
}, retryOptions);
},
beginTransaction: async () => {
const client = await pool.connect();
try {
await client.query('BEGIN');
return {
query: async (sql, params) => {
const startTime = Date.now();
try {
monitor_1.monitor.emit(monitor_1.MonitorEvents.QUERY_START, {
clientType: 'pg',
sql,
params,
attempt: 1,
inTransaction: true,
});
const { rows } = await client.query(sql, params);
const elapsedTime = Date.now() - startTime;
monitor_1.monitor.emit(monitor_1.MonitorEvents.QUERY_END, {
clientType: 'pg',
sql,
params,
attempt: 1,
elapsedTime,
inTransaction: true,
});
return rows;
}
catch (error) {
const elapsedTime = Date.now() - startTime;
monitor_1.monitor.emit(monitor_1.MonitorEvents.QUERY_ERROR, {
clientType: 'pg',
sql,
params,
attempt: 1,
elapsedTime,
error,
inTransaction: true,
});
throw error;
}
},
commit: async () => {
try {
await client.query('COMMIT');
monitor_1.monitor.emit(monitor_1.MonitorEvents.TRANSACTION_COMMIT, {
clientType: 'pg',
});
}
finally {
client.release();
}
},
rollback: async () => {
try {
await client.query('ROLLBACK');
monitor_1.monitor.emit(monitor_1.MonitorEvents.TRANSACTION_ROLLBACK, {
clientType: 'pg',
});
}
finally {
client.release();
}
},
};
}
catch (error) {
client.release();
throw error;
}
},
};
};
exports.createPgClient = createPgClient;
//# sourceMappingURL=pgClient.js.map