@take-out/postgres 0.0.98 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,60 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all) __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: !0
9
+ });
10
+ },
11
+ __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, {
13
+ get: () => from[key],
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ return to;
17
+ };
18
+ var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
19
+ value: !0
20
+ }), mod);
21
+ var chunkedQuery_exports = {};
22
+ __export(chunkedQuery_exports, {
23
+ processInChunks: () => processInChunks,
24
+ updateInChunks: () => updateInChunks
25
+ });
26
+ module.exports = __toCommonJS(chunkedQuery_exports);
27
+ async function processInChunks(client, query, processor, options = {}) {
28
+ const {
29
+ chunkSize = 1e3,
30
+ onProgress
31
+ } = options;
32
+ let offset = 0,
33
+ hasMore = !0,
34
+ totalProcessed = 0;
35
+ const countQuery = query.replace(/SELECT .+ FROM/, "SELECT COUNT(*) FROM").replace(/ORDER BY .+/, ""),
36
+ countResult = await client.query(countQuery),
37
+ totalCount = Number.parseInt(countResult.rows[0].count, 10);
38
+ for (; hasMore;) {
39
+ const paginatedQuery = `${query} LIMIT ${chunkSize} OFFSET ${offset}`,
40
+ result = await client.query(paginatedQuery);
41
+ if (result.rows.length === 0) {
42
+ hasMore = !1;
43
+ break;
44
+ }
45
+ await processor(result.rows), totalProcessed += result.rows.length, offset += chunkSize, onProgress && onProgress(totalProcessed, totalCount), result.rows.length < chunkSize && (hasMore = !1);
46
+ }
47
+ }
48
+ async function updateInChunks(client, tableName, selectQuery, transformer, options = {}) {
49
+ let totalUpdated = 0;
50
+ return await processInChunks(client, selectQuery, async rows => {
51
+ for (const row of rows) {
52
+ const updates = await transformer(row);
53
+ if (updates && Object.keys(updates).length > 0) {
54
+ const setClause = Object.keys(updates).map((key, index) => `${key} = $${index + 2}`).join(", "),
55
+ values = [row.id, ...Object.values(updates)];
56
+ await client.query(`UPDATE ${tableName} SET ${setClause} WHERE id = $1`, values), totalUpdated++;
57
+ }
58
+ }
59
+ }, options), totalUpdated;
60
+ }
@@ -0,0 +1,51 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: !0 });
8
+ }, __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from == "object" || typeof from == "function")
10
+ for (let key of __getOwnPropNames(from))
11
+ !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod);
15
+ var chunkedQuery_exports = {};
16
+ __export(chunkedQuery_exports, {
17
+ processInChunks: () => processInChunks,
18
+ updateInChunks: () => updateInChunks
19
+ });
20
+ module.exports = __toCommonJS(chunkedQuery_exports);
21
+ async function processInChunks(client, query, processor, options = {}) {
22
+ const { chunkSize = 1e3, onProgress } = options;
23
+ let offset = 0, hasMore = !0, totalProcessed = 0;
24
+ const countQuery = query.replace(/SELECT .+ FROM/, "SELECT COUNT(*) FROM").replace(/ORDER BY .+/, ""), countResult = await client.query(countQuery), totalCount = Number.parseInt(countResult.rows[0].count, 10);
25
+ for (; hasMore; ) {
26
+ const paginatedQuery = `${query} LIMIT ${chunkSize} OFFSET ${offset}`, result = await client.query(paginatedQuery);
27
+ if (result.rows.length === 0) {
28
+ hasMore = !1;
29
+ break;
30
+ }
31
+ await processor(result.rows), totalProcessed += result.rows.length, offset += chunkSize, onProgress && onProgress(totalProcessed, totalCount), result.rows.length < chunkSize && (hasMore = !1);
32
+ }
33
+ }
34
+ async function updateInChunks(client, tableName, selectQuery, transformer, options = {}) {
35
+ let totalUpdated = 0;
36
+ return await processInChunks(
37
+ client,
38
+ selectQuery,
39
+ async (rows) => {
40
+ for (const row of rows) {
41
+ const updates = await transformer(row);
42
+ if (updates && Object.keys(updates).length > 0) {
43
+ const setClause = Object.keys(updates).map((key, index) => `${key} = $${index + 2}`).join(", "), values = [row.id, ...Object.values(updates)];
44
+ await client.query(`UPDATE ${tableName} SET ${setClause} WHERE id = $1`, values), totalUpdated++;
45
+ }
46
+ }
47
+ },
48
+ options
49
+ ), totalUpdated;
50
+ }
51
+ //# sourceMappingURL=chunkedQuery.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/chunkedQuery.ts"],
4
+ "mappings": ";;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA,eAAsB,gBACpB,QACA,OACA,WACA,UAA+B,CAAC,GACjB;AACf,QAAM,EAAE,YAAY,KAAM,WAAW,IAAI;AACzC,MAAI,SAAS,GACT,UAAU,IACV,iBAAiB;AAGrB,QAAM,aAAa,MAChB,QAAQ,kBAAkB,sBAAsB,EAChD,QAAQ,eAAe,EAAE,GACtB,cAAc,MAAM,OAAO,MAAM,UAAU,GAC3C,aAAa,OAAO,SAAS,YAAY,KAAK,CAAC,EAAE,OAAO,EAAE;AAEhE,SAAO,WAAS;AACd,UAAM,iBAAiB,GAAG,KAAK,UAAU,SAAS,WAAW,MAAM,IAC7D,SAAS,MAAM,OAAO,MAAS,cAAc;AAEnD,QAAI,OAAO,KAAK,WAAW,GAAG;AAC5B,gBAAU;AACV;AAAA,IACF;AAEA,UAAM,UAAU,OAAO,IAAI,GAE3B,kBAAkB,OAAO,KAAK,QAC9B,UAAU,WAEN,cACF,WAAW,gBAAgB,UAAU,GAInC,OAAO,KAAK,SAAS,cACvB,UAAU;AAAA,EAEd;AACF;AAKA,eAAsB,eACpB,QACA,WACA,aACA,aACA,UAA+B,CAAC,GACf;AACjB,MAAI,eAAe;AAEnB,eAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,OAAO,SAAS;AACd,iBAAW,OAAO,MAAM;AACtB,cAAM,UAAU,MAAM,YAAY,GAAG;AAErC,YAAI,WAAW,OAAO,KAAK,OAAO,EAAE,SAAS,GAAG;AAE9C,gBAAM,YAAY,OAAO,KAAK,OAAO,EAClC,IAAI,CAAC,KAAK,UAAU,GAAG,GAAG,OAAO,QAAQ,CAAC,EAAE,EAC5C,KAAK,IAAI,GAEN,SAAS,CAAC,IAAI,IAAI,GAAG,OAAO,OAAO,OAAO,CAAC;AAEjD,gBAAM,OAAO,MAAM,UAAU,SAAS,QAAQ,SAAS,kBAAkB,MAAM,GAE/E;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,EACF,GAEO;AACT;",
5
+ "names": []
6
+ }
@@ -0,0 +1,34 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all) __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: !0
9
+ });
10
+ },
11
+ __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, {
13
+ get: () => from[key],
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ return to;
17
+ };
18
+ var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
19
+ value: !0
20
+ }), mod);
21
+ var createDb_exports = {};
22
+ __export(createDb_exports, {
23
+ createDb: () => createDb
24
+ });
25
+ module.exports = __toCommonJS(createDb_exports);
26
+ var import_node_postgres = require("drizzle-orm/node-postgres"),
27
+ import_createPool = require("./createPool.cjs");
28
+ const createDb = (connectionString, schema) => {
29
+ const pool = (0, import_createPool.createPool)(connectionString);
30
+ return (0, import_node_postgres.drizzle)(pool, {
31
+ schema,
32
+ logger: !1
33
+ });
34
+ };
@@ -0,0 +1,28 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: !0 });
8
+ }, __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from == "object" || typeof from == "function")
10
+ for (let key of __getOwnPropNames(from))
11
+ !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod);
15
+ var createDb_exports = {};
16
+ __export(createDb_exports, {
17
+ createDb: () => createDb
18
+ });
19
+ module.exports = __toCommonJS(createDb_exports);
20
+ var import_node_postgres = require("drizzle-orm/node-postgres"), import_createPool = require("./createPool");
21
+ const createDb = (connectionString, schema) => {
22
+ const pool = (0, import_createPool.createPool)(connectionString);
23
+ return (0, import_node_postgres.drizzle)(pool, {
24
+ schema,
25
+ logger: !1
26
+ });
27
+ };
28
+ //# sourceMappingURL=createDb.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/createDb.ts"],
4
+ "mappings": ";;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAA6C,sCAE7C,oBAA2B;AAEpB,MAAM,WAAW,CACtB,kBACA,WAC4B;AAC5B,QAAM,WAAO,8BAAW,gBAAgB;AACxC,aAAO,8BAAQ,MAAM;AAAA,IACnB;AAAA,IACA,QAAQ;AAAA,EACV,CAAC;AACH;",
5
+ "names": []
6
+ }
@@ -0,0 +1,40 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf,
6
+ __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all) __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: !0
11
+ });
12
+ },
13
+ __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, {
15
+ get: () => from[key],
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
26
+ value: mod,
27
+ enumerable: !0
28
+ }) : target, mod)),
29
+ __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
30
+ value: !0
31
+ }), mod);
32
+ var createPool_exports = {};
33
+ __export(createPool_exports, {
34
+ createPool: () => createPool
35
+ });
36
+ module.exports = __toCommonJS(createPool_exports);
37
+ var import_pg = __toESM(require("pg"), 1);
38
+ const createPool = connectionString => new import_pg.default.Pool({
39
+ connectionString
40
+ });
@@ -0,0 +1,32 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf, __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: !0 });
9
+ }, __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from == "object" || typeof from == "function")
11
+ for (let key of __getOwnPropNames(from))
12
+ !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ return to;
14
+ };
15
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
16
+ // If the importer is in node compatibility mode or this is not an ESM
17
+ // file that has been converted to a CommonJS file using a Babel-
18
+ // compatible transform (i.e. "__esModule" has not been set), then set
19
+ // "default" to the CommonJS "module.exports" for node compatibility.
20
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target,
21
+ mod
22
+ )), __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod);
23
+ var createPool_exports = {};
24
+ __export(createPool_exports, {
25
+ createPool: () => createPool
26
+ });
27
+ module.exports = __toCommonJS(createPool_exports);
28
+ var import_pg = __toESM(require("pg"), 1);
29
+ const createPool = (connectionString) => new import_pg.default.Pool({
30
+ connectionString
31
+ });
32
+ //# sourceMappingURL=createPool.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/createPool.ts"],
4
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAA8B;AAEvB,MAAM,aAAa,CAAC,qBAClB,IAAI,UAAAA,QAAG,KAAK;AAAA,EACjB;AACF,CAAC;",
5
+ "names": ["pg"]
6
+ }
@@ -0,0 +1,172 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf,
6
+ __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all) __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: !0
11
+ });
12
+ },
13
+ __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from == "object" || typeof from == "function") for (let key of __getOwnPropNames(from)) !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, {
15
+ get: () => from[key],
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
26
+ value: mod,
27
+ enumerable: !0
28
+ }) : target, mod)),
29
+ __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
30
+ value: !0
31
+ }), mod);
32
+ var getDBClient_exports = {};
33
+ __export(getDBClient_exports, {
34
+ getDBClient: () => getDBClient,
35
+ getNewClient: () => getNewClient,
36
+ queryDb: () => queryDb
37
+ });
38
+ module.exports = __toCommonJS(getDBClient_exports);
39
+ var import_pg = __toESM(require("pg"), 1);
40
+ const cache = /* @__PURE__ */new Map(),
41
+ createPoolKey = connectionString => connectionString,
42
+ getOrCreatePoolCache = (connectionString, config) => {
43
+ const key = createPoolKey(connectionString);
44
+ return cache.has(key) || cache.set(key, {
45
+ pool: new import_pg.default.Pool(config),
46
+ maxConnections: null,
47
+ reservedConnections: null,
48
+ openedConnections: null,
49
+ openedConnectionsLastUpdate: null
50
+ }), cache.get(key);
51
+ };
52
+ async function getDBClient(options = {}) {
53
+ const {
54
+ pool,
55
+ connectionString,
56
+ retries = 8
57
+ } = options;
58
+ if (!pool && !connectionString) throw new Error("Either pool or connectionString must be provided");
59
+ let client = null;
60
+ try {
61
+ return client = await tryToGetNewClientFromPool(pool, connectionString, retries), client;
62
+ } catch (error) {
63
+ throw console.error("Failed to get DB client:", error), error;
64
+ }
65
+ }
66
+ async function tryToGetNewClientFromPool(providedPool, connectionString, retries) {
67
+ const {
68
+ default: retry
69
+ } = await import("async-retry");
70
+ return await retry(async () => {
71
+ if (providedPool) {
72
+ console.info("Connecting to provided pool...");
73
+ const client2 = await providedPool.connect();
74
+ return console.info("Connected to pool"), client2;
75
+ }
76
+ if (!connectionString) throw new Error("No connection string provided");
77
+ const poolCache = getOrCreatePoolCache(connectionString, {
78
+ connectionString,
79
+ connectionTimeoutMillis: 5e3,
80
+ // idle_session_timeout set to 35s on server, client timeout at 30s
81
+ // fix via https://github.com/brianc/node-postgres/issues/2718#issuecomment-2094885323
82
+ idleTimeoutMillis: 3e4,
83
+ allowExitOnIdle: !0
84
+ });
85
+ console.info(`Connecting to pool ${connectionString}...`);
86
+ const client = await poolCache.pool.connect();
87
+ return console.info("Connected to pool"), client;
88
+ }, {
89
+ retries,
90
+ minTimeout: 300,
91
+ factor: 2,
92
+ maxTimeout: 8e3
93
+ });
94
+ }
95
+ async function queryDb(queryText, params, options = {}) {
96
+ let client = null;
97
+ try {
98
+ return client = await tryToGetNewClientFromPool(options.pool, options.connectionString, options.retries || 8), await client.query(queryText, params);
99
+ } catch (error) {
100
+ throw console.error("Database query failed:", {
101
+ query: queryText,
102
+ error: error instanceof Error ? error.message : String(error)
103
+ }), error;
104
+ } finally {
105
+ if (client && options.connectionString) {
106
+ if (await checkForTooManyConnections(client, options.connectionString)) {
107
+ const poolCache = cache.get(createPoolKey(options.connectionString));
108
+ client.release(), await poolCache?.pool.end(), poolCache && cache.delete(createPoolKey(options.connectionString));
109
+ } else client.release();
110
+ } else client && client.release();
111
+ }
112
+ }
113
+ async function checkForTooManyConnections(client, connectionString) {
114
+ const poolCache = cache.get(createPoolKey(connectionString));
115
+ if (!poolCache) return !1;
116
+ const currentTime = Date.now(),
117
+ openedConnectionsMaxAge = 1e4,
118
+ maxConnectionsTolerance = 0.9;
119
+ if (poolCache.maxConnections === null || poolCache.reservedConnections === null) {
120
+ const [maxConnections, reservedConnections] = await getConnectionLimits(client);
121
+ console.info(`Max connections: ${maxConnections}, Reserved connections: ${reservedConnections}`), poolCache.maxConnections = maxConnections, poolCache.reservedConnections = reservedConnections;
122
+ }
123
+ if (poolCache.openedConnections === null || poolCache.openedConnectionsLastUpdate === null || currentTime - poolCache.openedConnectionsLastUpdate > openedConnectionsMaxAge) {
124
+ const openedConnections = await getOpenedConnections(client, connectionString);
125
+ poolCache.openedConnections = openedConnections, poolCache.openedConnectionsLastUpdate = currentTime;
126
+ }
127
+ return poolCache.openedConnections > (poolCache.maxConnections - poolCache.reservedConnections) * maxConnectionsTolerance ? (console.warn(`Too many connections detected: ${poolCache.openedConnections}/${poolCache.maxConnections - poolCache.reservedConnections}`), !0) : !1;
128
+ }
129
+ async function getConnectionLimits(client) {
130
+ console.info("Getting connection limits...");
131
+ const maxConnectionsResult = await client.query("SHOW max_connections"),
132
+ reservedConnectionResult = await client.query("SHOW superuser_reserved_connections");
133
+ return [Number.parseInt(maxConnectionsResult.rows[0].max_connections, 10), Number.parseInt(reservedConnectionResult.rows[0].superuser_reserved_connections, 10)];
134
+ }
135
+ async function getOpenedConnections(client, connectionString) {
136
+ const dbName = new URL(connectionString).pathname.slice(1);
137
+ console.info("Getting opened connections...");
138
+ const openConnectionsResult = await client.query("SELECT numbackends as opened_connections FROM pg_stat_database WHERE datname = $1", [dbName]),
139
+ result = Number.parseInt(openConnectionsResult.rows[0]?.opened_connections || 0, 10);
140
+ return console.info(`Opened connections: ${result}`), result;
141
+ }
142
+ async function getNewClient(options = {}) {
143
+ const {
144
+ connectionString
145
+ } = options;
146
+ if (!connectionString) throw new Error("connectionString is required for getNewClient");
147
+ try {
148
+ return await tryToGetNewClient(connectionString);
149
+ } catch (error) {
150
+ throw console.error("Failed to get new client:", error), error;
151
+ }
152
+ }
153
+ async function tryToGetNewClient(connectionString) {
154
+ const configurations = {
155
+ connectionString,
156
+ connectionTimeoutMillis: 5e3,
157
+ idleTimeoutMillis: 3e4,
158
+ allowExitOnIdle: !0
159
+ },
160
+ {
161
+ default: retry
162
+ } = await import("async-retry");
163
+ return await retry(async () => {
164
+ const newClient = new import_pg.default.Client(configurations);
165
+ return await newClient.connect(), newClient;
166
+ }, {
167
+ retries: 10,
168
+ minTimeout: 100,
169
+ factor: 2,
170
+ maxTimeout: 5e3
171
+ });
172
+ }
@@ -0,0 +1,179 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf, __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: !0 });
9
+ }, __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from == "object" || typeof from == "function")
11
+ for (let key of __getOwnPropNames(from))
12
+ !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ return to;
14
+ };
15
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
16
+ // If the importer is in node compatibility mode or this is not an ESM
17
+ // file that has been converted to a CommonJS file using a Babel-
18
+ // compatible transform (i.e. "__esModule" has not been set), then set
19
+ // "default" to the CommonJS "module.exports" for node compatibility.
20
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: !0 }) : target,
21
+ mod
22
+ )), __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod);
23
+ var getDBClient_exports = {};
24
+ __export(getDBClient_exports, {
25
+ getDBClient: () => getDBClient,
26
+ getNewClient: () => getNewClient,
27
+ queryDb: () => queryDb
28
+ });
29
+ module.exports = __toCommonJS(getDBClient_exports);
30
+ var import_pg = __toESM(require("pg"), 1);
31
+ const cache = /* @__PURE__ */ new Map(), createPoolKey = (connectionString) => connectionString, getOrCreatePoolCache = (connectionString, config) => {
32
+ const key = createPoolKey(connectionString);
33
+ return cache.has(key) || cache.set(key, {
34
+ pool: new import_pg.default.Pool(config),
35
+ maxConnections: null,
36
+ reservedConnections: null,
37
+ openedConnections: null,
38
+ openedConnectionsLastUpdate: null
39
+ }), cache.get(key);
40
+ };
41
+ async function getDBClient(options = {}) {
42
+ const { pool, connectionString, retries = 8 } = options;
43
+ if (!pool && !connectionString)
44
+ throw new Error("Either pool or connectionString must be provided");
45
+ let client = null;
46
+ try {
47
+ return client = await tryToGetNewClientFromPool(pool, connectionString, retries), client;
48
+ } catch (error) {
49
+ throw console.error("Failed to get DB client:", error), error;
50
+ }
51
+ }
52
+ async function tryToGetNewClientFromPool(providedPool, connectionString, retries) {
53
+ const { default: retry } = await import("async-retry");
54
+ return await retry(
55
+ async () => {
56
+ if (providedPool) {
57
+ console.info("Connecting to provided pool...");
58
+ const client2 = await providedPool.connect();
59
+ return console.info("Connected to pool"), client2;
60
+ }
61
+ if (!connectionString)
62
+ throw new Error("No connection string provided");
63
+ const poolCache = getOrCreatePoolCache(connectionString, {
64
+ connectionString,
65
+ connectionTimeoutMillis: 5e3,
66
+ // idle_session_timeout set to 35s on server, client timeout at 30s
67
+ // fix via https://github.com/brianc/node-postgres/issues/2718#issuecomment-2094885323
68
+ idleTimeoutMillis: 3e4,
69
+ allowExitOnIdle: !0
70
+ });
71
+ console.info(`Connecting to pool ${connectionString}...`);
72
+ const client = await poolCache.pool.connect();
73
+ return console.info("Connected to pool"), client;
74
+ },
75
+ {
76
+ retries,
77
+ minTimeout: 300,
78
+ factor: 2,
79
+ maxTimeout: 8e3
80
+ }
81
+ );
82
+ }
83
+ async function queryDb(queryText, params, options = {}) {
84
+ let client = null;
85
+ try {
86
+ return client = await tryToGetNewClientFromPool(
87
+ options.pool,
88
+ options.connectionString,
89
+ options.retries || 8
90
+ ), await client.query(queryText, params);
91
+ } catch (error) {
92
+ throw console.error("Database query failed:", {
93
+ query: queryText,
94
+ error: error instanceof Error ? error.message : String(error)
95
+ }), error;
96
+ } finally {
97
+ if (client && options.connectionString)
98
+ if (await checkForTooManyConnections(
99
+ client,
100
+ options.connectionString
101
+ )) {
102
+ const poolCache = cache.get(createPoolKey(options.connectionString));
103
+ client.release(), await poolCache?.pool.end(), poolCache && cache.delete(createPoolKey(options.connectionString));
104
+ } else
105
+ client.release();
106
+ else client && client.release();
107
+ }
108
+ }
109
+ async function checkForTooManyConnections(client, connectionString) {
110
+ const poolCache = cache.get(createPoolKey(connectionString));
111
+ if (!poolCache) return !1;
112
+ const currentTime = Date.now(), openedConnectionsMaxAge = 1e4, maxConnectionsTolerance = 0.9;
113
+ if (poolCache.maxConnections === null || poolCache.reservedConnections === null) {
114
+ const [maxConnections, reservedConnections] = await getConnectionLimits(client);
115
+ console.info(
116
+ `Max connections: ${maxConnections}, Reserved connections: ${reservedConnections}`
117
+ ), poolCache.maxConnections = maxConnections, poolCache.reservedConnections = reservedConnections;
118
+ }
119
+ if (poolCache.openedConnections === null || poolCache.openedConnectionsLastUpdate === null || currentTime - poolCache.openedConnectionsLastUpdate > openedConnectionsMaxAge) {
120
+ const openedConnections = await getOpenedConnections(client, connectionString);
121
+ poolCache.openedConnections = openedConnections, poolCache.openedConnectionsLastUpdate = currentTime;
122
+ }
123
+ return poolCache.openedConnections > (poolCache.maxConnections - poolCache.reservedConnections) * maxConnectionsTolerance ? (console.warn(
124
+ `Too many connections detected: ${poolCache.openedConnections}/${poolCache.maxConnections - poolCache.reservedConnections}`
125
+ ), !0) : !1;
126
+ }
127
+ async function getConnectionLimits(client) {
128
+ console.info("Getting connection limits...");
129
+ const maxConnectionsResult = await client.query("SHOW max_connections"), reservedConnectionResult = await client.query(
130
+ "SHOW superuser_reserved_connections"
131
+ );
132
+ return [
133
+ Number.parseInt(maxConnectionsResult.rows[0].max_connections, 10),
134
+ Number.parseInt(reservedConnectionResult.rows[0].superuser_reserved_connections, 10)
135
+ ];
136
+ }
137
+ async function getOpenedConnections(client, connectionString) {
138
+ const dbName = new URL(connectionString).pathname.slice(1);
139
+ console.info("Getting opened connections...");
140
+ const openConnectionsResult = await client.query(
141
+ "SELECT numbackends as opened_connections FROM pg_stat_database WHERE datname = $1",
142
+ [dbName]
143
+ ), result = Number.parseInt(
144
+ openConnectionsResult.rows[0]?.opened_connections || 0,
145
+ 10
146
+ );
147
+ return console.info(`Opened connections: ${result}`), result;
148
+ }
149
+ async function getNewClient(options = {}) {
150
+ const { connectionString } = options;
151
+ if (!connectionString)
152
+ throw new Error("connectionString is required for getNewClient");
153
+ try {
154
+ return await tryToGetNewClient(connectionString);
155
+ } catch (error) {
156
+ throw console.error("Failed to get new client:", error), error;
157
+ }
158
+ }
159
+ async function tryToGetNewClient(connectionString) {
160
+ const configurations = {
161
+ connectionString,
162
+ connectionTimeoutMillis: 5e3,
163
+ idleTimeoutMillis: 3e4,
164
+ allowExitOnIdle: !0
165
+ }, { default: retry } = await import("async-retry");
166
+ return await retry(
167
+ async () => {
168
+ const newClient = new import_pg.default.Client(configurations);
169
+ return await newClient.connect(), newClient;
170
+ },
171
+ {
172
+ retries: 10,
173
+ minTimeout: 100,
174
+ factor: 2,
175
+ maxTimeout: 5e3
176
+ }
177
+ );
178
+ }
179
+ //# sourceMappingURL=getDBClient.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/getDBClient.ts"],
4
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAA+C;AAY/C,MAAM,QAAQ,oBAAI,IAShB,GAEI,gBAAgB,CAAC,qBAA6B,kBAE9C,uBAAuB,CAAC,kBAA0B,WAA0B;AAChF,QAAM,MAAM,cAAc,gBAAgB;AAE1C,SAAK,MAAM,IAAI,GAAG,KAChB,MAAM,IAAI,KAAK;AAAA,IACb,MAAM,IAAI,UAAAA,QAAG,KAAK,MAAM;AAAA,IACxB,gBAAgB;AAAA,IAChB,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,6BAA6B;AAAA,EAC/B,CAAC,GAGI,MAAM,IAAI,GAAG;AACtB;AAEA,eAAsB,YAAY,UAA8B,CAAC,GAAwB;AACvF,QAAM,EAAE,MAAM,kBAAkB,UAAU,EAAE,IAAI;AAEhD,MAAI,CAAC,QAAQ,CAAC;AACZ,UAAM,IAAI,MAAM,kDAAkD;AAGpE,MAAI,SAA4B;AAEhC,MAAI;AACF,oBAAS,MAAM,0BAA0B,MAAM,kBAAkB,OAAO,GACjE;AAAA,EACT,SAAS,OAAO;AACd,kBAAQ,MAAM,4BAA4B,KAAK,GACzC;AAAA,EACR;AACF;AAEA,eAAe,0BACb,cACA,kBACA,SACqB;AACrB,QAAM,EAAE,SAAS,MAAM,IAAI,MAAM,OAAO,aAAa;AAsCrD,SArCuB,MAAM;AAAA,IAC3B,YAAY;AACV,UAAI,cAAc;AAChB,gBAAQ,KAAK,gCAAgC;AAC7C,cAAMC,UAAS,MAAM,aAAa,QAAQ;AAC1C,uBAAQ,KAAK,mBAAmB,GACzBA;AAAA,MACT;AAEA,UAAI,CAAC;AACH,cAAM,IAAI,MAAM,+BAA+B;AAYjD,YAAM,YAAY,qBAAqB,kBATD;AAAA,QACpC;AAAA,QACA,yBAAyB;AAAA;AAAA;AAAA,QAGzB,mBAAmB;AAAA,QACnB,iBAAiB;AAAA,MACnB,CAEuE;AAEvE,cAAQ,KAAK,sBAAsB,gBAAgB,KAAK;AACxD,YAAM,SAAS,MAAM,UAAU,KAAK,QAAQ;AAC5C,qBAAQ,KAAK,mBAAmB,GACzB;AAAA,IACT;AAAA,IACA;AAAA,MACE;AAAA,MACA,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,YAAY;AAAA,IACd;AAAA,EACF;AAGF;AAEA,eAAsB,QACpB,WACA,QACA,UAA8B,CAAC,GACD;AAC9B,MAAI,SAA4B;AAEhC,MAAI;AACF,oBAAS,MAAM;AAAA,MACb,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,QAAQ,WAAW;AAAA,IACrB,GACO,MAAM,OAAO,MAAM,WAAW,MAAM;AAAA,EAC7C,SAAS,OAAO;AACd,kBAAQ,MAAM,0BAA0B;AAAA,MACtC,OAAO;AAAA,MACP,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC9D,CAAC,GACK;AAAA,EACR,UAAE;AACA,QAAI,UAAU,QAAQ;AAMpB,UAL2B,MAAM;AAAA,QAC/B;AAAA,QACA,QAAQ;AAAA,MACV,GAEwB;AACtB,cAAM,YAAY,MAAM,IAAI,cAAc,QAAQ,gBAAgB,CAAC;AACnE,eAAO,QAAQ,GACf,MAAM,WAAW,KAAK,IAAI,GACtB,aACF,MAAM,OAAO,cAAc,QAAQ,gBAAgB,CAAC;AAAA,MAExD;AACE,eAAO,QAAQ;AAAA,QAEZ,CAAI,UACT,OAAO,QAAQ;AAAA,EAEnB;AACF;AAEA,eAAe,2BACb,QACA,kBACkB;AAClB,QAAM,YAAY,MAAM,IAAI,cAAc,gBAAgB,CAAC;AAC3D,MAAI,CAAC,UAAW,QAAO;AAEvB,QAAM,cAAc,KAAK,IAAI,GACvB,0BAA0B,KAC1B,0BAA0B;AAEhC,MAAI,UAAU,mBAAmB,QAAQ,UAAU,wBAAwB,MAAM;AAC/E,UAAM,CAAC,gBAAgB,mBAAmB,IAAI,MAAM,oBAAoB,MAAM;AAC9E,YAAQ;AAAA,MACN,oBAAoB,cAAc,2BAA2B,mBAAmB;AAAA,IAClF,GACA,UAAU,iBAAiB,gBAC3B,UAAU,sBAAsB;AAAA,EAClC;AAEA,MACE,UAAU,sBAAsB,QAChC,UAAU,gCAAgC,QAC1C,cAAc,UAAU,8BAA8B,yBACtD;AACA,UAAM,oBAAoB,MAAM,qBAAqB,QAAQ,gBAAgB;AAC7E,cAAU,oBAAoB,mBAC9B,UAAU,8BAA8B;AAAA,EAC1C;AAEA,SACE,UAAU,qBACT,UAAU,iBAAiB,UAAU,uBAAuB,2BAE7D,QAAQ;AAAA,IACN,kCAAkC,UAAU,iBAAiB,IAAI,UAAU,iBAAiB,UAAU,mBAAmB;AAAA,EAC3H,GACO,MAGF;AACT;AAEA,eAAe,oBAAoB,QAA+C;AAChF,UAAQ,KAAK,8BAA8B;AAC3C,QAAM,uBAAuB,MAAM,OAAO,MAAM,sBAAsB,GAChE,2BAA2B,MAAM,OAAO;AAAA,IAC5C;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,SAAS,qBAAqB,KAAK,CAAC,EAAE,iBAAiB,EAAE;AAAA,IAChE,OAAO,SAAS,yBAAyB,KAAK,CAAC,EAAE,gCAAgC,EAAE;AAAA,EACrF;AACF;AAEA,eAAe,qBACb,QACA,kBACiB;AAEjB,QAAM,SAAS,IAAI,IAAI,gBAAgB,EAAE,SAAS,MAAM,CAAC;AACzD,UAAQ,KAAK,+BAA+B;AAC5C,QAAM,wBAAwB,MAAM,OAAO;AAAA,IACzC;AAAA,IACA,CAAC,MAAM;AAAA,EACT,GACM,SAAS,OAAO;AAAA,IACpB,sBAAsB,KAAK,CAAC,GAAG,sBAAsB;AAAA,IACrD;AAAA,EACF;AACA,iBAAQ,KAAK,uBAAuB,MAAM,EAAE,GACrC;AACT;AAEA,eAAsB,aAAa,UAA8B,CAAC,GAAuB;AACvF,QAAM,EAAE,iBAAiB,IAAI;AAE7B,MAAI,CAAC;AACH,UAAM,IAAI,MAAM,+CAA+C;AAGjE,MAAI;AAEF,WADe,MAAM,kBAAkB,gBAAgB;AAAA,EAEzD,SAAS,OAAO;AACd,kBAAQ,MAAM,6BAA6B,KAAK,GAC1C;AAAA,EACR;AACF;AAEA,eAAe,kBAAkB,kBAA8C;AAC7E,QAAM,iBAAgC;AAAA,IACpC;AAAA,IACA,yBAAyB;AAAA,IACzB,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,EACnB,GAEM,EAAE,SAAS,MAAM,IAAI,MAAM,OAAO,aAAa;AAerD,SAde,MAAM;AAAA,IACnB,YAAY;AACV,YAAM,YAAY,IAAI,UAAAD,QAAG,OAAO,cAAc;AAC9C,mBAAM,UAAU,QAAQ,GACjB;AAAA,IACT;AAAA,IACA;AAAA,MACE,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,YAAY;AAAA,IACd;AAAA,EACF;AAGF;",
5
+ "names": ["pg", "client"]
6
+ }
@@ -0,0 +1,35 @@
1
+ async function processInChunks(client, query, processor, options = {}) {
2
+ const { chunkSize = 1e3, onProgress } = options;
3
+ let offset = 0, hasMore = !0, totalProcessed = 0;
4
+ const countQuery = query.replace(/SELECT .+ FROM/, "SELECT COUNT(*) FROM").replace(/ORDER BY .+/, ""), countResult = await client.query(countQuery), totalCount = Number.parseInt(countResult.rows[0].count, 10);
5
+ for (; hasMore; ) {
6
+ const paginatedQuery = `${query} LIMIT ${chunkSize} OFFSET ${offset}`, result = await client.query(paginatedQuery);
7
+ if (result.rows.length === 0) {
8
+ hasMore = !1;
9
+ break;
10
+ }
11
+ await processor(result.rows), totalProcessed += result.rows.length, offset += chunkSize, onProgress && onProgress(totalProcessed, totalCount), result.rows.length < chunkSize && (hasMore = !1);
12
+ }
13
+ }
14
+ async function updateInChunks(client, tableName, selectQuery, transformer, options = {}) {
15
+ let totalUpdated = 0;
16
+ return await processInChunks(
17
+ client,
18
+ selectQuery,
19
+ async (rows) => {
20
+ for (const row of rows) {
21
+ const updates = await transformer(row);
22
+ if (updates && Object.keys(updates).length > 0) {
23
+ const setClause = Object.keys(updates).map((key, index) => `${key} = $${index + 2}`).join(", "), values = [row.id, ...Object.values(updates)];
24
+ await client.query(`UPDATE ${tableName} SET ${setClause} WHERE id = $1`, values), totalUpdated++;
25
+ }
26
+ }
27
+ },
28
+ options
29
+ ), totalUpdated;
30
+ }
31
+ export {
32
+ processInChunks,
33
+ updateInChunks
34
+ };
35
+ //# sourceMappingURL=chunkedQuery.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/chunkedQuery.ts"],
4
+ "mappings": "AAUA,eAAsB,gBACpB,QACA,OACA,WACA,UAA+B,CAAC,GACjB;AACf,QAAM,EAAE,YAAY,KAAM,WAAW,IAAI;AACzC,MAAI,SAAS,GACT,UAAU,IACV,iBAAiB;AAGrB,QAAM,aAAa,MAChB,QAAQ,kBAAkB,sBAAsB,EAChD,QAAQ,eAAe,EAAE,GACtB,cAAc,MAAM,OAAO,MAAM,UAAU,GAC3C,aAAa,OAAO,SAAS,YAAY,KAAK,CAAC,EAAE,OAAO,EAAE;AAEhE,SAAO,WAAS;AACd,UAAM,iBAAiB,GAAG,KAAK,UAAU,SAAS,WAAW,MAAM,IAC7D,SAAS,MAAM,OAAO,MAAS,cAAc;AAEnD,QAAI,OAAO,KAAK,WAAW,GAAG;AAC5B,gBAAU;AACV;AAAA,IACF;AAEA,UAAM,UAAU,OAAO,IAAI,GAE3B,kBAAkB,OAAO,KAAK,QAC9B,UAAU,WAEN,cACF,WAAW,gBAAgB,UAAU,GAInC,OAAO,KAAK,SAAS,cACvB,UAAU;AAAA,EAEd;AACF;AAKA,eAAsB,eACpB,QACA,WACA,aACA,aACA,UAA+B,CAAC,GACf;AACjB,MAAI,eAAe;AAEnB,eAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,OAAO,SAAS;AACd,iBAAW,OAAO,MAAM;AACtB,cAAM,UAAU,MAAM,YAAY,GAAG;AAErC,YAAI,WAAW,OAAO,KAAK,OAAO,EAAE,SAAS,GAAG;AAE9C,gBAAM,YAAY,OAAO,KAAK,OAAO,EAClC,IAAI,CAAC,KAAK,UAAU,GAAG,GAAG,OAAO,QAAQ,CAAC,EAAE,EAC5C,KAAK,IAAI,GAEN,SAAS,CAAC,IAAI,IAAI,GAAG,OAAO,OAAO,OAAO,CAAC;AAEjD,gBAAM,OAAO,MAAM,UAAU,SAAS,QAAQ,SAAS,kBAAkB,MAAM,GAE/E;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,EACF,GAEO;AACT;",
5
+ "names": []
6
+ }
@@ -0,0 +1,36 @@
1
+ async function processInChunks(client, query, processor, options = {}) {
2
+ const {
3
+ chunkSize = 1e3,
4
+ onProgress
5
+ } = options;
6
+ let offset = 0,
7
+ hasMore = !0,
8
+ totalProcessed = 0;
9
+ const countQuery = query.replace(/SELECT .+ FROM/, "SELECT COUNT(*) FROM").replace(/ORDER BY .+/, ""),
10
+ countResult = await client.query(countQuery),
11
+ totalCount = Number.parseInt(countResult.rows[0].count, 10);
12
+ for (; hasMore;) {
13
+ const paginatedQuery = `${query} LIMIT ${chunkSize} OFFSET ${offset}`,
14
+ result = await client.query(paginatedQuery);
15
+ if (result.rows.length === 0) {
16
+ hasMore = !1;
17
+ break;
18
+ }
19
+ await processor(result.rows), totalProcessed += result.rows.length, offset += chunkSize, onProgress && onProgress(totalProcessed, totalCount), result.rows.length < chunkSize && (hasMore = !1);
20
+ }
21
+ }
22
+ async function updateInChunks(client, tableName, selectQuery, transformer, options = {}) {
23
+ let totalUpdated = 0;
24
+ return await processInChunks(client, selectQuery, async rows => {
25
+ for (const row of rows) {
26
+ const updates = await transformer(row);
27
+ if (updates && Object.keys(updates).length > 0) {
28
+ const setClause = Object.keys(updates).map((key, index) => `${key} = $${index + 2}`).join(", "),
29
+ values = [row.id, ...Object.values(updates)];
30
+ await client.query(`UPDATE ${tableName} SET ${setClause} WHERE id = $1`, values), totalUpdated++;
31
+ }
32
+ }
33
+ }, options), totalUpdated;
34
+ }
35
+ export { processInChunks, updateInChunks };
36
+ //# sourceMappingURL=chunkedQuery.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["processInChunks","client","query","processor","options","chunkSize","onProgress","offset","hasMore","totalProcessed","countQuery","replace","countResult","totalCount","Number","parseInt","rows","count","paginatedQuery","result","length","updateInChunks","tableName","selectQuery","transformer","totalUpdated","row","updates","Object","keys","setClause","map","key","index","join","values","id"],"sources":["../../src/chunkedQuery.ts"],"sourcesContent":[null],"mappings":"AAUA,eAAsBA,gBACpBC,MAAA,EACAC,KAAA,EACAC,SAAA,EACAC,OAAA,GAA+B,CAAC,GACjB;EACf,MAAM;IAAEC,SAAA,GAAY;IAAMC;EAAW,IAAIF,OAAA;EACzC,IAAIG,MAAA,GAAS;IACTC,OAAA,GAAU;IACVC,cAAA,GAAiB;EAGrB,MAAMC,UAAA,GAAaR,KAAA,CAChBS,OAAA,CAAQ,kBAAkB,sBAAsB,EAChDA,OAAA,CAAQ,eAAe,EAAE;IACtBC,WAAA,GAAc,MAAMX,MAAA,CAAOC,KAAA,CAAMQ,UAAU;IAC3CG,UAAA,GAAaC,MAAA,CAAOC,QAAA,CAASH,WAAA,CAAYI,IAAA,CAAK,CAAC,EAAEC,KAAA,EAAO,EAAE;EAEhE,OAAOT,OAAA,GAAS;IACd,MAAMU,cAAA,GAAiB,GAAGhB,KAAK,UAAUG,SAAS,WAAWE,MAAM;MAC7DY,MAAA,GAAS,MAAMlB,MAAA,CAAOC,KAAA,CAASgB,cAAc;IAEnD,IAAIC,MAAA,CAAOH,IAAA,CAAKI,MAAA,KAAW,GAAG;MAC5BZ,OAAA,GAAU;MACV;IACF;IAEA,MAAML,SAAA,CAAUgB,MAAA,CAAOH,IAAI,GAE3BP,cAAA,IAAkBU,MAAA,CAAOH,IAAA,CAAKI,MAAA,EAC9Bb,MAAA,IAAUF,SAAA,EAENC,UAAA,IACFA,UAAA,CAAWG,cAAA,EAAgBI,UAAU,GAInCM,MAAA,CAAOH,IAAA,CAAKI,MAAA,GAASf,SAAA,KACvBG,OAAA,GAAU;EAEd;AACF;AAKA,eAAsBa,eACpBpB,MAAA,EACAqB,SAAA,EACAC,WAAA,EACAC,WAAA,EACApB,OAAA,GAA+B,CAAC,GACf;EACjB,IAAIqB,YAAA,GAAe;EAEnB,aAAMzB,eAAA,CACJC,MAAA,EACAsB,WAAA,EACA,MAAOP,IAAA,IAAS;IACd,WAAWU,GAAA,IAAOV,IAAA,EAAM;MACtB,MAAMW,OAAA,GAAU,MAAMH,WAAA,CAAYE,GAAG;MAErC,IAAIC,OAAA,IAAWC,MAAA,CAAOC,IAAA,CAAKF,OAAO,EAAEP,MAAA,GAAS,GAAG;QAE9C,MAAMU,SAAA,GAAYF,MAAA,CAAOC,IAAA,CAAKF,OAAO,EAClCI,GAAA,CAAI,CAACC,GAAA,EAAKC,KAAA,KAAU,GAAGD,GAAG,OAAOC,KAAA,GAAQ,CAAC,EAAE,EAC5CC,IAAA,CAAK,IAAI;UAENC,MAAA,GAAS,CAACT,GAAA,CAAIU,EAAA,EAAI,GAAGR,MAAA,CAAOO,MAAA,CAAOR,OAAO,CAAC;QAEjD,MAAM1B,MAAA,CAAOC,KAAA,CAAM,UAAUoB,SAAS,QAAQQ,SAAS,kBAAkBK,MAAM,GAE/EV,YAAA;MACF;IACF;EACF,GACArB,OACF,GAEOqB,YAAA;AACT","ignoreList":[]}
@@ -0,0 +1,13 @@
1
+ import { drizzle } from "drizzle-orm/node-postgres";
2
+ import { createPool } from "./createPool";
3
+ const createDb = (connectionString, schema) => {
4
+ const pool = createPool(connectionString);
5
+ return drizzle(pool, {
6
+ schema,
7
+ logger: !1
8
+ });
9
+ };
10
+ export {
11
+ createDb
12
+ };
13
+ //# sourceMappingURL=createDb.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/createDb.ts"],
4
+ "mappings": "AAAA,SAA8B,eAAe;AAE7C,SAAS,kBAAkB;AAEpB,MAAM,WAAW,CACtB,kBACA,WAC4B;AAC5B,QAAM,OAAO,WAAW,gBAAgB;AACxC,SAAO,QAAQ,MAAM;AAAA,IACnB;AAAA,IACA,QAAQ;AAAA,EACV,CAAC;AACH;",
5
+ "names": []
6
+ }
@@ -0,0 +1,11 @@
1
+ import { drizzle } from "drizzle-orm/node-postgres";
2
+ import { createPool } from "./createPool.mjs";
3
+ const createDb = (connectionString, schema) => {
4
+ const pool = createPool(connectionString);
5
+ return drizzle(pool, {
6
+ schema,
7
+ logger: !1
8
+ });
9
+ };
10
+ export { createDb };
11
+ //# sourceMappingURL=createDb.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["drizzle","createPool","createDb","connectionString","schema","pool","logger"],"sources":["../../src/createDb.ts"],"sourcesContent":[null],"mappings":"AAAA,SAA8BA,OAAA,QAAe;AAE7C,SAASC,UAAA,QAAkB;AAEpB,MAAMC,QAAA,GAAWA,CACtBC,gBAAA,EACAC,MAAA,KAC4B;EAC5B,MAAMC,IAAA,GAAOJ,UAAA,CAAWE,gBAAgB;EACxC,OAAOH,OAAA,CAAQK,IAAA,EAAM;IACnBD,MAAA;IACAE,MAAA,EAAQ;EACV,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,8 @@
1
+ import pg from "pg";
2
+ const createPool = (connectionString) => new pg.Pool({
3
+ connectionString
4
+ });
5
+ export {
6
+ createPool
7
+ };
8
+ //# sourceMappingURL=createPool.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/createPool.ts"],
4
+ "mappings": "AAAA,OAAO,QAAuB;AAEvB,MAAM,aAAa,CAAC,qBAClB,IAAI,GAAG,KAAK;AAAA,EACjB;AACF,CAAC;",
5
+ "names": []
6
+ }
@@ -0,0 +1,6 @@
1
+ import pg from "pg";
2
+ const createPool = connectionString => new pg.Pool({
3
+ connectionString
4
+ });
5
+ export { createPool };
6
+ //# sourceMappingURL=createPool.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["pg","createPool","connectionString","Pool"],"sources":["../../src/createPool.ts"],"sourcesContent":[null],"mappings":"AAAA,OAAOA,EAAA,MAAuB;AAEvB,MAAMC,UAAA,GAAcC,gBAAA,IAClB,IAAIF,EAAA,CAAGG,IAAA,CAAK;EACjBD;AACF,CAAC","ignoreList":[]}
@@ -0,0 +1,155 @@
1
+ import pg from "pg";
2
+ const cache = /* @__PURE__ */ new Map(), createPoolKey = (connectionString) => connectionString, getOrCreatePoolCache = (connectionString, config) => {
3
+ const key = createPoolKey(connectionString);
4
+ return cache.has(key) || cache.set(key, {
5
+ pool: new pg.Pool(config),
6
+ maxConnections: null,
7
+ reservedConnections: null,
8
+ openedConnections: null,
9
+ openedConnectionsLastUpdate: null
10
+ }), cache.get(key);
11
+ };
12
+ async function getDBClient(options = {}) {
13
+ const { pool, connectionString, retries = 8 } = options;
14
+ if (!pool && !connectionString)
15
+ throw new Error("Either pool or connectionString must be provided");
16
+ let client = null;
17
+ try {
18
+ return client = await tryToGetNewClientFromPool(pool, connectionString, retries), client;
19
+ } catch (error) {
20
+ throw console.error("Failed to get DB client:", error), error;
21
+ }
22
+ }
23
+ async function tryToGetNewClientFromPool(providedPool, connectionString, retries) {
24
+ const { default: retry } = await import("async-retry");
25
+ return await retry(
26
+ async () => {
27
+ if (providedPool) {
28
+ console.info("Connecting to provided pool...");
29
+ const client2 = await providedPool.connect();
30
+ return console.info("Connected to pool"), client2;
31
+ }
32
+ if (!connectionString)
33
+ throw new Error("No connection string provided");
34
+ const poolCache = getOrCreatePoolCache(connectionString, {
35
+ connectionString,
36
+ connectionTimeoutMillis: 5e3,
37
+ // idle_session_timeout set to 35s on server, client timeout at 30s
38
+ // fix via https://github.com/brianc/node-postgres/issues/2718#issuecomment-2094885323
39
+ idleTimeoutMillis: 3e4,
40
+ allowExitOnIdle: !0
41
+ });
42
+ console.info(`Connecting to pool ${connectionString}...`);
43
+ const client = await poolCache.pool.connect();
44
+ return console.info("Connected to pool"), client;
45
+ },
46
+ {
47
+ retries,
48
+ minTimeout: 300,
49
+ factor: 2,
50
+ maxTimeout: 8e3
51
+ }
52
+ );
53
+ }
54
+ async function queryDb(queryText, params, options = {}) {
55
+ let client = null;
56
+ try {
57
+ return client = await tryToGetNewClientFromPool(
58
+ options.pool,
59
+ options.connectionString,
60
+ options.retries || 8
61
+ ), await client.query(queryText, params);
62
+ } catch (error) {
63
+ throw console.error("Database query failed:", {
64
+ query: queryText,
65
+ error: error instanceof Error ? error.message : String(error)
66
+ }), error;
67
+ } finally {
68
+ if (client && options.connectionString)
69
+ if (await checkForTooManyConnections(
70
+ client,
71
+ options.connectionString
72
+ )) {
73
+ const poolCache = cache.get(createPoolKey(options.connectionString));
74
+ client.release(), await poolCache?.pool.end(), poolCache && cache.delete(createPoolKey(options.connectionString));
75
+ } else
76
+ client.release();
77
+ else client && client.release();
78
+ }
79
+ }
80
+ async function checkForTooManyConnections(client, connectionString) {
81
+ const poolCache = cache.get(createPoolKey(connectionString));
82
+ if (!poolCache) return !1;
83
+ const currentTime = Date.now(), openedConnectionsMaxAge = 1e4, maxConnectionsTolerance = 0.9;
84
+ if (poolCache.maxConnections === null || poolCache.reservedConnections === null) {
85
+ const [maxConnections, reservedConnections] = await getConnectionLimits(client);
86
+ console.info(
87
+ `Max connections: ${maxConnections}, Reserved connections: ${reservedConnections}`
88
+ ), poolCache.maxConnections = maxConnections, poolCache.reservedConnections = reservedConnections;
89
+ }
90
+ if (poolCache.openedConnections === null || poolCache.openedConnectionsLastUpdate === null || currentTime - poolCache.openedConnectionsLastUpdate > openedConnectionsMaxAge) {
91
+ const openedConnections = await getOpenedConnections(client, connectionString);
92
+ poolCache.openedConnections = openedConnections, poolCache.openedConnectionsLastUpdate = currentTime;
93
+ }
94
+ return poolCache.openedConnections > (poolCache.maxConnections - poolCache.reservedConnections) * maxConnectionsTolerance ? (console.warn(
95
+ `Too many connections detected: ${poolCache.openedConnections}/${poolCache.maxConnections - poolCache.reservedConnections}`
96
+ ), !0) : !1;
97
+ }
98
+ async function getConnectionLimits(client) {
99
+ console.info("Getting connection limits...");
100
+ const maxConnectionsResult = await client.query("SHOW max_connections"), reservedConnectionResult = await client.query(
101
+ "SHOW superuser_reserved_connections"
102
+ );
103
+ return [
104
+ Number.parseInt(maxConnectionsResult.rows[0].max_connections, 10),
105
+ Number.parseInt(reservedConnectionResult.rows[0].superuser_reserved_connections, 10)
106
+ ];
107
+ }
108
+ async function getOpenedConnections(client, connectionString) {
109
+ const dbName = new URL(connectionString).pathname.slice(1);
110
+ console.info("Getting opened connections...");
111
+ const openConnectionsResult = await client.query(
112
+ "SELECT numbackends as opened_connections FROM pg_stat_database WHERE datname = $1",
113
+ [dbName]
114
+ ), result = Number.parseInt(
115
+ openConnectionsResult.rows[0]?.opened_connections || 0,
116
+ 10
117
+ );
118
+ return console.info(`Opened connections: ${result}`), result;
119
+ }
120
+ async function getNewClient(options = {}) {
121
+ const { connectionString } = options;
122
+ if (!connectionString)
123
+ throw new Error("connectionString is required for getNewClient");
124
+ try {
125
+ return await tryToGetNewClient(connectionString);
126
+ } catch (error) {
127
+ throw console.error("Failed to get new client:", error), error;
128
+ }
129
+ }
130
+ async function tryToGetNewClient(connectionString) {
131
+ const configurations = {
132
+ connectionString,
133
+ connectionTimeoutMillis: 5e3,
134
+ idleTimeoutMillis: 3e4,
135
+ allowExitOnIdle: !0
136
+ }, { default: retry } = await import("async-retry");
137
+ return await retry(
138
+ async () => {
139
+ const newClient = new pg.Client(configurations);
140
+ return await newClient.connect(), newClient;
141
+ },
142
+ {
143
+ retries: 10,
144
+ minTimeout: 100,
145
+ factor: 2,
146
+ maxTimeout: 5e3
147
+ }
148
+ );
149
+ }
150
+ export {
151
+ getDBClient,
152
+ getNewClient,
153
+ queryDb
154
+ };
155
+ //# sourceMappingURL=getDBClient.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/getDBClient.ts"],
4
+ "mappings": "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",
5
+ "names": ["client"]
6
+ }
@@ -0,0 +1,136 @@
1
+ import pg from "pg";
2
+ const cache = /* @__PURE__ */new Map(),
3
+ createPoolKey = connectionString => connectionString,
4
+ getOrCreatePoolCache = (connectionString, config) => {
5
+ const key = createPoolKey(connectionString);
6
+ return cache.has(key) || cache.set(key, {
7
+ pool: new pg.Pool(config),
8
+ maxConnections: null,
9
+ reservedConnections: null,
10
+ openedConnections: null,
11
+ openedConnectionsLastUpdate: null
12
+ }), cache.get(key);
13
+ };
14
+ async function getDBClient(options = {}) {
15
+ const {
16
+ pool,
17
+ connectionString,
18
+ retries = 8
19
+ } = options;
20
+ if (!pool && !connectionString) throw new Error("Either pool or connectionString must be provided");
21
+ let client = null;
22
+ try {
23
+ return client = await tryToGetNewClientFromPool(pool, connectionString, retries), client;
24
+ } catch (error) {
25
+ throw console.error("Failed to get DB client:", error), error;
26
+ }
27
+ }
28
+ async function tryToGetNewClientFromPool(providedPool, connectionString, retries) {
29
+ const {
30
+ default: retry
31
+ } = await import("async-retry");
32
+ return await retry(async () => {
33
+ if (providedPool) {
34
+ console.info("Connecting to provided pool...");
35
+ const client2 = await providedPool.connect();
36
+ return console.info("Connected to pool"), client2;
37
+ }
38
+ if (!connectionString) throw new Error("No connection string provided");
39
+ const poolCache = getOrCreatePoolCache(connectionString, {
40
+ connectionString,
41
+ connectionTimeoutMillis: 5e3,
42
+ // idle_session_timeout set to 35s on server, client timeout at 30s
43
+ // fix via https://github.com/brianc/node-postgres/issues/2718#issuecomment-2094885323
44
+ idleTimeoutMillis: 3e4,
45
+ allowExitOnIdle: !0
46
+ });
47
+ console.info(`Connecting to pool ${connectionString}...`);
48
+ const client = await poolCache.pool.connect();
49
+ return console.info("Connected to pool"), client;
50
+ }, {
51
+ retries,
52
+ minTimeout: 300,
53
+ factor: 2,
54
+ maxTimeout: 8e3
55
+ });
56
+ }
57
+ async function queryDb(queryText, params, options = {}) {
58
+ let client = null;
59
+ try {
60
+ return client = await tryToGetNewClientFromPool(options.pool, options.connectionString, options.retries || 8), await client.query(queryText, params);
61
+ } catch (error) {
62
+ throw console.error("Database query failed:", {
63
+ query: queryText,
64
+ error: error instanceof Error ? error.message : String(error)
65
+ }), error;
66
+ } finally {
67
+ if (client && options.connectionString) {
68
+ if (await checkForTooManyConnections(client, options.connectionString)) {
69
+ const poolCache = cache.get(createPoolKey(options.connectionString));
70
+ client.release(), await poolCache?.pool.end(), poolCache && cache.delete(createPoolKey(options.connectionString));
71
+ } else client.release();
72
+ } else client && client.release();
73
+ }
74
+ }
75
+ async function checkForTooManyConnections(client, connectionString) {
76
+ const poolCache = cache.get(createPoolKey(connectionString));
77
+ if (!poolCache) return !1;
78
+ const currentTime = Date.now(),
79
+ openedConnectionsMaxAge = 1e4,
80
+ maxConnectionsTolerance = 0.9;
81
+ if (poolCache.maxConnections === null || poolCache.reservedConnections === null) {
82
+ const [maxConnections, reservedConnections] = await getConnectionLimits(client);
83
+ console.info(`Max connections: ${maxConnections}, Reserved connections: ${reservedConnections}`), poolCache.maxConnections = maxConnections, poolCache.reservedConnections = reservedConnections;
84
+ }
85
+ if (poolCache.openedConnections === null || poolCache.openedConnectionsLastUpdate === null || currentTime - poolCache.openedConnectionsLastUpdate > openedConnectionsMaxAge) {
86
+ const openedConnections = await getOpenedConnections(client, connectionString);
87
+ poolCache.openedConnections = openedConnections, poolCache.openedConnectionsLastUpdate = currentTime;
88
+ }
89
+ return poolCache.openedConnections > (poolCache.maxConnections - poolCache.reservedConnections) * maxConnectionsTolerance ? (console.warn(`Too many connections detected: ${poolCache.openedConnections}/${poolCache.maxConnections - poolCache.reservedConnections}`), !0) : !1;
90
+ }
91
+ async function getConnectionLimits(client) {
92
+ console.info("Getting connection limits...");
93
+ const maxConnectionsResult = await client.query("SHOW max_connections"),
94
+ reservedConnectionResult = await client.query("SHOW superuser_reserved_connections");
95
+ return [Number.parseInt(maxConnectionsResult.rows[0].max_connections, 10), Number.parseInt(reservedConnectionResult.rows[0].superuser_reserved_connections, 10)];
96
+ }
97
+ async function getOpenedConnections(client, connectionString) {
98
+ const dbName = new URL(connectionString).pathname.slice(1);
99
+ console.info("Getting opened connections...");
100
+ const openConnectionsResult = await client.query("SELECT numbackends as opened_connections FROM pg_stat_database WHERE datname = $1", [dbName]),
101
+ result = Number.parseInt(openConnectionsResult.rows[0]?.opened_connections || 0, 10);
102
+ return console.info(`Opened connections: ${result}`), result;
103
+ }
104
+ async function getNewClient(options = {}) {
105
+ const {
106
+ connectionString
107
+ } = options;
108
+ if (!connectionString) throw new Error("connectionString is required for getNewClient");
109
+ try {
110
+ return await tryToGetNewClient(connectionString);
111
+ } catch (error) {
112
+ throw console.error("Failed to get new client:", error), error;
113
+ }
114
+ }
115
+ async function tryToGetNewClient(connectionString) {
116
+ const configurations = {
117
+ connectionString,
118
+ connectionTimeoutMillis: 5e3,
119
+ idleTimeoutMillis: 3e4,
120
+ allowExitOnIdle: !0
121
+ },
122
+ {
123
+ default: retry
124
+ } = await import("async-retry");
125
+ return await retry(async () => {
126
+ const newClient = new pg.Client(configurations);
127
+ return await newClient.connect(), newClient;
128
+ }, {
129
+ retries: 10,
130
+ minTimeout: 100,
131
+ factor: 2,
132
+ maxTimeout: 5e3
133
+ });
134
+ }
135
+ export { getDBClient, getNewClient, queryDb };
136
+ //# sourceMappingURL=getDBClient.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["pg","cache","Map","createPoolKey","connectionString","getOrCreatePoolCache","config","key","has","set","pool","Pool","maxConnections","reservedConnections","openedConnections","openedConnectionsLastUpdate","get","getDBClient","options","retries","Error","client","tryToGetNewClientFromPool","error","console","providedPool","default","retry","info","client2","connect","poolCache","connectionTimeoutMillis","idleTimeoutMillis","allowExitOnIdle","minTimeout","factor","maxTimeout","queryDb","queryText","params","query","message","String","checkForTooManyConnections","release","end","delete","currentTime","Date","now","openedConnectionsMaxAge","maxConnectionsTolerance","getConnectionLimits","getOpenedConnections","warn","maxConnectionsResult","reservedConnectionResult","Number","parseInt","rows","max_connections","superuser_reserved_connections","dbName","URL","pathname","slice","openConnectionsResult","result","opened_connections","getNewClient","tryToGetNewClient","configurations","newClient","Client"],"sources":["../../src/getDBClient.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@take-out/postgres",
3
- "version": "0.0.98",
3
+ "version": "0.1.0",
4
4
  "sideEffects": false,
