@freemework/sql.postgres
Version:
Postgres SQL Facade library of the Freemework Project.
920 lines • 58 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FSqlConnectionFactoryPostgres = exports.FSqlConnectionFactoryPostgresLoggerLabel = void 0;
const common_1 = require("@freemework/common");
const pg_1 = __importDefault(require("pg"));
/**
* Package oid contains OID constants as defined by the Postgres server.
* @description
SELECT
CASE
WHEN "typcategory" = 'A' THEN CONCAT('array', "typname", ' = ', "oid", ',')
ELSE CONCAT("typname", ' = ', "oid", ',')
END
FROM "pg_type"
WHERE "oid" < 10000 ORDER BY "oid"
* @see PG type codes - https://www.postgresql.org/docs/current/catalog-pg-type.html#CATALOG-TYPCATEGORY-TABLE
* @see https://github.com/postgres/postgres/blob/2e4db241bfd3206bad8286f8ffc2db6bbdaefcdf/src/include/catalog/pg_type.dat
*/
var PostgresObjectID;
(function (PostgresObjectID) {
PostgresObjectID[PostgresObjectID["bool"] = 16] = "bool";
PostgresObjectID[PostgresObjectID["bytea"] = 17] = "bytea";
PostgresObjectID[PostgresObjectID["char"] = 18] = "char";
PostgresObjectID[PostgresObjectID["name"] = 19] = "name";
PostgresObjectID[PostgresObjectID["int8"] = 20] = "int8";
PostgresObjectID[PostgresObjectID["int2"] = 21] = "int2";
PostgresObjectID[PostgresObjectID["arrayint2vector"] = 22] = "arrayint2vector";
PostgresObjectID[PostgresObjectID["int4"] = 23] = "int4";
PostgresObjectID[PostgresObjectID["regproc"] = 24] = "regproc";
PostgresObjectID[PostgresObjectID["text"] = 25] = "text";
PostgresObjectID[PostgresObjectID["oid"] = 26] = "oid";
PostgresObjectID[PostgresObjectID["tid"] = 27] = "tid";
PostgresObjectID[PostgresObjectID["xid"] = 28] = "xid";
PostgresObjectID[PostgresObjectID["cid"] = 29] = "cid";
PostgresObjectID[PostgresObjectID["arrayoidvector"] = 30] = "arrayoidvector";
PostgresObjectID[PostgresObjectID["pg_ddl_command"] = 32] = "pg_ddl_command";
PostgresObjectID[PostgresObjectID["pg_type"] = 71] = "pg_type";
PostgresObjectID[PostgresObjectID["pg_attribute"] = 75] = "pg_attribute";
PostgresObjectID[PostgresObjectID["pg_proc"] = 81] = "pg_proc";
PostgresObjectID[PostgresObjectID["pg_class"] = 83] = "pg_class";
PostgresObjectID[PostgresObjectID["json"] = 114] = "json";
PostgresObjectID[PostgresObjectID["xml"] = 142] = "xml";
PostgresObjectID[PostgresObjectID["array_xml"] = 143] = "array_xml";
PostgresObjectID[PostgresObjectID["pg_node_tree"] = 194] = "pg_node_tree";
PostgresObjectID[PostgresObjectID["array_json"] = 199] = "array_json";
PostgresObjectID[PostgresObjectID["array_pg_type"] = 210] = "array_pg_type";
PostgresObjectID[PostgresObjectID["table_am_handler"] = 269] = "table_am_handler";
PostgresObjectID[PostgresObjectID["array_pg_attribute"] = 270] = "array_pg_attribute";
PostgresObjectID[PostgresObjectID["array_xid8"] = 271] = "array_xid8";
PostgresObjectID[PostgresObjectID["array_pg_proc"] = 272] = "array_pg_proc";
PostgresObjectID[PostgresObjectID["array_pg_class"] = 273] = "array_pg_class";
PostgresObjectID[PostgresObjectID["index_am_handler"] = 325] = "index_am_handler";
PostgresObjectID[PostgresObjectID["point"] = 600] = "point";
PostgresObjectID[PostgresObjectID["lseg"] = 601] = "lseg";
PostgresObjectID[PostgresObjectID["path"] = 602] = "path";
PostgresObjectID[PostgresObjectID["box"] = 603] = "box";
PostgresObjectID[PostgresObjectID["polygon"] = 604] = "polygon";
PostgresObjectID[PostgresObjectID["line"] = 628] = "line";
PostgresObjectID[PostgresObjectID["array_line"] = 629] = "array_line";
PostgresObjectID[PostgresObjectID["cidr"] = 650] = "cidr";
PostgresObjectID[PostgresObjectID["array_cidr"] = 651] = "array_cidr";
PostgresObjectID[PostgresObjectID["float4"] = 700] = "float4";
PostgresObjectID[PostgresObjectID["float8"] = 701] = "float8";
PostgresObjectID[PostgresObjectID["unknown"] = 705] = "unknown";
PostgresObjectID[PostgresObjectID["circle"] = 718] = "circle";
PostgresObjectID[PostgresObjectID["array_circle"] = 719] = "array_circle";
PostgresObjectID[PostgresObjectID["macaddr8"] = 774] = "macaddr8";
PostgresObjectID[PostgresObjectID["array_macaddr8"] = 775] = "array_macaddr8";
PostgresObjectID[PostgresObjectID["money"] = 790] = "money";
PostgresObjectID[PostgresObjectID["array_money"] = 791] = "array_money";
PostgresObjectID[PostgresObjectID["macaddr"] = 829] = "macaddr";
PostgresObjectID[PostgresObjectID["inet"] = 869] = "inet";
PostgresObjectID[PostgresObjectID["array_bool"] = 1000] = "array_bool";
PostgresObjectID[PostgresObjectID["array_bytea"] = 1001] = "array_bytea";
PostgresObjectID[PostgresObjectID["array_char"] = 1002] = "array_char";
PostgresObjectID[PostgresObjectID["array_name"] = 1003] = "array_name";
PostgresObjectID[PostgresObjectID["array_int2"] = 1005] = "array_int2";
PostgresObjectID[PostgresObjectID["array_int2vector"] = 1006] = "array_int2vector";
PostgresObjectID[PostgresObjectID["array_int4"] = 1007] = "array_int4";
PostgresObjectID[PostgresObjectID["array_regproc"] = 1008] = "array_regproc";
PostgresObjectID[PostgresObjectID["array_text"] = 1009] = "array_text";
PostgresObjectID[PostgresObjectID["array_tid"] = 1010] = "array_tid";
PostgresObjectID[PostgresObjectID["array_xid"] = 1011] = "array_xid";
PostgresObjectID[PostgresObjectID["array_cid"] = 1012] = "array_cid";
PostgresObjectID[PostgresObjectID["array_oidvector"] = 1013] = "array_oidvector";
PostgresObjectID[PostgresObjectID["array_bpchar"] = 1014] = "array_bpchar";
PostgresObjectID[PostgresObjectID["array_varchar"] = 1015] = "array_varchar";
PostgresObjectID[PostgresObjectID["array_int8"] = 1016] = "array_int8";
PostgresObjectID[PostgresObjectID["array_point"] = 1017] = "array_point";
PostgresObjectID[PostgresObjectID["array_lseg"] = 1018] = "array_lseg";
PostgresObjectID[PostgresObjectID["array_path"] = 1019] = "array_path";
PostgresObjectID[PostgresObjectID["array_box"] = 1020] = "array_box";
PostgresObjectID[PostgresObjectID["array_float4"] = 1021] = "array_float4";
PostgresObjectID[PostgresObjectID["array_float8"] = 1022] = "array_float8";
PostgresObjectID[PostgresObjectID["array_polygon"] = 1027] = "array_polygon";
PostgresObjectID[PostgresObjectID["array_oid"] = 1028] = "array_oid";
PostgresObjectID[PostgresObjectID["aclitem"] = 1033] = "aclitem";
PostgresObjectID[PostgresObjectID["array_aclitem"] = 1034] = "array_aclitem";
PostgresObjectID[PostgresObjectID["array_macaddr"] = 1040] = "array_macaddr";
PostgresObjectID[PostgresObjectID["array_inet"] = 1041] = "array_inet";
PostgresObjectID[PostgresObjectID["bpchar"] = 1042] = "bpchar";
PostgresObjectID[PostgresObjectID["varchar"] = 1043] = "varchar";
PostgresObjectID[PostgresObjectID["date"] = 1082] = "date";
PostgresObjectID[PostgresObjectID["time"] = 1083] = "time";
PostgresObjectID[PostgresObjectID["timestamp"] = 1114] = "timestamp";
PostgresObjectID[PostgresObjectID["array_timestamp"] = 1115] = "array_timestamp";
PostgresObjectID[PostgresObjectID["array_date"] = 1182] = "array_date";
PostgresObjectID[PostgresObjectID["array_time"] = 1183] = "array_time";
PostgresObjectID[PostgresObjectID["timestamptz"] = 1184] = "timestamptz";
PostgresObjectID[PostgresObjectID["array_timestamptz"] = 1185] = "array_timestamptz";
PostgresObjectID[PostgresObjectID["interval"] = 1186] = "interval";
PostgresObjectID[PostgresObjectID["array_interval"] = 1187] = "array_interval";
PostgresObjectID[PostgresObjectID["array_numeric"] = 1231] = "array_numeric";
PostgresObjectID[PostgresObjectID["pg_database"] = 1248] = "pg_database";
PostgresObjectID[PostgresObjectID["array_cstring"] = 1263] = "array_cstring";
PostgresObjectID[PostgresObjectID["timetz"] = 1266] = "timetz";
PostgresObjectID[PostgresObjectID["array_timetz"] = 1270] = "array_timetz";
PostgresObjectID[PostgresObjectID["bit"] = 1560] = "bit";
PostgresObjectID[PostgresObjectID["array_bit"] = 1561] = "array_bit";
PostgresObjectID[PostgresObjectID["varbit"] = 1562] = "varbit";
PostgresObjectID[PostgresObjectID["array_varbit"] = 1563] = "array_varbit";
PostgresObjectID[PostgresObjectID["numeric"] = 1700] = "numeric";
PostgresObjectID[PostgresObjectID["refcursor"] = 1790] = "refcursor";
PostgresObjectID[PostgresObjectID["array_refcursor"] = 2201] = "array_refcursor";
PostgresObjectID[PostgresObjectID["regprocedure"] = 2202] = "regprocedure";
PostgresObjectID[PostgresObjectID["regoper"] = 2203] = "regoper";
PostgresObjectID[PostgresObjectID["regoperator"] = 2204] = "regoperator";
PostgresObjectID[PostgresObjectID["regclass"] = 2205] = "regclass";
PostgresObjectID[PostgresObjectID["regtype"] = 2206] = "regtype";
PostgresObjectID[PostgresObjectID["array_regprocedure"] = 2207] = "array_regprocedure";
PostgresObjectID[PostgresObjectID["array_regoper"] = 2208] = "array_regoper";
PostgresObjectID[PostgresObjectID["array_regoperator"] = 2209] = "array_regoperator";
PostgresObjectID[PostgresObjectID["array_regclass"] = 2210] = "array_regclass";
PostgresObjectID[PostgresObjectID["array_regtype"] = 2211] = "array_regtype";
PostgresObjectID[PostgresObjectID["record"] = 2249] = "record";
PostgresObjectID[PostgresObjectID["cstring"] = 2275] = "cstring";
PostgresObjectID[PostgresObjectID["any"] = 2276] = "any";
PostgresObjectID[PostgresObjectID["anyarray"] = 2277] = "anyarray";
PostgresObjectID[PostgresObjectID["void"] = 2278] = "void";
PostgresObjectID[PostgresObjectID["trigger"] = 2279] = "trigger";
PostgresObjectID[PostgresObjectID["language_handler"] = 2280] = "language_handler";
PostgresObjectID[PostgresObjectID["internal"] = 2281] = "internal";
PostgresObjectID[PostgresObjectID["anyelement"] = 2283] = "anyelement";
PostgresObjectID[PostgresObjectID["_record"] = 2287] = "_record";
PostgresObjectID[PostgresObjectID["anynonarray"] = 2776] = "anynonarray";
PostgresObjectID[PostgresObjectID["pg_authid"] = 2842] = "pg_authid";
PostgresObjectID[PostgresObjectID["pg_auth_members"] = 2843] = "pg_auth_members";
PostgresObjectID[PostgresObjectID["array_txid_snapshot"] = 2949] = "array_txid_snapshot";
PostgresObjectID[PostgresObjectID["uuid"] = 2950] = "uuid";
PostgresObjectID[PostgresObjectID["array_uuid"] = 2951] = "array_uuid";
PostgresObjectID[PostgresObjectID["txid_snapshot"] = 2970] = "txid_snapshot";
PostgresObjectID[PostgresObjectID["fdw_handler"] = 3115] = "fdw_handler";
PostgresObjectID[PostgresObjectID["pg_lsn"] = 3220] = "pg_lsn";
PostgresObjectID[PostgresObjectID["array_pg_lsn"] = 3221] = "array_pg_lsn";
PostgresObjectID[PostgresObjectID["tsm_handler"] = 3310] = "tsm_handler";
PostgresObjectID[PostgresObjectID["pg_ndistinct"] = 3361] = "pg_ndistinct";
PostgresObjectID[PostgresObjectID["pg_dependencies"] = 3402] = "pg_dependencies";
PostgresObjectID[PostgresObjectID["anyenum"] = 3500] = "anyenum";
PostgresObjectID[PostgresObjectID["tsvector"] = 3614] = "tsvector";
PostgresObjectID[PostgresObjectID["tsquery"] = 3615] = "tsquery";
PostgresObjectID[PostgresObjectID["gtsvector"] = 3642] = "gtsvector";
PostgresObjectID[PostgresObjectID["array_tsvector"] = 3643] = "array_tsvector";
PostgresObjectID[PostgresObjectID["array_gtsvector"] = 3644] = "array_gtsvector";
PostgresObjectID[PostgresObjectID["array_tsquery"] = 3645] = "array_tsquery";
PostgresObjectID[PostgresObjectID["regconfig"] = 3734] = "regconfig";
PostgresObjectID[PostgresObjectID["array_regconfig"] = 3735] = "array_regconfig";
PostgresObjectID[PostgresObjectID["regdictionary"] = 3769] = "regdictionary";
PostgresObjectID[PostgresObjectID["array_regdictionary"] = 3770] = "array_regdictionary";
PostgresObjectID[PostgresObjectID["jsonb"] = 3802] = "jsonb";
PostgresObjectID[PostgresObjectID["array_jsonb"] = 3807] = "array_jsonb";
PostgresObjectID[PostgresObjectID["anyrange"] = 3831] = "anyrange";
PostgresObjectID[PostgresObjectID["event_trigger"] = 3838] = "event_trigger";
PostgresObjectID[PostgresObjectID["int4range"] = 3904] = "int4range";
PostgresObjectID[PostgresObjectID["array_int4range"] = 3905] = "array_int4range";
PostgresObjectID[PostgresObjectID["numrange"] = 3906] = "numrange";
PostgresObjectID[PostgresObjectID["array_numrange"] = 3907] = "array_numrange";
PostgresObjectID[PostgresObjectID["tsrange"] = 3908] = "tsrange";
PostgresObjectID[PostgresObjectID["array_tsrange"] = 3909] = "array_tsrange";
PostgresObjectID[PostgresObjectID["tstzrange"] = 3910] = "tstzrange";
PostgresObjectID[PostgresObjectID["array_tstzrange"] = 3911] = "array_tstzrange";
PostgresObjectID[PostgresObjectID["daterange"] = 3912] = "daterange";
PostgresObjectID[PostgresObjectID["array_daterange"] = 3913] = "array_daterange";
PostgresObjectID[PostgresObjectID["int8range"] = 3926] = "int8range";
PostgresObjectID[PostgresObjectID["array_int8range"] = 3927] = "array_int8range";
PostgresObjectID[PostgresObjectID["pg_shseclabel"] = 4066] = "pg_shseclabel";
PostgresObjectID[PostgresObjectID["jsonpath"] = 4072] = "jsonpath";
PostgresObjectID[PostgresObjectID["array_jsonpath"] = 4073] = "array_jsonpath";
PostgresObjectID[PostgresObjectID["regnamespace"] = 4089] = "regnamespace";
PostgresObjectID[PostgresObjectID["array_regnamespace"] = 4090] = "array_regnamespace";
PostgresObjectID[PostgresObjectID["regrole"] = 4096] = "regrole";
PostgresObjectID[PostgresObjectID["array_regrole"] = 4097] = "array_regrole";
PostgresObjectID[PostgresObjectID["regcollation"] = 4191] = "regcollation";
PostgresObjectID[PostgresObjectID["array_regcollation"] = 4192] = "array_regcollation";
PostgresObjectID[PostgresObjectID["int4multirange"] = 4451] = "int4multirange";
PostgresObjectID[PostgresObjectID["nummultirange"] = 4532] = "nummultirange";
PostgresObjectID[PostgresObjectID["tsmultirange"] = 4533] = "tsmultirange";
PostgresObjectID[PostgresObjectID["tstzmultirange"] = 4534] = "tstzmultirange";
PostgresObjectID[PostgresObjectID["datemultirange"] = 4535] = "datemultirange";
PostgresObjectID[PostgresObjectID["int8multirange"] = 4536] = "int8multirange";
PostgresObjectID[PostgresObjectID["anymultirange"] = 4537] = "anymultirange";
PostgresObjectID[PostgresObjectID["anycompatiblemultirange"] = 4538] = "anycompatiblemultirange";
PostgresObjectID[PostgresObjectID["pg_brin_bloom_summary"] = 4600] = "pg_brin_bloom_summary";
PostgresObjectID[PostgresObjectID["pg_brin_minmax_multi_summary"] = 4601] = "pg_brin_minmax_multi_summary";
PostgresObjectID[PostgresObjectID["pg_mcv_list"] = 5017] = "pg_mcv_list";
PostgresObjectID[PostgresObjectID["pg_snapshot"] = 5038] = "pg_snapshot";
PostgresObjectID[PostgresObjectID["array_pg_snapshot"] = 5039] = "array_pg_snapshot";
PostgresObjectID[PostgresObjectID["xid8"] = 5069] = "xid8";
PostgresObjectID[PostgresObjectID["anycompatible"] = 5077] = "anycompatible";
PostgresObjectID[PostgresObjectID["anycompatiblearray"] = 5078] = "anycompatiblearray";
PostgresObjectID[PostgresObjectID["anycompatiblenonarray"] = 5079] = "anycompatiblenonarray";
PostgresObjectID[PostgresObjectID["anycompatiblerange"] = 5080] = "anycompatiblerange";
PostgresObjectID[PostgresObjectID["pg_subscription"] = 6101] = "pg_subscription";
PostgresObjectID[PostgresObjectID["array_int4multirange"] = 6150] = "array_int4multirange";
PostgresObjectID[PostgresObjectID["array_nummultirange"] = 6151] = "array_nummultirange";
PostgresObjectID[PostgresObjectID["array_tsmultirange"] = 6152] = "array_tsmultirange";
PostgresObjectID[PostgresObjectID["array_tstzmultirange"] = 6153] = "array_tstzmultirange";
PostgresObjectID[PostgresObjectID["array_datemultirange"] = 6155] = "array_datemultirange";
PostgresObjectID[PostgresObjectID["array_int8multirange"] = 6157] = "array_int8multirange";
})(PostgresObjectID || (PostgresObjectID = {}));
pg_1.default.types.setTypeParser(PostgresObjectID.timestamp, function (stringValue) {
return stringValue;
});
class FSqlConnectionFactoryPostgresLoggerLabel extends common_1.FLoggerLabel {
static CONNECTION_NUMBER = new FSqlConnectionFactoryPostgresLoggerLabel("sql.postgres.connection", "Describes a number (counter) of connection");
static HOST = new FSqlConnectionFactoryPostgresLoggerLabel("sql.postgres.host", "PostgreSQL server hostname/IP");
static PORT = new FSqlConnectionFactoryPostgresLoggerLabel("sql.postgres.port", "PostgreSQL server port");
static DATABASE = new FSqlConnectionFactoryPostgresLoggerLabel("sql.postgres.db", "Name of a database");
}
exports.FSqlConnectionFactoryPostgresLoggerLabel = FSqlConnectionFactoryPostgresLoggerLabel;
class FSqlConnectionFactoryPostgres extends common_1.FInitableBase {
loggingSqlLabels;
_url;
_pool;
_defaultSchema;
_databaseName;
_log;
_connectionCounter;
// This implementation wrap package https://www.npmjs.com/package/pg
constructor(opts) {
super();
this._connectionCounter = 0;
this._log = opts.log !== undefined ? opts.log : common_1.FLogger.create(this.constructor.name);
this.loggingSqlLabels = opts.loggingSqlLabels !== undefined ? opts.loggingSqlLabels : true;
switch (opts.url.protocol) {
case "postgres:":
case "postgres+ssl:":
this._url = opts.url;
break;
default:
throw new common_1.FExceptionArgument("Expected URL schema 'postgres:' or 'postgres+ssl:'.", "opts.url");
}
this._log.trace(common_1.FExecutionContext.Empty, "PostgresProviderPoolFactory constructed");
const poolConfig = { host: this._url.hostname };
if (this._url.port !== "") {
poolConfig.port = Number.parseInt(this._url.port);
}
if (this._url.username !== "") {
poolConfig.user = this._url.username;
}
if (this._url.password !== "") {
poolConfig.password = this._url.password;
}
// DB name
let pathname = this._url.pathname;
while (pathname.length > 0 && pathname[0] === "/") {
pathname = pathname.substring(1);
}
poolConfig.database = pathname;
this._databaseName = pathname;
// Timeouts
poolConfig.connectionTimeoutMillis = (opts.connectionTimeoutMillis !== undefined) ? opts.connectionTimeoutMillis : 5000;
poolConfig.idleTimeoutMillis = (opts.idleTimeoutMillis !== undefined) ? opts.idleTimeoutMillis : 30000;
// Keep-alive
poolConfig.keepAlive = (opts.keepAlive !== undefined) ? opts.keepAlive : true;
poolConfig.keepAliveInitialDelayMillis = (opts.keepAliveInitialDelayMillis !== undefined) ? opts.keepAliveInitialDelayMillis : 5000;
// App name
if (opts.applicationName !== "") {
poolConfig.application_name = opts.applicationName;
}
else {
const appNameFromUrl = this._url.searchParams.get("app");
if (appNameFromUrl !== null && appNameFromUrl !== "") {
poolConfig.application_name = appNameFromUrl;
}
}
const schemaFromUrl = this._url.searchParams.get("schema");
this._defaultSchema = opts.defaultSchema !== undefined ?
opts.defaultSchema :
schemaFromUrl !== null ? schemaFromUrl : "public";
// SSL
if (this._url.protocol === "postgres+ssl:") {
poolConfig.ssl = {};
if (opts.ssl !== undefined) {
if (opts.ssl !== undefined) {
if (opts.ssl === "prefer") {
poolConfig.ssl.rejectUnauthorized = false;
this._log.debug(common_1.FExecutionContext.Empty, "Using partial secured connection without checking identity (SSL-prefer, no certificate validation).");
}
else {
poolConfig.ssl.rejectUnauthorized = true;
this._log.debug(common_1.FExecutionContext.Empty, "Using full secured connection (with certificate validation).");
if (opts.ssl.caCert !== undefined) {
poolConfig.ssl.ca = opts.ssl.caCert;
this._log.debug(common_1.FExecutionContext.Empty, "CA certificate was provided.");
}
if (opts.ssl.clientCert !== undefined) {
poolConfig.ssl.cert = opts.ssl.clientCert.cert;
poolConfig.ssl.key = opts.ssl.clientCert.key;
this._log.debug(common_1.FExecutionContext.Empty, "Client certificate was provided.");
}
}
}
}
else {
poolConfig.ssl.rejectUnauthorized = false;
this._log.debug(common_1.FExecutionContext.Empty, "Using partial secured connection without checking identity (SSL-prefer, no certificate validation).");
}
}
else {
this._log.debug(common_1.FExecutionContext.Empty, "Using unsecured connection (non-SSL).");
}
this._pool = new pg_1.default.Pool(poolConfig);
this._pool.on("error", (e, _connection) => {
/*
https://node-postgres.com/api/pool
When a client is sitting idly in the pool it can still emit errors
because it is connected to a live backend. If the backend goes down
or a network partition is encountered all the idle, connected clients
in your application will emit an error through the pool's error event emitter.
The error listener is passed the error as the first argument and the client
upon which the error occurred as the 2nd argument. The client will be
automatically terminated and removed from the pool, it is only passed to the
error handler in case you want to inspect it.
*/
const ex = common_1.FException.wrapIfNeeded(e);
this._log.debug(common_1.FExecutionContext.Empty, ex.message);
this._log.trace(common_1.FExecutionContext.Empty, ex.message, ex);
});
}
get defaultSchema() { return this._defaultSchema; }
async create(executionContext) {
this.verifyInitializedAndNotDisposed();
const connectionNumber = this._connectionCounter++;
const cancellationToken = common_1.FCancellationExecutionContext.of(executionContext).cancellationToken;
const pgClient = await this._pool.connect();
try {
cancellationToken.throwIfCancellationRequested();
if (this._defaultSchema !== null) {
await pgClient.query(`SET search_path TO ${this._defaultSchema}`);
}
await pgClient.query("SET TIME ZONE '00:00'");
const FSqlConnection = new FSqlConnectionPostgres(executionContext, this, connectionNumber, pgClient, async () => {
// dispose callback
pgClient.release();
}, this._log);
return FSqlConnection;
}
catch (e) {
pgClient.release();
throw e;
}
}
_createSqlLoggerLabelsExecutionContext(executionContext) {
if (this.loggingSqlLabels) {
executionContext = new common_1.FLoggerLabelsExecutionContext(executionContext, FSqlConnectionFactoryPostgresLoggerLabel.HOST.value(this._url.hostname), FSqlConnectionFactoryPostgresLoggerLabel.PORT.value(this._url.port), FSqlConnectionFactoryPostgresLoggerLabel.DATABASE.value(this._databaseName));
}
return executionContext;
}
usingConnection(executionContext, worker) {
const executionPromise = (async () => {
const connectionInitExecutionContext = this._createSqlLoggerLabelsExecutionContext(executionContext);
const sqlConnection = await this.create(connectionInitExecutionContext);
const workerExecutionContext = this.loggingSqlLabels
? new common_1.FLoggerLabelsExecutionContext(connectionInitExecutionContext, FSqlConnectionFactoryPostgresLoggerLabel.CONNECTION_NUMBER.value(sqlConnection.connectionNumber.toString()))
: connectionInitExecutionContext;
try {
let workerResult;
if (worker.length === 1) {
workerResult = await worker(sqlConnection);
}
else if (worker.length === 2) {
workerResult = await worker(workerExecutionContext, sqlConnection);
}
else {
throw new common_1.FExceptionArgument("Wrong worker function. Expect a function with 1 or 2 arguments.", "worker");
}
return workerResult;
}
finally {
await sqlConnection.dispose();
}
})();
return executionPromise;
}
usingConnectionWithTransaction(executionContext, worker) {
return this.usingConnection(executionContext, async (sqlConnection) => {
const connectionInitExecutionContext = this._createSqlLoggerLabelsExecutionContext(executionContext);
const uncancellableExecutionContext = new common_1.FCancellationExecutionContext(executionContext, common_1.FCancellationToken.Dummy);
await sqlConnection.statement("BEGIN TRANSACTION").execute(executionContext);
try {
const workerExecutionContext = this.loggingSqlLabels
? new common_1.FLoggerLabelsExecutionContext(connectionInitExecutionContext, FSqlConnectionFactoryPostgresLoggerLabel.CONNECTION_NUMBER.value(sqlConnection.connectionNumber.toString()))
: connectionInitExecutionContext;
let workerResult;
if (worker.length === 1) {
workerResult = await worker(sqlConnection);
}
else if (worker.length === 2) {
workerResult = await worker(workerExecutionContext, sqlConnection);
}
else {
throw new common_1.FExceptionArgument("Wrong worker function. Expect a function with 1 or 2 arguments.", "worker");
}
// We have not to cancel this operation, so pass uncancellableExecutionContext
await sqlConnection.statement("COMMIT TRANSACTION").execute(uncancellableExecutionContext);
return workerResult;
}
catch (e) {
try {
// We have not to cancel this operation, so pass uncancellableExecutionContext
await sqlConnection.statement("ROLLBACK TRANSACTION").execute(uncancellableExecutionContext);
}
catch (e2) {
throw new common_1.FExceptionAggregate([
common_1.FException.wrapIfNeeded(e),
common_1.FException.wrapIfNeeded(e2)
]);
}
throw e;
}
});
}
onInit() {
const logger = this._log;
if (logger.isTraceEnabled) {
logger.trace(this.initExecutionContext, `Initializing instance of ${this.constructor.name} ...`);
}
}
async onDispose() {
const logger = this._log;
if (logger.isTraceEnabled) {
logger.trace(this.initExecutionContext, `Disposing instance of ${this.constructor.name} ...`);
}
// Dispose never raise error
try {
await this._pool.end();
}
catch (e) {
const ex = common_1.FException.wrapIfNeeded(e);
if (logger.isWarnEnabled) {
logger.warn(this.initExecutionContext, "Module 'pg' ends pool with error. " + ex.message);
}
else {
console.error("Module 'pg' ends pool with error", e);
}
logger.debug(this.initExecutionContext, "Module 'pg' ends pool with error", ex);
}
}
}
exports.FSqlConnectionFactoryPostgres = FSqlConnectionFactoryPostgres;
class FSqlConnectionPostgres extends common_1.FDisposableBase {
connectionNumber;
pgClient;
log;
_factory;
_initExecutionContext;
_disposer;
constructor(executionContext, factory, connectionNumber, pgClient, disposer, log) {
super();
this.connectionNumber = connectionNumber;
this._factory = factory;
this.pgClient = pgClient;
this._disposer = disposer;
this.log = log;
this._initExecutionContext = this._factory.loggingSqlLabels
? new common_1.FLoggerLabelsExecutionContext(executionContext, FSqlConnectionFactoryPostgresLoggerLabel.CONNECTION_NUMBER.value(this.connectionNumber.toString()))
: executionContext;
this.log.trace(this._initExecutionContext, "FSqlConnectionPostgres constructed");
}
get factory() {
return this._factory;
}
statement(sqlText) {
super.verifyNotDisposed();
if (!sqlText) {
throw new common_1.FExceptionArgument("sql");
}
if (this.log.isTraceEnabled) {
const trimmedSqlText = helpers.trimSqlTextForException(sqlText);
this.log.trace(this._initExecutionContext, "FSqlConnectionPostgres Statement: " + trimmedSqlText);
}
return new FSqlStatementPostgres(this, sqlText);
}
async createTempTable(executionContext, tableName, columnsDefinitions) {
const tempTable = new FSqlTemporaryTablePostgres(this, executionContext, tableName, columnsDefinitions);
await tempTable.init(executionContext);
return tempTable;
}
async onDispose() {
this.log.trace(this._initExecutionContext, "FSqlConnectionPostgres disposing...");
await this._disposer();
this.log.trace(this._initExecutionContext, "FSqlConnectionPostgres disposed");
}
}
class FSqlStatementPostgres {
_sqlText;
_owner;
constructor(owner, sqlText) {
this._owner = owner;
this._sqlText = sqlText;
}
async execute(executionContext, ...values) {
await helpers.executeRunQuery(executionContext, this._owner.pgClient, this._sqlText, helpers.statementArgumentsAdapter(values));
}
async executeQuery(executionContext, ...values) {
const underlyingResult = await helpers.executeRunQuery(executionContext, this._owner.pgClient, this._sqlText, helpers.statementArgumentsAdapter(values));
const underlyingResultRows = underlyingResult.rows;
const underlyingResultFields = underlyingResult.fields;
if (underlyingResultFields[0].dataTypeID === PostgresObjectID.refcursor) {
throw new common_1.FExceptionInvalidOperation("executeQuery: does not support multiset request yet");
}
if (underlyingResultRows.length > 0 && !(underlyingResultFields[0].dataTypeID === PostgresObjectID.void)) {
return underlyingResultRows.map(row => new FSqlResultRecordPostgres(row, underlyingResultFields));
}
else {
return [];
}
}
// tslint:disable-next-line:max-line-length
async executeQueryMultiSets(executionContext, ...values) {
const cancellationToken = common_1.FCancellationExecutionContext.of(executionContext).cancellationToken;
// Executing: BEGIN
await helpers.executeRunQuery(executionContext, this._owner.pgClient, "BEGIN TRANSACTION", []);
try {
cancellationToken.throwIfCancellationRequested();
const resultFetchs = await helpers.executeRunQuery(executionContext, this._owner.pgClient, this._sqlText, helpers.statementArgumentsAdapter(values));
cancellationToken.throwIfCancellationRequested();
// Verify that this is a multi-request
if (resultFetchs.fields[0].dataTypeID !== PostgresObjectID.refcursor) {
// This is not a multi request. Raise exception.
const trimmedSqlText = helpers.trimSqlTextForException(this._sqlText);
throw new common_1.FExceptionInvalidOperation(`executeQueryMultiSets: cannot execute this script: ${trimmedSqlText}`);
}
const resultFetchsValue = helpers.parsingValue(resultFetchs);
const friendlyResult = [];
for (let i = 0; i < resultFetchsValue.length; i++) {
const fetch = resultFetchsValue[i];
const queryFetchs = await helpers.executeRunQuery(executionContext, this._owner.pgClient, `FETCH ALL IN "${fetch}";`, []);
cancellationToken.throwIfCancellationRequested();
friendlyResult.push(queryFetchs.rows.map(row => new FSqlResultRecordPostgres(row, queryFetchs.fields)));
}
// Executing: COMMIT
await helpers.executeRunQuery(executionContext, this._owner.pgClient, "COMMIT", []);
return friendlyResult;
}
catch (e) {
// Executing: ROLLBACK
await helpers.executeRunQuery(executionContext, this._owner.pgClient, "ROLLBACK", []);
throw e;
}
}
async executeScalar(executionContext, ...values) {
const underlyingResult = await helpers.executeRunQuery(executionContext, this._owner.pgClient, this._sqlText, helpers.statementArgumentsAdapter(values));
const underlyingRows = underlyingResult.rows;
if (underlyingRows.length === 0) {
const trimmedSqlText = helpers.trimSqlTextForException(this._sqlText);
throw new common_1.FSqlExceptionNoSuchRecord(`executeScalar: No record for query ${trimmedSqlText}`);
}
const underlyingFields = underlyingResult.fields;
if (underlyingFields.length === 0) {
throw new common_1.FExceptionInvalidOperation("executeScalar: SQL query returns no result");
}
if (underlyingFields[0].dataTypeID === PostgresObjectID.refcursor) {
throw new common_1.FExceptionInvalidOperation("executeScalar: does not support multiset request yet");
}
const underlyingFirstRow = underlyingRows[0];
const value = underlyingFirstRow[Object.keys(underlyingFirstRow)[0]];
const fi = underlyingFields[0];
if (value !== undefined || fi !== undefined) {
return new FSqlDataPostgres(value, fi);
}
else {
throw new common_1.FSqlException(`executeScalar: Bad argument ${value} and ${fi}`);
}
}
async executeScalarOrNull(executionContext, ...values) {
const underlyingResult = await helpers.executeRunQuery(executionContext, this._owner.pgClient, this._sqlText, helpers.statementArgumentsAdapter(values));
const underlyingRows = underlyingResult.rows;
const underlyingFields = underlyingResult.fields;
if (underlyingRows.length > 0) {
if (underlyingFields[0].dataTypeID === PostgresObjectID.refcursor) {
throw new common_1.FExceptionInvalidOperation("executeScalarOrNull: does not support multiset request yet");
}
const underlyingFirstRow = underlyingRows[0];
const value = underlyingFirstRow[Object.keys(underlyingFirstRow)[0]];
const fi = underlyingFields[0];
if (value !== undefined || fi !== undefined) {
return new FSqlDataPostgres(value, fi);
}
else {
throw new common_1.FSqlException(`executeScalarOrNull: Bad argument ${value} and ${fi}`);
}
}
else {
return null;
}
}
async executeSingle(executionContext, ...values) {
const underlyingResult = await helpers.executeRunQuery(executionContext, this._owner.pgClient, this._sqlText, helpers.statementArgumentsAdapter(values));
const underlyingResultRows = underlyingResult.rows;
const underlyingResultFields = underlyingResult.fields;
if (underlyingResultFields.length === 0) {
throw new common_1.FExceptionInvalidOperation("executeSingle: SQL query returns no result");
}
if (underlyingResultFields[0].dataTypeID === PostgresObjectID.refcursor) {
throw new common_1.FExceptionInvalidOperation("executeSingle: does not support multi request");
}
if (underlyingResultRows.length === 0) {
const trimmedSqlText = helpers.trimSqlTextForException(this._sqlText);
throw new common_1.FSqlExceptionNoSuchRecord(`executeSingle: No record for query ${trimmedSqlText}`);
}
else if (underlyingResultRows.length === 1 && !(underlyingResultFields[0].dataTypeID === PostgresObjectID.void)) {
return new FSqlResultRecordPostgres(underlyingResultRows[0], underlyingResultFields);
}
else {
throw new common_1.FExceptionInvalidOperation(`executeSingle: SQL query returns non-single result`);
}
}
async executeSingleOrNull(executionContext, ...values) {
const underlyingResult = await helpers.executeRunQuery(executionContext, this._owner.pgClient, this._sqlText, helpers.statementArgumentsAdapter(values));
const underlyingResultRows = underlyingResult.rows;
const underlyingResultFields = underlyingResult.fields;
if (underlyingResultFields.length === 0) {
throw new common_1.FExceptionInvalidOperation("executeSingleOrNull: SQL query returns no result");
}
if (underlyingResultFields[0].dataTypeID === PostgresObjectID.refcursor) {
throw new common_1.FExceptionInvalidOperation("executeSingleOrNull: does not support multi request");
}
if (underlyingResultRows.length === 0) {
return null;
}
else if (underlyingResultRows.length === 1 && !(underlyingResultFields[0].dataTypeID === PostgresObjectID.void)) {
return new FSqlResultRecordPostgres(underlyingResultRows[0], underlyingResultFields);
}
else {
throw new common_1.FExceptionInvalidOperation("executeSingleOrNull: SQL query returns non-single result");
}
}
}
class FSqlResultRecordPostgres {
_fieldsData;
_fieldsInfo;
_nameMap;
constructor(fieldsData, fieldsInfo) {
if (Object.keys(fieldsData).length !== fieldsInfo.length) {
throw new Error("Internal error. Fields count is not equal to data columns.");
}
this._fieldsData = fieldsData;
this._fieldsInfo = fieldsInfo;
}
get(nameOrIndex) {
if (typeof nameOrIndex === "string") {
return this.getByName(nameOrIndex);
}
else {
return this.getByIndex(nameOrIndex);
}
}
get nameMap() {
if (this._nameMap === undefined) {
const nameMap = {};
const total = this._fieldsInfo.length;
for (let index = 0; index < total; ++index) {
const fi = this._fieldsInfo[index];
if (fi.name in nameMap) {
throw new Error("Cannot access FSqlResultRecord by name due result set has name duplicates");
}
nameMap[fi.name] = fi;
}
this._nameMap = nameMap;
}
return this._nameMap;
}
getByIndex(index) {
const fi = this._fieldsInfo[index];
if (fi === undefined) {
throw new common_1.FExceptionArgument(`PostgresSqlResultRecord does not have field with index '${index}'`, "index");
}
const value = this._fieldsData[fi.name];
return new FSqlDataPostgres(value, fi);
}
getByName(name) {
const fi = this.nameMap[name];
if (fi === undefined) {
throw new common_1.FExceptionArgument(`PostgresSqlResultRecord does not have field with name '${name}'`, "name");
}
const value = this._fieldsData[fi.name];
return new FSqlDataPostgres(value, fi);
}
}
class FSqlTemporaryTablePostgres extends common_1.FInitableBase {
_owner;
_executionContext;
_tableName;
_columnsDefinitions;
constructor(owner, executionContext, tableName, columnsDefinitions) {
super();
this._owner = owner;
this._executionContext = executionContext;
this._tableName = tableName;
this._columnsDefinitions = columnsDefinitions;
}
bulkInsert(executionContext, bulkValues) {
return this._owner.statement(`INSERT INTO \`${this._tableName}\``).execute(executionContext, bulkValues);
}
clear(executionContext) {
return this._owner.statement(`DELETE FROM \`${this._tableName}\``).execute(executionContext);
}
insert(executionContext, values) {
return this._owner.statement(`INSERT INTO \`${this._tableName}\``).execute(executionContext, ...values);
}
async onInit() {
await this._owner.statement(`CREATE TEMPORARY TABLE ${this._tableName} (${this._columnsDefinitions})`).execute(this._executionContext);
}
async onDispose() {
try {
await this._owner.statement(`DROP TABLE ${this._tableName}`).execute(this._executionContext);
}
catch (e) {
// dispose never raise error
if (e instanceof common_1.FCancellationException) {
return; // skip error message if task was cancelled
}
// Dispose never raise errors
console.error(e); // we cannot do anymore here, just log
}
}
}
class FSqlDataPostgres {
_postgresValue;
_fi;
get asBoolean() {
if (typeof this._postgresValue === "boolean") {
return this._postgresValue;
}
else {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asBoolean"));
}
}
get asBooleanNullable() {
if (this._postgresValue === null) {
return null;
}
else if (typeof this._postgresValue === "boolean") {
return this._postgresValue;
}
else {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asBooleanNullable"));
}
}
get asString() {
if (this._postgresValue === null) {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asString"));
}
else if (typeof this._postgresValue === "string") {
return this._postgresValue;
}
else {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asString"));
}
}
get asStringNullable() {
if (this._postgresValue === null) {
return null;
}
else if (typeof this._postgresValue === "string") {
return this._postgresValue;
}
else {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asStringNullable"));
}
}
get asInteger() {
if (this._postgresValue === null) {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asInteger"));
}
else if (typeof this._postgresValue === "number" && Number.isInteger(this._postgresValue)) {
return this._postgresValue;
}
else {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asInteger"));
}
}
get asIntegerNullable() {
if (this._postgresValue === null) {
return null;
}
else if (typeof this._postgresValue === "number" && Number.isInteger(this._postgresValue)) {
return this._postgresValue;
}
else {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asIntegerNullable"));
}
}
get asNumber() {
if (this._postgresValue === null) {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asNumber"));
}
else if (typeof this._postgresValue === "number") {
return this._postgresValue;
}
else if (this._fi.dataTypeID === PostgresObjectID.numeric && typeof this._postgresValue === "string") {
return Number.parseFloat(this._postgresValue);
}
else {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asNumber"));
}
}
get asNumberNullable() {
if (this._postgresValue === null) {
return null;
}
else if (typeof this._postgresValue === "number") {
return this._postgresValue;
}
else if (this._fi.dataTypeID === PostgresObjectID.numeric && typeof this._postgresValue === "string") {
return Number.parseFloat(this._postgresValue);
}
else {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asNumberNullable"));
}
}
get asDecimal() {
if (this._postgresValue === null) {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asDecimal"));
}
else if (typeof this._postgresValue === "number") {
return common_1.FDecimal.fromFloat(this._postgresValue);
}
else if (typeof this._postgresValue === "string") {
return common_1.FDecimal.parse(this._postgresValue);
}
else {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asDecimal"));
}
}
get asDecimalNullable() {
if (this._postgresValue === null) {
return null;
}
else if (typeof this._postgresValue === "number") {
return common_1.FDecimal.fromFloat(this._postgresValue);
}
else if (typeof this._postgresValue === "string") {
return common_1.FDecimal.parse(this._postgresValue);
}
else {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asDecimalNullable"));
}
}
get asDate() {
if (this._postgresValue === null) {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asDate"));
// } else if (this._fi.dataTypeID === PostgresObjectID.timestamp && this._postgresValue instanceof Date) {
// // `pg` library make Date with local zone shift, so we need to make opposite changes to retrieve correct date from UTC timestamp
// return new Date(this._postgresValue.getTime() - this._postgresValue.getTimezoneOffset() * 60000);
}
else if (this._fi.dataTypeID === PostgresObjectID.timestamp && typeof this._postgresValue === "string") {
// `pg` library make Date with local zone shift, so we need to make opposite changes to retrieve correct date from UTC timestamp
return new Date(`${this._postgresValue}+0000`);
}
else {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asDate", `Right now the library supports TIMESTAMP WITHOUT TIME ZONE OID=${PostgresObjectID.timestamp} only. Got OID=${this._fi.dataTypeID}.`));
}
}
get asDateNullable() {
if (this._postgresValue === null) {
return null;
// } else if (this._fi.dataTypeID === PostgresObjectID.timestamp && this._postgresValue instanceof Date) {
// // `pg` library make Date with local zone shift, so we need to make opposite changes to retrieve correct date from UTC timestamp
// return new Date(this._postgresValue.getTime() - this._postgresValue.getTimezoneOffset() * 60000);
}
else if (this._fi.dataTypeID === PostgresObjectID.timestamp && typeof this._postgresValue === "string") {
// `pg` library make Date with local zone shift, so we need to make opposite changes to retrieve correct date from UTC timestamp
return new Date(`${this._postgresValue}+0000`);
}
else {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asDateNullable", `Right now the library supports TIMESTAMP WITHOUT TIME ZONE OID=${PostgresObjectID.timestamp} only. Got OID=${this._fi.dataTypeID}.`));
}
}
get asBinary() {
if (this._postgresValue === null) {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asBinary"));
}
else if (this._postgresValue instanceof Uint8Array) {
return this._postgresValue;
}
else {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asBinary"));
}
}
get asBinaryNullable() {
if (this._postgresValue === null) {
return null;
}
else if (this._postgresValue instanceof Uint8Array) {
return this._postgresValue;
}
else {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asBinaryNullable"));
}
}
get asObject() {
if (this._postgresValue === null) {
throw new common_1.FExceptionInvalidOperation(this.formatWrongDataTypeMessage("asObject"));
}
else if (this._fi.dataTypeID === PostgresObjectID.jsonb) {