5
5
  "source": "src/index.ts",
6
6
  "main": "dist/cjs",
@@ -53,7 +53,7 @@
53
53
  }
54
54
  },
55
55
  "dependencies": {
56
- "@take-out/helpers": "0.0.98",
56
+ "@take-out/helpers": "0.1.0",
57
57
  "async-retry": "^1.3.3",
58
58
  "citty": "^0.1.6"
59
59
  },
@@ -0,0 +1,17 @@
1
+ import type { PoolClient, QueryResultRow } from 'pg';
2
+ interface ChunkedQueryOptions {
3
+ chunkSize?: number;
4
+ onProgress?: (processed: number, total: number) => void;
5
+ }
6
+ /**
7
+ * Process database records in chunks to avoid memory issues with large datasets
8
+ */
9
+ export declare function processInChunks<T extends QueryResultRow = QueryResultRow>(client: PoolClient, query: string, processor: (rows: T[]) => Promise<void>, options?: ChunkedQueryOptions): Promise<void>;
10
+ /**
11
+ * Update records in chunks with a transformer function
12
+ */
13
+ export declare function updateInChunks<T extends QueryResultRow & {
14
+ id: string;
15
+ }>(client: PoolClient, tableName: string, selectQuery: string, transformer: (row: T) => Promise<Partial<T> | null>, options?: ChunkedQueryOptions): Promise<number>;
16
+ export {};
17
+ //# sourceMappingURL=chunkedQuery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunkedQuery.d.ts","sourceRoot":"","sources":["../src/chunkedQuery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,IAAI,CAAA;AAEpD,UAAU,mBAAmB;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACxD;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,EAC7E,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,EACvC,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,IAAI,CAAC,CAoCf;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,CAAC,SAAS,cAAc,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAC5E,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EACnD,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,MAAM,CAAC,CA4BjB"}
@@ -0,0 +1,3 @@
1
+ import { type NodePgDatabase } from 'drizzle-orm/node-postgres';
2
+ export declare const createDb: <TSchema extends Record<string, unknown>>(connectionString: string, schema: TSchema) => NodePgDatabase<TSchema>;
3
+ //# sourceMappingURL=createDb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createDb.d.ts","sourceRoot":"","sources":["../src/createDb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAW,MAAM,2BAA2B,CAAA;AAIxE,eAAO,MAAM,QAAQ,GAAI,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,kBAAkB,MAAM,EACxB,QAAQ,OAAO,KACd,cAAc,CAAC,OAAO,CAMxB,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { type Pool } from 'pg';
2
+ export declare const createPool: (connectionString: string) => Pool;
3
+ //# sourceMappingURL=createPool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createPool.d.ts","sourceRoot":"","sources":["../src/createPool.ts"],"names":[],"mappings":"AAAA,OAAW,EAAE,KAAK,IAAI,EAAE,MAAM,IAAI,CAAA;AAElC,eAAO,MAAM,UAAU,GAAI,kBAAkB,MAAM,KAAG,IAIrD,CAAA"}
@@ -0,0 +1,11 @@
1
+ import pg, { type Pool, type PoolClient } from 'pg';
2
+ export type GetDBClientOptions = {
3
+ pool?: Pool;
4
+ connectionString?: string;
5
+ retries?: number;
6
+ onRetry?: (error: Error, attempt: number) => void;
7
+ };
8
+ export declare function getDBClient(options?: GetDBClientOptions): Promise<PoolClient>;
9
+ export declare function queryDb(queryText: string, params?: any[], options?: GetDBClientOptions): Promise<pg.QueryResult<any>>;
10
+ export declare function getNewClient(options?: GetDBClientOptions): Promise<pg.Client>;
11
+ //# sourceMappingURL=getDBClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getDBClient.d.ts","sourceRoot":"","sources":["../src/getDBClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,KAAK,IAAI,EAAE,KAAK,UAAU,EAAE,MAAM,IAAI,CAAA;AAKnD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAClD,CAAA;AA+BD,wBAAsB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,UAAU,CAAC,CAgBvF;AAgDD,wBAAsB,OAAO,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,GAAG,EAAE,EACd,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAqC9B;AA6ED,wBAAsB,YAAY,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAcvF"}