@prairielearn/postgres 2.0.0 → 2.0.2
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.
- package/CHANGELOG.md +12 -0
- package/README.md +1 -0
- package/dist/default-pool.d.ts +2 -2
- package/dist/default-pool.test.js +2 -1
- package/dist/default-pool.test.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/pool.d.ts +6 -2
- package/dist/pool.js +25 -12
- package/dist/pool.js.map +1 -1
- package/dist/pool.test.js +25 -6
- package/dist/pool.test.js.map +1 -1
- package/dist/test-utils.js +1 -0
- package/dist/test-utils.js.map +1 -1
- package/package.json +29 -16
- package/src/default-pool.test.ts +3 -1
- package/src/index.ts +1 -1
- package/src/pool.test.ts +34 -10
- package/src/pool.ts +32 -12
- package/src/test-utils.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @prairielearn/postgres
|
|
2
2
|
|
|
3
|
+
## 2.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- fd8f6e6: Use processed SQL when throwing errors with a `position` property
|
|
8
|
+
|
|
9
|
+
## 2.0.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 901fce8: Upgrade all JavaScript dependencies
|
|
14
|
+
|
|
3
15
|
## 2.0.0
|
|
4
16
|
|
|
5
17
|
### Major Changes
|
package/README.md
CHANGED
package/dist/default-pool.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { PostgresPool, type CursorIterator, type QueryParams } from './pool.js';
|
|
3
3
|
declare const defaultPool: PostgresPool;
|
|
4
4
|
export { defaultPool, type CursorIterator, type QueryParams };
|
|
5
|
-
export declare const init: (arg1: import("
|
|
6
|
-
export declare const initAsync: (pgConfig: import("
|
|
5
|
+
export declare const init: (arg1: import("./pool.js").PostgresPoolConfig, arg2: (error: Error, client: import("pg").PoolClient) => void, callback: (err: NodeJS.ErrnoException) => void) => void;
|
|
6
|
+
export declare const initAsync: (pgConfig: import("./pool.js").PostgresPoolConfig, idleErrorHandler: (error: Error, client: import("pg").PoolClient) => void) => Promise<void>;
|
|
7
7
|
export declare const close: (callback: (err: NodeJS.ErrnoException) => void) => void;
|
|
8
8
|
export declare const closeAsync: () => Promise<void>;
|
|
9
9
|
export declare const getClientAsync: () => Promise<import("pg").PoolClient>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { assert } from 'chai';
|
|
2
|
-
import { PostgresPool } from './pool.js';
|
|
3
2
|
import * as pgPool from './default-pool.js';
|
|
3
|
+
import { PostgresPool } from './pool.js';
|
|
4
4
|
/**
|
|
5
5
|
* Properties on {@link PostgresPool} that should not be available on the default
|
|
6
6
|
* pool's exports.
|
|
@@ -13,6 +13,7 @@ const HIDDEN_PROPERTIES = new Set([
|
|
|
13
13
|
'searchSchema',
|
|
14
14
|
'_queryCount',
|
|
15
15
|
'queryValidatedCursorInternal',
|
|
16
|
+
'errorOnUnusedParameters',
|
|
16
17
|
// Getters
|
|
17
18
|
'totalCount',
|
|
18
19
|
'idleCount',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-pool.test.js","sourceRoot":"","sources":["../src/default-pool.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"default-pool.test.js","sourceRoot":"","sources":["../src/default-pool.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAE9B,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC;;;GAGG;AACH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,aAAa;IACb,kBAAkB;IAClB,MAAM;IACN,WAAW;IACX,cAAc;IACd,aAAa;IACb,8BAA8B;IAC9B,yBAAyB;IACzB,UAAU;IACV,YAAY;IACZ,WAAW;IACX,cAAc;IACd,YAAY;CACb,CAAC,CAAC;AAEH,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACrB,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;QAEhC,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC;aAC7B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;aACxC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YAChB,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CAAE,MAAc,CAAC,IAAI,CAAC,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEL,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;aACpD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;aACxC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YAChB,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CAAE,MAAc,CAAC,IAAI,CAAC,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;QAEhC,MAAM,eAAe,GAAG;YACtB,GAAG,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC;YACnC,GAAG,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YAC1D,cAAc;SACf,CAAC;QAEF,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YAChD,MAAM,CAAC,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { assert } from 'chai';\n\nimport * as pgPool from './default-pool.js';\nimport { PostgresPool } from './pool.js';\n\n/**\n * Properties on {@link PostgresPool} that should not be available on the default\n * pool's exports.\n */\nconst HIDDEN_PROPERTIES = new Set([\n 'constructor',\n // Private members\n 'pool',\n 'alsClient',\n 'searchSchema',\n '_queryCount',\n 'queryValidatedCursorInternal',\n 'errorOnUnusedParameters',\n // Getters\n 'totalCount',\n 'idleCount',\n 'waitingCount',\n 'queryCount',\n]);\n\ndescribe('sqldb', () => {\n it('exports the full PostgresPool interface', () => {\n const pool = new PostgresPool();\n\n Object.getOwnPropertyNames(pool)\n .filter((n) => !HIDDEN_PROPERTIES.has(n))\n .forEach((prop) => {\n assert.property(pgPool, prop);\n assert.ok((pgPool as any)[prop]);\n });\n\n Object.getOwnPropertyNames(Object.getPrototypeOf(pool))\n .filter((n) => !HIDDEN_PROPERTIES.has(n))\n .forEach((prop) => {\n assert.property(pgPool, prop);\n assert.ok((pgPool as any)[prop]);\n });\n });\n\n it('should not have extra properties', () => {\n const pool = new PostgresPool();\n\n const knownProperties = [\n ...Object.getOwnPropertyNames(pool),\n ...Object.getOwnPropertyNames(Object.getPrototypeOf(pool)),\n 'PostgresPool',\n ];\n\n Object.getOwnPropertyNames(pool).forEach((prop) => {\n assert.include(knownProperties, prop);\n });\n });\n});\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { type PoolClient } from 'pg';
|
|
2
2
|
export { loadSql, loadSqlEquiv } from './loader.js';
|
|
3
|
-
export { PostgresPool } from './pool.js';
|
|
3
|
+
export { PostgresPool, PostgresPoolConfig } from './pool.js';
|
|
4
4
|
export * from './default-pool.js';
|
|
5
5
|
export { makePostgresTestUtils, type PostgresTestUtils, type PostgresTestUtilsOptions, } from './test-utils.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,YAAY,EAAsB,MAAM,WAAW,CAAC;AAE7D,cAAc,mBAAmB,CAAC;AAElC,OAAO,EACL,qBAAqB,GAGtB,MAAM,iBAAiB,CAAC","sourcesContent":["export { type PoolClient } from 'pg';\n\nexport { loadSql, loadSqlEquiv } from './loader.js';\nexport { PostgresPool, PostgresPoolConfig } from './pool.js';\n\nexport * from './default-pool.js';\n\nexport {\n makePostgresTestUtils,\n type PostgresTestUtils,\n type PostgresTestUtilsOptions,\n} from './test-utils.js';\n"]}
|
package/dist/pool.d.ts
CHANGED
|
@@ -7,6 +7,9 @@ export interface CursorIterator<T> {
|
|
|
7
7
|
iterate: (batchSize: number) => AsyncGenerator<T[]>;
|
|
8
8
|
stream: (batchSize: number) => NodeJS.ReadWriteStream;
|
|
9
9
|
}
|
|
10
|
+
export interface PostgresPoolConfig extends pg.PoolConfig {
|
|
11
|
+
errorOnUnusedParameters?: boolean;
|
|
12
|
+
}
|
|
10
13
|
export declare class PostgresError extends Error {
|
|
11
14
|
data: Record<string, any>;
|
|
12
15
|
constructor(message: string, data: Record<string, any>);
|
|
@@ -24,14 +27,15 @@ export declare class PostgresPool {
|
|
|
24
27
|
private searchSchema;
|
|
25
28
|
/** Tracks the total number of queries executed by this pool. */
|
|
26
29
|
private _queryCount;
|
|
30
|
+
private errorOnUnusedParameters;
|
|
27
31
|
/**
|
|
28
32
|
* Creates a new connection pool and attempts to connect to the database.
|
|
29
33
|
*/
|
|
30
|
-
initAsync(pgConfig:
|
|
34
|
+
initAsync(pgConfig: PostgresPoolConfig, idleErrorHandler: (error: Error, client: pg.PoolClient) => void): Promise<void>;
|
|
31
35
|
/**
|
|
32
36
|
* Creates a new connection pool and attempts to connect to the database.
|
|
33
37
|
*/
|
|
34
|
-
init: (arg1:
|
|
38
|
+
init: (arg1: PostgresPoolConfig, arg2: (error: Error, client: pg.PoolClient) => void, callback: (err: NodeJS.ErrnoException) => void) => void;
|
|
35
39
|
/**
|
|
36
40
|
* Closes the connection pool.
|
|
37
41
|
*/
|
package/dist/pool.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { Readable, Transform } from 'node:stream';
|
|
3
|
+
import { callbackify } from 'node:util';
|
|
4
|
+
import debugfn from 'debug';
|
|
1
5
|
import _ from 'lodash';
|
|
6
|
+
import multipipe from 'multipipe';
|
|
2
7
|
import pg from 'pg';
|
|
3
8
|
import Cursor from 'pg-cursor';
|
|
4
|
-
import
|
|
5
|
-
import { callbackify } from 'node:util';
|
|
6
|
-
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
9
|
+
import { DatabaseError } from 'pg-protocol';
|
|
7
10
|
import { z } from 'zod';
|
|
8
|
-
import { Readable, Transform } from 'node:stream';
|
|
9
|
-
import multipipe from 'multipipe';
|
|
10
11
|
const debug = debugfn('@prairielearn/postgres');
|
|
11
12
|
const lastQueryMap = new WeakMap();
|
|
12
13
|
const searchSchemaMap = new WeakMap();
|
|
@@ -54,7 +55,7 @@ function debugParams(params) {
|
|
|
54
55
|
* Given an SQL string and params, creates an array of params and an SQL string
|
|
55
56
|
* with any named dollar-sign placeholders replaced with parameters.
|
|
56
57
|
*/
|
|
57
|
-
function paramsToArray(sql, params) {
|
|
58
|
+
function paramsToArray(sql, params, errorOnUnusedParameters) {
|
|
58
59
|
if (typeof sql !== 'string')
|
|
59
60
|
throw new Error('SQL must be a string');
|
|
60
61
|
if (Array.isArray(params)) {
|
|
@@ -74,10 +75,10 @@ function paramsToArray(sql, params) {
|
|
|
74
75
|
let paramsArray = [];
|
|
75
76
|
while ((result = re.exec(remainingSql)) !== null) {
|
|
76
77
|
const v = result[1];
|
|
77
|
-
if (!
|
|
78
|
-
if (!
|
|
78
|
+
if (!(v in map)) {
|
|
79
|
+
if (!(v in params))
|
|
79
80
|
throw new Error(`Missing parameter: ${v}`);
|
|
80
|
-
if (
|
|
81
|
+
if (Array.isArray(params[v])) {
|
|
81
82
|
map[v] =
|
|
82
83
|
'ARRAY[' +
|
|
83
84
|
_.map(_.range(nParams + 1, nParams + params[v].length + 1), function (n) {
|
|
@@ -98,6 +99,12 @@ function paramsToArray(sql, params) {
|
|
|
98
99
|
}
|
|
99
100
|
processedSql += remainingSql;
|
|
100
101
|
remainingSql = '';
|
|
102
|
+
if (errorOnUnusedParameters) {
|
|
103
|
+
const difference = _.difference(Object.keys(params), Object.keys(map));
|
|
104
|
+
if (difference.length) {
|
|
105
|
+
throw new Error(`Unused parameters in SQL query: ${JSON.stringify(difference)}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
101
108
|
return { processedSql, paramsArray };
|
|
102
109
|
}
|
|
103
110
|
/**
|
|
@@ -118,9 +125,13 @@ function enhanceError(err, sql, params) {
|
|
|
118
125
|
// `message` is a non-enumerable property, so we need to copy it manually to
|
|
119
126
|
// the error object.
|
|
120
127
|
sqlError.message = err.message;
|
|
128
|
+
const errorHasPosition = err instanceof DatabaseError && err.position != null;
|
|
121
129
|
return addDataToError(err, {
|
|
122
130
|
sqlError,
|
|
123
|
-
|
|
131
|
+
// If the error has a `position` field, we need to use the processed source
|
|
132
|
+
// (where e.g. `$foobar` has been replaced with `$1`) so that the position
|
|
133
|
+
// is accurate.
|
|
134
|
+
sql: errorHasPosition ? paramsToArray(sql, params, false).processedSql : sql,
|
|
124
135
|
sqlParams: params,
|
|
125
136
|
});
|
|
126
137
|
}
|
|
@@ -137,10 +148,12 @@ export class PostgresPool {
|
|
|
137
148
|
searchSchema = null;
|
|
138
149
|
/** Tracks the total number of queries executed by this pool. */
|
|
139
150
|
_queryCount = 0;
|
|
151
|
+
errorOnUnusedParameters = false;
|
|
140
152
|
/**
|
|
141
153
|
* Creates a new connection pool and attempts to connect to the database.
|
|
142
154
|
*/
|
|
143
155
|
async initAsync(pgConfig, idleErrorHandler) {
|
|
156
|
+
this.errorOnUnusedParameters = pgConfig.errorOnUnusedParameters ?? false;
|
|
144
157
|
this.pool = new pg.Pool(pgConfig);
|
|
145
158
|
this.pool.on('error', function (err, client) {
|
|
146
159
|
const lastQuery = lastQueryMap.get(client);
|
|
@@ -259,7 +272,7 @@ export class PostgresPool {
|
|
|
259
272
|
this._queryCount += 1;
|
|
260
273
|
debug('queryWithClient()', 'sql:', debugString(sql));
|
|
261
274
|
debug('queryWithClient()', 'params:', debugParams(params));
|
|
262
|
-
const { processedSql, paramsArray } = paramsToArray(sql, params);
|
|
275
|
+
const { processedSql, paramsArray } = paramsToArray(sql, params, this.errorOnUnusedParameters);
|
|
263
276
|
try {
|
|
264
277
|
lastQueryMap.set(client, processedSql);
|
|
265
278
|
const result = await client.query(processedSql, paramsArray);
|
|
@@ -819,7 +832,7 @@ export class PostgresPool {
|
|
|
819
832
|
this._queryCount += 1;
|
|
820
833
|
debug('queryCursorWithClient()', 'sql:', debugString(sql));
|
|
821
834
|
debug('queryCursorWithClient()', 'params:', debugParams(params));
|
|
822
|
-
const { processedSql, paramsArray } = paramsToArray(sql, params);
|
|
835
|
+
const { processedSql, paramsArray } = paramsToArray(sql, params, this.errorOnUnusedParameters);
|
|
823
836
|
lastQueryMap.set(client, processedSql);
|
|
824
837
|
return client.query(new Cursor(processedSql, paramsArray));
|
|
825
838
|
}
|
package/dist/pool.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"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","sourcesContent":["import _ from 'lodash';\nimport pg, { QueryResult } from 'pg';\nimport Cursor from 'pg-cursor';\nimport debugfn from 'debug';\nimport { callbackify } from 'node:util';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { z } from 'zod';\nimport { Readable, Transform } from 'node:stream';\nimport multipipe from 'multipipe';\n\nexport type QueryParams = Record<string, any> | any[];\n\nexport interface CursorIterator<T> {\n iterate: (batchSize: number) => AsyncGenerator<T[]>;\n stream: (batchSize: number) => NodeJS.ReadWriteStream;\n}\n\nconst debug = debugfn('@prairielearn/postgres');\nconst lastQueryMap = new WeakMap<pg.PoolClient, string>();\nconst searchSchemaMap = new WeakMap<pg.PoolClient, string>();\n\nfunction addDataToError(err: Error, data: Record<string, any>): Error {\n (err as any).data = {\n ...((err as any).data ?? {}),\n ...data,\n };\n return err;\n}\n\nexport class PostgresError extends Error {\n public data: Record<string, any>;\n\n constructor(message: string, data: Record<string, any>) {\n super(message);\n this.data = data;\n this.name = 'PostgresError';\n }\n}\n\n/**\n * Formats a string for debugging.\n */\nfunction debugString(s: string): string {\n if (!_.isString(s)) return 'NOT A STRING';\n s = s.replace(/\\n/g, '\\\\n');\n if (s.length > 78) s = s.substring(0, 75) + '...';\n s = '\"' + s + '\"';\n return s;\n}\n\n/**\n * Formats a set of params for debugging.\n */\nfunction debugParams(params: QueryParams): string {\n let s;\n try {\n s = JSON.stringify(params);\n } catch (err) {\n s = 'CANNOT JSON STRINGIFY';\n }\n return debugString(s);\n}\n\n/**\n * Given an SQL string and params, creates an array of params and an SQL string\n * with any named dollar-sign placeholders replaced with parameters.\n */\nfunction paramsToArray(\n sql: string,\n params: QueryParams,\n): { processedSql: string; paramsArray: any } {\n if (typeof sql !== 'string') throw new Error('SQL must be a string');\n if (Array.isArray(params)) {\n return {\n processedSql: sql,\n paramsArray: params,\n };\n }\n if (!_.isObjectLike(params)) throw new Error('params must be array or object');\n\n const re = /\\$([-_a-zA-Z0-9]+)/;\n let result;\n let processedSql = '';\n let remainingSql = sql;\n let nParams = 0;\n const map: Record<string, string> = {};\n let paramsArray: any[] = [];\n while ((result = re.exec(remainingSql)) !== null) {\n const v = result[1];\n if (!_.has(map, v)) {\n if (!_.has(params, v)) throw new Error(`Missing parameter: ${v}`);\n if (_.isArray(params[v])) {\n map[v] =\n 'ARRAY[' +\n _.map(_.range(nParams + 1, nParams + params[v].length + 1), function (n) {\n return '$' + n;\n }).join(',') +\n ']';\n nParams += params[v].length;\n paramsArray = paramsArray.concat(params[v]);\n } else {\n nParams++;\n map[v] = '$' + nParams;\n paramsArray.push(params[v]);\n }\n }\n processedSql += remainingSql.substring(0, result.index) + map[v];\n remainingSql = remainingSql.substring(result.index + result[0].length);\n }\n processedSql += remainingSql;\n remainingSql = '';\n return { processedSql, paramsArray };\n}\n\n/**\n * Escapes the given identifier for use in an SQL query. Useful for preventing\n * SQL injection.\n */\nfunction escapeIdentifier(identifier: string): string {\n // Note that as of 2021-06-29 escapeIdentifier() is undocumented. See:\n // https://github.com/brianc/node-postgres/pull/396\n // https://github.com/brianc/node-postgres/issues/1978\n // https://www.postgresql.org/docs/12/sql-syntax-lexical.html\n return pg.Client.prototype.escapeIdentifier(identifier);\n}\n\nfunction enhanceError(err: Error, sql: string, params: QueryParams): Error {\n // Copy the error so we don't end up with a circular reference in the\n // final error.\n const sqlError = { ...err };\n\n // `message` is a non-enumerable property, so we need to copy it manually to\n // the error object.\n sqlError.message = err.message;\n\n return addDataToError(err, {\n sqlError,\n sql,\n sqlParams: params,\n });\n}\n\nexport class PostgresPool {\n /** The pool from which clients will be acquired. */\n private pool: pg.Pool | null = null;\n /**\n * We use this to propagate the client associated with the current transaction\n * to any nested queries. In the past, we had some nasty bugs associated with\n * the fact that we tried to acquire new clients inside of transactions, which\n * ultimately lead to a deadlock.\n */\n private alsClient = new AsyncLocalStorage<pg.PoolClient>();\n private searchSchema: string | null = null;\n /** Tracks the total number of queries executed by this pool. */\n private _queryCount = 0;\n\n /**\n * Creates a new connection pool and attempts to connect to the database.\n */\n async initAsync(\n pgConfig: pg.PoolConfig,\n idleErrorHandler: (error: Error, client: pg.PoolClient) => void,\n ): Promise<void> {\n this.pool = new pg.Pool(pgConfig);\n this.pool.on('error', function (err, client) {\n const lastQuery = lastQueryMap.get(client);\n idleErrorHandler(addDataToError(err, { lastQuery }), client);\n });\n this.pool.on('connect', (client) => {\n client.on('error', (err) => {\n const lastQuery = lastQueryMap.get(client);\n idleErrorHandler(addDataToError(err, { lastQuery }), client);\n });\n });\n this.pool.on('remove', (client) => {\n // This shouldn't be necessary, as `pg` currently allows clients to be\n // garbage collected after they're removed. However, if `pg` someday\n // starts reusing client objects across difference connections, this\n // will ensure that we re-set the search path when the client reconnects.\n searchSchemaMap.delete(client);\n });\n\n // Attempt to connect to the database so that we can fail quickly if\n // something isn't configured correctly.\n let retryCount = 0;\n const retryTimeouts = [500, 1000, 2000, 5000, 10000];\n while (retryCount <= retryTimeouts.length) {\n try {\n const client = await this.pool.connect();\n client.release();\n return;\n } catch (err: any) {\n if (retryCount === retryTimeouts.length) {\n throw new Error(\n `Could not connect to Postgres after ${retryTimeouts.length} attempts: ${err.message}`,\n );\n }\n\n const timeout = retryTimeouts[retryCount];\n retryCount++;\n await new Promise((resolve) => setTimeout(resolve, timeout));\n }\n }\n }\n\n /**\n * Creates a new connection pool and attempts to connect to the database.\n */\n init = callbackify(this.initAsync);\n\n /**\n * Closes the connection pool.\n */\n async closeAsync(): Promise<void> {\n if (!this.pool) return;\n await this.pool.end();\n this.pool = null;\n }\n\n /**\n * Closes the connection pool.\n */\n close = callbackify(this.closeAsync);\n\n /**\n * Gets a new client from the connection pool. If `err` is not null\n * then `client` and `done` are undefined. If `err` is null then\n * `client` is valid and can be used. The caller MUST call `done()` to\n * release the client, whether or not errors occurred while using\n * `client`. The client can call `done(truthy_value)` to force\n * destruction of the client, but this should not be used except in\n * unusual circumstances.\n */\n async getClientAsync(): Promise<pg.PoolClient> {\n if (!this.pool) {\n throw new Error('Connection pool is not open');\n }\n\n // If we're inside a transaction, we'll reuse the same client to avoid a\n // potential deadlock.\n const client = this.alsClient.getStore() ?? (await this.pool.connect());\n\n // If we're configured to use a particular schema, we'll store whether or\n // not the search path has already been configured for this particular\n // client. If we acquire a client and it's already had its search path\n // set, we can avoid setting it again since the search path will persist\n // for the life of the client.\n //\n // We do this check for each call to `getClient` instead of on\n // `pool.connect` so that we don't have to be really careful about\n // destroying old clients that were created before `setSearchSchema` was\n // called. Instead, we'll just check if the search path matches the\n // currently-desired schema, and if it's a mismatch (or doesn't exist\n // at all), we re-set it for the current client.\n //\n // Note that this accidentally supports changing the search_path on the fly,\n // although that's not something we currently do (or would be likely to do).\n // It does NOT support clearing the existing search schema - e.g.,\n // `setSearchSchema(null)` would not work as you expect. This is fine, as\n // that's not something we ever do in practice.\n const clientSearchSchema = searchSchemaMap.get(client);\n if (this.searchSchema != null && clientSearchSchema !== this.searchSchema) {\n const setSearchPathSql = `SET search_path TO ${escapeIdentifier(this.searchSchema)},public`;\n try {\n await this.queryWithClientAsync(client, setSearchPathSql, {});\n } catch (err) {\n client.release();\n throw err;\n }\n searchSchemaMap.set(client, this.searchSchema);\n }\n\n return client;\n }\n\n /**\n * Gets a new client from the connection pool.\n */\n getClient(callback: (error: Error | null, client?: pg.PoolClient, done?: () => void) => void) {\n this.getClientAsync()\n .then((client) => callback(null, client, client.release))\n .catch((err) => callback(err));\n }\n\n /**\n * Performs a query with the given client.\n */\n async queryWithClientAsync(\n client: pg.PoolClient,\n sql: string,\n params: QueryParams,\n ): Promise<pg.QueryResult> {\n this._queryCount += 1;\n debug('queryWithClient()', 'sql:', debugString(sql));\n debug('queryWithClient()', 'params:', debugParams(params));\n const { processedSql, paramsArray } = paramsToArray(sql, params);\n try {\n lastQueryMap.set(client, processedSql);\n const result = await client.query(processedSql, paramsArray);\n debug('queryWithClient() success', 'rowCount:', result.rowCount);\n return result;\n } catch (err: any) {\n throw enhanceError(err, sql, params);\n }\n }\n\n /**\n * Performs a query with the given client.\n */\n queryWithClient = callbackify(this.queryWithClientAsync);\n\n /**\n * Performs a query with the given client. Errors if the query returns more\n * than one row.\n */\n async queryWithClientOneRowAsync(\n client: pg.PoolClient,\n sql: string,\n params: QueryParams,\n ): Promise<pg.QueryResult> {\n debug('queryWithClientOneRow()', 'sql:', debugString(sql));\n debug('queryWithClientOneRow()', 'params:', debugParams(params));\n const result = await this.queryWithClientAsync(client, sql, params);\n if (result.rowCount !== 1) {\n throw new PostgresError(`Incorrect rowCount: ${result.rowCount}`, {\n sql,\n sqlParams: params,\n result,\n });\n }\n debug('queryWithClientOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Performs a query with the given client. Errors if the query returns more\n * than one row.\n */\n queryWithClientOneRow = callbackify(this.queryWithClientOneRowAsync);\n\n /**\n * Performs a query with the given client. Errors if the query returns more\n * than one row.\n */\n async queryWithClientZeroOrOneRowAsync(\n client: pg.PoolClient,\n sql: string,\n params: QueryParams,\n ): Promise<QueryResult> {\n debug('queryWithClientZeroOrOneRow()', 'sql:', debugString(sql));\n debug('queryWithClientZeroOrOneRow()', 'params:', debugParams(params));\n const result = await this.queryWithClientAsync(client, sql, params);\n if (result.rowCount == null || result.rowCount > 1) {\n throw new PostgresError(`Incorrect rowCount: ${result.rowCount}`, {\n sql,\n sqlParams: params,\n result,\n });\n }\n debug('queryWithClientZeroOrOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Performs a query with the given client. Errors if the query returns more\n * than one row.\n */\n queryWithClientZeroOrOneRow = callbackify(this.queryWithClientZeroOrOneRowAsync);\n\n /**\n * Rolls back the current transaction for the given client.\n */\n async rollbackWithClientAsync(client: pg.PoolClient) {\n debug('rollbackWithClient()');\n // From https://node-postgres.com/features/transactions\n try {\n await client.query('ROLLBACK');\n // Only release the client if we weren't already inside a transaction.\n if (this.alsClient.getStore() === undefined) {\n client.release();\n }\n } catch (err: any) {\n // If there was a problem rolling back the query, something is\n // seriously messed up. Return the error to the release() function to\n // close & remove this client from the pool. If you leave a client in\n // the pool with an unaborted transaction, weird and hard to diagnose\n // problems might happen.\n client.release(err);\n }\n }\n\n /**\n * Rolls back the current transaction for the given client.\n */\n rollbackWithClient(\n client: pg.PoolClient,\n _done: (release?: any) => void,\n callback: (err: Error | null) => void,\n ) {\n // Note that we can't use `util.callbackify` here because this function\n // has an additional unused `done` parameter for backwards compatibility.\n this.rollbackWithClientAsync(client)\n .then(() => callback(null))\n .catch((err) => callback(err));\n }\n\n /**\n * Begins a new transaction.\n */\n async beginTransactionAsync(): Promise<pg.PoolClient> {\n debug('beginTransaction()');\n const client = await this.getClientAsync();\n try {\n await this.queryWithClientAsync(client, 'START TRANSACTION;', {});\n return client;\n } catch (err) {\n await this.rollbackWithClientAsync(client);\n throw err;\n }\n }\n\n /**\n * Commits the transaction if err is null, otherwise rollbacks the transaction.\n * Also releases the client.\n */\n async endTransactionAsync(client: pg.PoolClient, err: Error | null | undefined) {\n debug('endTransaction()');\n if (err) {\n try {\n await this.rollbackWithClientAsync(client);\n } catch (rollbackErr: any) {\n throw addDataToError(rollbackErr, { prevErr: err, rollback: 'fail' });\n }\n\n // Even though we successfully rolled back the transaction, there was\n // still an error in the first place that necessitated a rollback. Re-throw\n // that error here so that everything downstream of here will know about it.\n throw addDataToError(err, { rollback: 'success' });\n } else {\n try {\n await this.queryWithClientAsync(client, 'COMMIT', {});\n } finally {\n // Only release the client if we aren't nested inside another transaction.\n if (this.alsClient.getStore() === undefined) {\n client.release();\n }\n }\n }\n }\n\n /**\n * Commits the transaction if err is null, otherwise rollbacks the transaction.\n * Also releases the client.\n */\n endTransaction(\n client: pg.PoolClient,\n _done: (rollback?: any) => void,\n err: Error | null | undefined,\n callback: (error: Error | null) => void,\n ): void {\n this.endTransactionAsync(client, err)\n .then(() => callback(null))\n .catch((error) => callback(error));\n }\n\n /**\n * Runs the specified function inside of a transaction. The function will\n * receive a database client as an argument, but it can also make queries\n * as usual, and the correct client will be used automatically.\n *\n * The transaction will be rolled back if the function throws an error, and\n * will be committed otherwise.\n */\n async runInTransactionAsync<T>(fn: (client: pg.PoolClient) => Promise<T>): Promise<T> {\n // Check if we're already inside a transaction. If so, we won't start another one,\n // as Postgres doesn't support nested transactions.\n const client = this.alsClient.getStore();\n const isNestedTransaction = client !== undefined;\n const transactionClient = client ?? (await this.beginTransactionAsync());\n\n let result: T;\n try {\n result = await this.alsClient.run(transactionClient, () => fn(transactionClient));\n } catch (err: any) {\n if (!isNestedTransaction) {\n // If we're inside another transaction, we assume that the root transaction\n // will catch this error and roll back the transaction.\n await this.endTransactionAsync(transactionClient, err);\n }\n throw err;\n }\n\n if (!isNestedTransaction) {\n // If we're inside another transaction; don't commit it prematurely. Allow\n // the root transaction to commit it instead.\n //\n // Note that we don't invoke `endTransactionAsync` inside the `try` block\n // because we don't want an error thrown by it to trigger *another* call\n // to `endTransactionAsync` in the `catch` block.\n await this.endTransactionAsync(transactionClient, null);\n }\n\n return result;\n }\n\n /**\n * Executes a query with the specified parameters.\n */\n async queryAsync(sql: string, params: QueryParams): Promise<QueryResult> {\n debug('query()', 'sql:', debugString(sql));\n debug('query()', 'params:', debugParams(params));\n const client = await this.getClientAsync();\n try {\n return await this.queryWithClientAsync(client, sql, params);\n } finally {\n // Only release if we aren't nested in a transaction.\n if (this.alsClient.getStore() === undefined) {\n client.release();\n }\n }\n }\n\n /**\n * Executes a query with the specified parameters.\n */\n query = callbackify(this.queryAsync);\n\n /**\n * Executes a query with the specified parameters. Errors if the query does\n * not return exactly one row.\n */\n async queryOneRowAsync(sql: string, params: QueryParams): Promise<pg.QueryResult> {\n debug('queryOneRow()', 'sql:', debugString(sql));\n debug('queryOneRow()', 'params:', debugParams(params));\n const result = await this.queryAsync(sql, params);\n if (result.rowCount !== 1) {\n throw new PostgresError(`Incorrect rowCount: ${result.rowCount}`, {\n sql,\n sqlParams: params,\n });\n }\n debug('queryOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Executes a query with the specified parameters. Errors if the query does\n * not return exactly one row.\n */\n queryOneRow = callbackify(this.queryOneRowAsync);\n\n /**\n * Executes a query with the specified parameters. Errors if the query\n * returns more than one row.\n */\n async queryZeroOrOneRowAsync(sql: string, params: QueryParams): Promise<pg.QueryResult> {\n debug('queryZeroOrOneRow()', 'sql:', debugString(sql));\n debug('queryZeroOrOneRow()', 'params:', debugParams(params));\n const result = await this.queryAsync(sql, params);\n if (result.rowCount == null || result.rowCount > 1) {\n throw new PostgresError(`Incorrect rowCount: ${result.rowCount}`, {\n sql,\n sqlParams: params,\n });\n }\n debug('queryZeroOrOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Executes a query with the specified parameters. Errors if the query\n * returns more than one row.\n */\n queryZeroOrOneRow = callbackify(this.queryZeroOrOneRowAsync);\n\n /**\n * Calls the given function with the specified parameters.\n */\n async callAsync(functionName: string, params: any[]): Promise<pg.QueryResult> {\n debug('call()', 'function:', functionName);\n debug('call()', 'params:', debugParams(params));\n const placeholders = _.map(_.range(1, params.length + 1), (v) => '$' + v).join();\n const sql = `SELECT * FROM ${escapeIdentifier(functionName)}(${placeholders});`;\n const result = await this.queryAsync(sql, params);\n debug('call() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Calls the given function with the specified parameters.\n */\n call = callbackify(this.callAsync);\n\n /**\n * Calls the given function with the specified parameters. Errors if the\n * function does not return exactly one row.\n */\n async callOneRowAsync(functionName: string, params: any[]): Promise<pg.QueryResult> {\n debug('callOneRow()', 'function:', functionName);\n debug('callOneRow()', 'params:', debugParams(params));\n const result = await this.callAsync(functionName, params);\n if (result.rowCount !== 1) {\n throw new PostgresError('Incorrect rowCount: ' + result.rowCount, {\n functionName,\n sqlParams: params,\n });\n }\n debug('callOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Calls the given function with the specified parameters. Errors if the\n * function does not return exactly one row.\n */\n callOneRow = callbackify(this.callOneRowAsync);\n\n /**\n * Calls the given function with the specified parameters. Errors if the\n * function returns more than one row.\n */\n async callZeroOrOneRowAsync(functionName: string, params: any[]): Promise<pg.QueryResult> {\n debug('callZeroOrOneRow()', 'function:', functionName);\n debug('callZeroOrOneRow()', 'params:', debugParams(params));\n const result = await this.callAsync(functionName, params);\n if (result.rowCount == null || result.rowCount > 1) {\n throw new PostgresError('Incorrect rowCount: ' + result.rowCount, {\n functionName,\n sqlParams: params,\n });\n }\n debug('callZeroOrOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Calls the given function with the specified parameters. Errors if the\n * function returns more than one row.\n */\n callZeroOrOneRow = callbackify(this.callZeroOrOneRowAsync);\n\n /**\n * Calls a function with the specified parameters using a specific client.\n */\n async callWithClientAsync(\n client: pg.PoolClient,\n functionName: string,\n params: any[],\n ): Promise<pg.QueryResult> {\n debug('callWithClient()', 'function:', functionName);\n debug('callWithClient()', 'params:', debugParams(params));\n const placeholders = _.map(_.range(1, params.length + 1), (v) => '$' + v).join();\n const sql = `SELECT * FROM ${escapeIdentifier(functionName)}(${placeholders})`;\n const result = await this.queryWithClientAsync(client, sql, params);\n debug('callWithClient() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Calls a function with the specified parameters using a specific client.\n */\n callWithClient = callbackify(this.callWithClientAsync);\n\n /**\n * Calls a function with the specified parameters using a specific client.\n * Errors if the function does not return exactly one row.\n */\n async callWithClientOneRowAsync(\n client: pg.PoolClient,\n functionName: string,\n params: any[],\n ): Promise<pg.QueryResult> {\n debug('callWithClientOneRow()', 'function:', functionName);\n debug('callWithClientOneRow()', 'params:', debugParams(params));\n const result = await this.callWithClientAsync(client, functionName, params);\n if (result.rowCount !== 1) {\n throw new PostgresError('Incorrect rowCount: ' + result.rowCount, {\n functionName,\n sqlParams: params,\n });\n }\n debug('callWithClientOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Calls a function with the specified parameters using a specific client.\n * Errors if the function does not return exactly one row.\n */\n callWithClientOneRow = callbackify(this.callWithClientOneRowAsync);\n\n /**\n * Calls a function with the specified parameters using a specific client.\n * Errors if the function returns more than one row.\n */\n async callWithClientZeroOrOneRowAsync(\n client: pg.PoolClient,\n functionName: string,\n params: any[],\n ): Promise<pg.QueryResult> {\n debug('callWithClientZeroOrOneRow()', 'function:', functionName);\n debug('callWithClientZeroOrOneRow()', 'params:', debugParams(params));\n const result = await this.callWithClientAsync(client, functionName, params);\n if (result.rowCount == null || result.rowCount > 1) {\n throw new PostgresError('Incorrect rowCount: ' + result.rowCount, {\n functionName,\n sqlParams: params,\n });\n }\n debug('callWithClientZeroOrOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Calls a function with the specified parameters using a specific client.\n * Errors if the function returns more than one row.\n */\n callWithClientZeroOrOneRow = callbackify(this.callWithClientZeroOrOneRowAsync);\n\n /**\n * Wrapper around {@link queryAsync} that parses the resulting rows with the\n * given Zod schema. Returns only the rows of the query.\n */\n async queryValidatedRows<Model extends z.ZodTypeAny>(\n query: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model>[]> {\n const results = await this.queryAsync(query, params);\n return z.array(model).parse(results.rows);\n }\n\n /**\n * Wrapper around {@link queryOneRowAsync} that parses the resulting row with\n * the given Zod schema. Returns only a single row of the query.\n */\n async queryValidatedOneRow<Model extends z.ZodTypeAny>(\n query: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model>> {\n const results = await this.queryOneRowAsync(query, params);\n return model.parse(results.rows[0]);\n }\n\n /**\n * Wrapper around {@link queryZeroOrOneRowAsync} that parses the resulting row\n * (if any) with the given Zod schema. Returns either a single row or `null`.\n */\n async queryValidatedZeroOrOneRow<Model extends z.ZodTypeAny>(\n query: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model> | null> {\n const results = await this.queryZeroOrOneRowAsync(query, params);\n if (results.rows.length === 0) {\n return null;\n } else {\n return model.parse(results.rows[0]);\n }\n }\n\n /**\n * Wrapper around {@link queryAsync} that validates that only one column is\n * returned and parses the data in it with the given Zod schema. Returns only\n * the single column of the query as an array.\n */\n async queryValidatedSingleColumnRows<Model extends z.ZodTypeAny>(\n query: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model>[]> {\n const results = await this.queryAsync(query, params);\n if (results.fields.length !== 1) {\n throw new Error(`Expected one column, got ${results.fields.length}`);\n }\n const columnName = results.fields[0].name;\n const rawData = results.rows.map((row) => row[columnName]);\n return z.array(model).parse(rawData);\n }\n\n /**\n * Wrapper around {@link queryOneRowAsync} that validates that only one column\n * is returned and parses the data in it with the given Zod schema. Returns\n * only the single entry.\n */\n async queryValidatedSingleColumnOneRow<Model extends z.ZodTypeAny>(\n query: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model>> {\n const results = await this.queryOneRowAsync(query, params);\n if (results.fields.length !== 1) {\n throw new Error(`Expected one column, got ${results.fields.length}`);\n }\n const columnName = results.fields[0].name;\n return model.parse(results.rows[0][columnName]);\n }\n\n /**\n * Wrapper around {@link queryZeroOrOneRowAsync} that validates that only one\n * column is returned and parses the data in it (if any) with the given Zod\n * schema. Returns either the single row of the query or `null`.\n */\n async queryValidatedSingleColumnZeroOrOneRow<Model extends z.ZodTypeAny>(\n query: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model> | null> {\n const results = await this.queryZeroOrOneRowAsync(query, params);\n if (results.fields.length !== 1) {\n throw new Error(`Expected one column, got ${results.fields.length}`);\n }\n if (results.rows.length === 0) {\n return null;\n } else {\n const columnName = results.fields[0].name;\n return model.parse(results.rows[0][columnName]);\n }\n }\n\n /**\n * Wrapper around {@link callAsync} that parses the resulting rows with the\n * given Zod schema. Returns only the rows.\n */\n async callValidatedRows<Model extends z.ZodTypeAny>(\n sprocName: string,\n params: any[],\n model: Model,\n ): Promise<z.infer<Model>[]> {\n const results = await this.callAsync(sprocName, params);\n return z.array(model).parse(results.rows);\n }\n\n /**\n * Wrapper around {@link callOneRowAsync} that parses the resulting rows with\n * the given Zod schema. Returns only a single row.\n */\n async callValidatedOneRow<Model extends z.ZodTypeAny>(\n sprocName: string,\n params: any[],\n model: Model,\n ): Promise<z.infer<Model>> {\n const results = await this.callOneRowAsync(sprocName, params);\n return model.parse(results.rows[0]);\n }\n\n /**\n * Wrapper around {@link callZeroOrOneRowAsync} that parses the resulting row\n * (if any) with the given Zod schema. Returns at most a single row.\n */\n async callValidatedZeroOrOneRow<Model extends z.ZodTypeAny>(\n sprocName: string,\n params: any[],\n model: Model,\n ): Promise<z.infer<Model> | null> {\n const results = await this.callZeroOrOneRowAsync(sprocName, params);\n if (results.rows.length === 0) {\n return null;\n } else {\n return model.parse(results.rows[0]);\n }\n }\n\n async queryRows<Model extends z.ZodTypeAny>(sql: string, model: Model): Promise<z.infer<Model>[]>;\n async queryRows<Model extends z.ZodTypeAny>(\n sql: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model>[]>;\n async queryRows<Model extends z.ZodTypeAny>(\n sql: string,\n paramsOrSchema: QueryParams | Model,\n maybeModel?: Model,\n ) {\n const params = maybeModel === undefined ? {} : (paramsOrSchema as QueryParams);\n const model = maybeModel === undefined ? (paramsOrSchema as Model) : maybeModel;\n const results = await this.queryAsync(sql, params);\n if (results.fields.length === 1) {\n const columnName = results.fields[0].name;\n const rawData = results.rows.map((row) => row[columnName]);\n return z.array(model).parse(rawData);\n } else {\n return z.array(model).parse(results.rows);\n }\n }\n\n async queryRow<Model extends z.ZodTypeAny>(sql: string, model: Model): Promise<z.infer<Model>>;\n async queryRow<Model extends z.ZodTypeAny>(\n sql: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model>>;\n async queryRow<Model extends z.ZodTypeAny>(\n sql: string,\n paramsOrSchema: QueryParams | Model,\n maybeModel?: Model,\n ) {\n const params = maybeModel === undefined ? {} : (paramsOrSchema as QueryParams);\n const model = maybeModel === undefined ? (paramsOrSchema as Model) : maybeModel;\n const results = await this.queryOneRowAsync(sql, params);\n if (results.fields.length === 1) {\n const columnName = results.fields[0].name;\n return model.parse(results.rows[0][columnName]);\n } else {\n return model.parse(results.rows[0]);\n }\n }\n\n async queryOptionalRow<Model extends z.ZodTypeAny>(\n sql: string,\n model: Model,\n ): Promise<z.infer<Model> | null>;\n async queryOptionalRow<Model extends z.ZodTypeAny>(\n sql: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model> | null>;\n async queryOptionalRow<Model extends z.ZodTypeAny>(\n sql: string,\n paramsOrSchema: QueryParams | Model,\n maybeModel?: Model,\n ) {\n const params = maybeModel === undefined ? {} : (paramsOrSchema as QueryParams);\n const model = maybeModel === undefined ? (paramsOrSchema as Model) : maybeModel;\n const results = await this.queryZeroOrOneRowAsync(sql, params);\n if (results.rows.length === 0) {\n return null;\n } else if (results.fields.length === 1) {\n const columnName = results.fields[0].name;\n return model.parse(results.rows[0][columnName]);\n } else {\n return model.parse(results.rows[0]);\n }\n }\n\n async callRows<Model extends z.ZodTypeAny>(sql: string, model: Model): Promise<z.infer<Model>[]>;\n async callRows<Model extends z.ZodTypeAny>(\n sql: string,\n params: any[],\n model: Model,\n ): Promise<z.infer<Model>[]>;\n async callRows<Model extends z.ZodTypeAny>(\n sql: string,\n paramsOrSchema: any[] | Model,\n maybeModel?: Model,\n ) {\n const params = maybeModel === undefined ? [] : (paramsOrSchema as any[]);\n const model = maybeModel === undefined ? (paramsOrSchema as Model) : maybeModel;\n const results = await this.callAsync(sql, params);\n if (results.fields.length === 1) {\n const columnName = results.fields[0].name;\n const rawData = results.rows.map((row) => row[columnName]);\n return z.array(model).parse(rawData);\n } else {\n return z.array(model).parse(results.rows);\n }\n }\n\n async callRow<Model extends z.ZodTypeAny>(sql: string, model: Model): Promise<z.infer<Model>>;\n async callRow<Model extends z.ZodTypeAny>(\n sql: string,\n params: any[],\n model: Model,\n ): Promise<z.infer<Model>>;\n async callRow<Model extends z.ZodTypeAny>(\n sql: string,\n paramsOrSchema: any[] | Model,\n maybeModel?: Model,\n ) {\n const params = maybeModel === undefined ? [] : (paramsOrSchema as any[]);\n const model = maybeModel === undefined ? (paramsOrSchema as Model) : maybeModel;\n const results = await this.callOneRowAsync(sql, params);\n if (results.fields.length === 1) {\n const columnName = results.fields[0].name;\n return model.parse(results.rows[0][columnName]);\n } else {\n return model.parse(results.rows[0]);\n }\n }\n\n async callOptionalRow<Model extends z.ZodTypeAny>(\n sql: string,\n model: Model,\n ): Promise<z.infer<Model> | null>;\n async callOptionalRow<Model extends z.ZodTypeAny>(\n sql: string,\n params: any[],\n model: Model,\n ): Promise<z.infer<Model> | null>;\n async callOptionalRow<Model extends z.ZodTypeAny>(\n sql: string,\n paramsOrSchema: any[] | Model,\n maybeModel?: Model,\n ) {\n const params = maybeModel === undefined ? [] : (paramsOrSchema as any[]);\n const model = maybeModel === undefined ? (paramsOrSchema as Model) : maybeModel;\n const results = await this.callZeroOrOneRowAsync(sql, params);\n if (results.rows.length === 0) {\n return null;\n } else if (results.fields.length === 1) {\n const columnName = results.fields[0].name;\n return model.parse(results.rows[0][columnName]);\n } else {\n return model.parse(results.rows[0]);\n }\n }\n\n /**\n * Returns a {@link Cursor} for the given query. The cursor can be used to\n * read results in batches, which is useful for large result sets.\n */\n async queryCursorWithClient(\n client: pg.PoolClient,\n sql: string,\n params: QueryParams,\n ): Promise<Cursor> {\n this._queryCount += 1;\n debug('queryCursorWithClient()', 'sql:', debugString(sql));\n debug('queryCursorWithClient()', 'params:', debugParams(params));\n const { processedSql, paramsArray } = paramsToArray(sql, params);\n lastQueryMap.set(client, processedSql);\n return client.query(new Cursor(processedSql, paramsArray));\n }\n\n /**\n * Returns an {@link CursorIterator} that can be used to iterate over the\n * results of the query in batches, which is useful for large result sets.\n */\n async queryCursor<Model extends z.ZodTypeAny>(\n sql: string,\n params: QueryParams,\n ): Promise<CursorIterator<z.infer<Model>>> {\n return this.queryValidatedCursorInternal(sql, params);\n }\n\n /**\n * Returns an {@link CursorIterator} that can be used to iterate over the\n * results of the query in batches, which is useful for large result sets.\n * Each row will be parsed by the given Zod schema.\n */\n async queryValidatedCursor<Model extends z.ZodTypeAny>(\n sql: string,\n params: QueryParams,\n model: Model,\n ): Promise<CursorIterator<z.infer<Model>>> {\n return this.queryValidatedCursorInternal(sql, params, model);\n }\n\n private async queryValidatedCursorInternal<Model extends z.ZodTypeAny>(\n sql: string,\n params: QueryParams,\n model?: Model,\n ): Promise<CursorIterator<z.infer<Model>>> {\n const client = await this.getClientAsync();\n const cursor = await this.queryCursorWithClient(client, sql, params);\n\n let iterateCalled = false;\n const iterator: CursorIterator<z.infer<Model>> = {\n async *iterate(batchSize: number) {\n // Safety check: if someone calls iterate multiple times, they're\n // definitely doing something wrong.\n if (iterateCalled) {\n throw new Error('iterate() called multiple times');\n }\n iterateCalled = true;\n\n try {\n while (true) {\n const rows = await cursor.read(batchSize);\n if (rows.length === 0) {\n break;\n }\n\n if (model) {\n yield z.array(model).parse(rows);\n } else {\n yield rows;\n }\n }\n } catch (err: any) {\n throw enhanceError(err, sql, params);\n } finally {\n try {\n await cursor.close();\n } finally {\n client.release();\n }\n }\n },\n stream(batchSize: number) {\n const transform = new Transform({\n readableObjectMode: true,\n writableObjectMode: true,\n transform(chunk, _encoding, callback) {\n for (const row of chunk) {\n this.push(row);\n }\n callback();\n },\n });\n\n // TODO: use native `node:stream#compose` once it's stable.\n const generator = iterator.iterate(batchSize);\n const pipe = multipipe(Readable.from(generator), transform);\n\n // When the underlying stream is closed, we need to make sure that the\n // cursor is also closed. We do this by calling `return()` on the generator,\n // which will trigger its `finally` block, which will in turn release\n // the client and close the cursor. The fact that the stream is already\n // closed by this point means that someone reading from the stream will\n // never actually see the `null` value that's returned.\n pipe.once('close', () => {\n generator.return(null);\n });\n\n return pipe;\n },\n };\n return iterator;\n }\n\n /**\n * Set the schema to use for the search path.\n *\n * @param schema The schema name to use (can be \"null\" to unset the search path)\n */\n async setSearchSchema(schema: string) {\n if (schema == null) {\n this.searchSchema = schema;\n return;\n }\n\n await this.queryAsync(`CREATE SCHEMA IF NOT EXISTS ${escapeIdentifier(schema)}`, {});\n // We only set searchSchema after CREATE to avoid the above query() call using searchSchema.\n this.searchSchema = schema;\n }\n\n /**\n * Get the schema that is currently used for the search path.\n *\n * @return schema in use (may be `null` to indicate no schema)\n */\n getSearchSchema(): string | null {\n return this.searchSchema;\n }\n\n /**\n * Generate, set, and return a random schema name.\n *\n * @param prefix The prefix of the new schema, only the first 28 characters will be used (after lowercasing).\n * @returns The randomly-generated search schema.\n */\n async setRandomSearchSchemaAsync(prefix: string): Promise<string> {\n // truncated prefix (max 28 characters)\n const truncPrefix = prefix.substring(0, 28);\n // timestamp in format YYYY-MM-DDTHH:MM:SS.SSSZ (guaranteed to not exceed 27 characters in the spec)\n const timestamp = new Date().toISOString();\n // random 6-character suffix to avoid clashes (approx 2 billion possible values)\n const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');\n const suffix = _.times(6, function () {\n return _.sample(chars);\n }).join('');\n\n // Schema is guaranteed to have length at most 63 (= 28 + 1 + 27 + 1 + 6),\n // which is the default PostgreSQL identifier limit.\n // Note that this schema name will need quoting because of characters like ':', '-', etc\n const schema = `${truncPrefix}_${timestamp}_${suffix}`;\n await this.setSearchSchema(schema);\n return schema;\n }\n\n /**\n * Generate, set, and return a random schema name.\n */\n setRandomSearchSchema = callbackify(this.setRandomSearchSchemaAsync);\n\n /** The number of established connections. */\n get totalCount() {\n return this.pool?.totalCount ?? 0;\n }\n\n /** The number of idle connections. */\n get idleCount() {\n return this.pool?.idleCount ?? 0;\n }\n\n /** The number of queries waiting for a connection to become available. */\n get waitingCount() {\n return this.pool?.waitingCount ?? 0;\n }\n\n /** The total number of queries that have been executed by this pool. */\n get queryCount() {\n return this._queryCount;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport { Readable, Transform } from 'node:stream';\nimport { callbackify } from 'node:util';\n\nimport debugfn from 'debug';\nimport _ from 'lodash';\nimport multipipe from 'multipipe';\nimport pg, { QueryResult } from 'pg';\nimport Cursor from 'pg-cursor';\nimport { DatabaseError } from 'pg-protocol';\nimport { z } from 'zod';\n\nexport type QueryParams = Record<string, any> | any[];\n\nexport interface CursorIterator<T> {\n iterate: (batchSize: number) => AsyncGenerator<T[]>;\n stream: (batchSize: number) => NodeJS.ReadWriteStream;\n}\n\nexport interface PostgresPoolConfig extends pg.PoolConfig {\n errorOnUnusedParameters?: boolean;\n}\n\nconst debug = debugfn('@prairielearn/postgres');\nconst lastQueryMap = new WeakMap<pg.PoolClient, string>();\nconst searchSchemaMap = new WeakMap<pg.PoolClient, string>();\n\nfunction addDataToError(err: Error, data: Record<string, any>): Error {\n (err as any).data = {\n ...((err as any).data ?? {}),\n ...data,\n };\n return err;\n}\n\nexport class PostgresError extends Error {\n public data: Record<string, any>;\n\n constructor(message: string, data: Record<string, any>) {\n super(message);\n this.data = data;\n this.name = 'PostgresError';\n }\n}\n\n/**\n * Formats a string for debugging.\n */\nfunction debugString(s: string): string {\n if (!_.isString(s)) return 'NOT A STRING';\n s = s.replace(/\\n/g, '\\\\n');\n if (s.length > 78) s = s.substring(0, 75) + '...';\n s = '\"' + s + '\"';\n return s;\n}\n\n/**\n * Formats a set of params for debugging.\n */\nfunction debugParams(params: QueryParams): string {\n let s;\n try {\n s = JSON.stringify(params);\n } catch (err) {\n s = 'CANNOT JSON STRINGIFY';\n }\n return debugString(s);\n}\n\n/**\n * Given an SQL string and params, creates an array of params and an SQL string\n * with any named dollar-sign placeholders replaced with parameters.\n */\nfunction paramsToArray(\n sql: string,\n params: QueryParams,\n errorOnUnusedParameters: boolean,\n): { processedSql: string; paramsArray: any } {\n if (typeof sql !== 'string') throw new Error('SQL must be a string');\n if (Array.isArray(params)) {\n return {\n processedSql: sql,\n paramsArray: params,\n };\n }\n if (!_.isObjectLike(params)) throw new Error('params must be array or object');\n\n const re = /\\$([-_a-zA-Z0-9]+)/;\n let result;\n let processedSql = '';\n let remainingSql = sql;\n let nParams = 0;\n const map: Record<string, string> = {};\n let paramsArray: any[] = [];\n while ((result = re.exec(remainingSql)) !== null) {\n const v = result[1];\n if (!(v in map)) {\n if (!(v in params)) throw new Error(`Missing parameter: ${v}`);\n if (Array.isArray(params[v])) {\n map[v] =\n 'ARRAY[' +\n _.map(_.range(nParams + 1, nParams + params[v].length + 1), function (n) {\n return '$' + n;\n }).join(',') +\n ']';\n nParams += params[v].length;\n paramsArray = paramsArray.concat(params[v]);\n } else {\n nParams++;\n map[v] = '$' + nParams;\n paramsArray.push(params[v]);\n }\n }\n processedSql += remainingSql.substring(0, result.index) + map[v];\n remainingSql = remainingSql.substring(result.index + result[0].length);\n }\n processedSql += remainingSql;\n remainingSql = '';\n if (errorOnUnusedParameters) {\n const difference = _.difference(Object.keys(params), Object.keys(map));\n if (difference.length) {\n throw new Error(`Unused parameters in SQL query: ${JSON.stringify(difference)}`);\n }\n }\n return { processedSql, paramsArray };\n}\n\n/**\n * Escapes the given identifier for use in an SQL query. Useful for preventing\n * SQL injection.\n */\nfunction escapeIdentifier(identifier: string): string {\n // Note that as of 2021-06-29 escapeIdentifier() is undocumented. See:\n // https://github.com/brianc/node-postgres/pull/396\n // https://github.com/brianc/node-postgres/issues/1978\n // https://www.postgresql.org/docs/12/sql-syntax-lexical.html\n return pg.Client.prototype.escapeIdentifier(identifier);\n}\n\nfunction enhanceError(err: Error, sql: string, params: QueryParams): Error {\n // Copy the error so we don't end up with a circular reference in the\n // final error.\n const sqlError = { ...err };\n\n // `message` is a non-enumerable property, so we need to copy it manually to\n // the error object.\n sqlError.message = err.message;\n\n const errorHasPosition = err instanceof DatabaseError && err.position != null;\n\n return addDataToError(err, {\n sqlError,\n // If the error has a `position` field, we need to use the processed source\n // (where e.g. `$foobar` has been replaced with `$1`) so that the position\n // is accurate.\n sql: errorHasPosition ? paramsToArray(sql, params, false).processedSql : sql,\n sqlParams: params,\n });\n}\n\nexport class PostgresPool {\n /** The pool from which clients will be acquired. */\n private pool: pg.Pool | null = null;\n /**\n * We use this to propagate the client associated with the current transaction\n * to any nested queries. In the past, we had some nasty bugs associated with\n * the fact that we tried to acquire new clients inside of transactions, which\n * ultimately lead to a deadlock.\n */\n private alsClient = new AsyncLocalStorage<pg.PoolClient>();\n private searchSchema: string | null = null;\n /** Tracks the total number of queries executed by this pool. */\n private _queryCount = 0;\n private errorOnUnusedParameters = false;\n\n /**\n * Creates a new connection pool and attempts to connect to the database.\n */\n async initAsync(\n pgConfig: PostgresPoolConfig,\n idleErrorHandler: (error: Error, client: pg.PoolClient) => void,\n ): Promise<void> {\n this.errorOnUnusedParameters = pgConfig.errorOnUnusedParameters ?? false;\n this.pool = new pg.Pool(pgConfig);\n this.pool.on('error', function (err, client) {\n const lastQuery = lastQueryMap.get(client);\n idleErrorHandler(addDataToError(err, { lastQuery }), client);\n });\n this.pool.on('connect', (client) => {\n client.on('error', (err) => {\n const lastQuery = lastQueryMap.get(client);\n idleErrorHandler(addDataToError(err, { lastQuery }), client);\n });\n });\n this.pool.on('remove', (client) => {\n // This shouldn't be necessary, as `pg` currently allows clients to be\n // garbage collected after they're removed. However, if `pg` someday\n // starts reusing client objects across difference connections, this\n // will ensure that we re-set the search path when the client reconnects.\n searchSchemaMap.delete(client);\n });\n\n // Attempt to connect to the database so that we can fail quickly if\n // something isn't configured correctly.\n let retryCount = 0;\n const retryTimeouts = [500, 1000, 2000, 5000, 10000];\n while (retryCount <= retryTimeouts.length) {\n try {\n const client = await this.pool.connect();\n client.release();\n return;\n } catch (err: any) {\n if (retryCount === retryTimeouts.length) {\n throw new Error(\n `Could not connect to Postgres after ${retryTimeouts.length} attempts: ${err.message}`,\n );\n }\n\n const timeout = retryTimeouts[retryCount];\n retryCount++;\n await new Promise((resolve) => setTimeout(resolve, timeout));\n }\n }\n }\n\n /**\n * Creates a new connection pool and attempts to connect to the database.\n */\n init = callbackify(this.initAsync);\n\n /**\n * Closes the connection pool.\n */\n async closeAsync(): Promise<void> {\n if (!this.pool) return;\n await this.pool.end();\n this.pool = null;\n }\n\n /**\n * Closes the connection pool.\n */\n close = callbackify(this.closeAsync);\n\n /**\n * Gets a new client from the connection pool. If `err` is not null\n * then `client` and `done` are undefined. If `err` is null then\n * `client` is valid and can be used. The caller MUST call `done()` to\n * release the client, whether or not errors occurred while using\n * `client`. The client can call `done(truthy_value)` to force\n * destruction of the client, but this should not be used except in\n * unusual circumstances.\n */\n async getClientAsync(): Promise<pg.PoolClient> {\n if (!this.pool) {\n throw new Error('Connection pool is not open');\n }\n\n // If we're inside a transaction, we'll reuse the same client to avoid a\n // potential deadlock.\n const client = this.alsClient.getStore() ?? (await this.pool.connect());\n\n // If we're configured to use a particular schema, we'll store whether or\n // not the search path has already been configured for this particular\n // client. If we acquire a client and it's already had its search path\n // set, we can avoid setting it again since the search path will persist\n // for the life of the client.\n //\n // We do this check for each call to `getClient` instead of on\n // `pool.connect` so that we don't have to be really careful about\n // destroying old clients that were created before `setSearchSchema` was\n // called. Instead, we'll just check if the search path matches the\n // currently-desired schema, and if it's a mismatch (or doesn't exist\n // at all), we re-set it for the current client.\n //\n // Note that this accidentally supports changing the search_path on the fly,\n // although that's not something we currently do (or would be likely to do).\n // It does NOT support clearing the existing search schema - e.g.,\n // `setSearchSchema(null)` would not work as you expect. This is fine, as\n // that's not something we ever do in practice.\n const clientSearchSchema = searchSchemaMap.get(client);\n if (this.searchSchema != null && clientSearchSchema !== this.searchSchema) {\n const setSearchPathSql = `SET search_path TO ${escapeIdentifier(this.searchSchema)},public`;\n try {\n await this.queryWithClientAsync(client, setSearchPathSql, {});\n } catch (err) {\n client.release();\n throw err;\n }\n searchSchemaMap.set(client, this.searchSchema);\n }\n\n return client;\n }\n\n /**\n * Gets a new client from the connection pool.\n */\n getClient(callback: (error: Error | null, client?: pg.PoolClient, done?: () => void) => void) {\n this.getClientAsync()\n .then((client) => callback(null, client, client.release))\n .catch((err) => callback(err));\n }\n\n /**\n * Performs a query with the given client.\n */\n async queryWithClientAsync(\n client: pg.PoolClient,\n sql: string,\n params: QueryParams,\n ): Promise<pg.QueryResult> {\n this._queryCount += 1;\n debug('queryWithClient()', 'sql:', debugString(sql));\n debug('queryWithClient()', 'params:', debugParams(params));\n const { processedSql, paramsArray } = paramsToArray(sql, params, this.errorOnUnusedParameters);\n try {\n lastQueryMap.set(client, processedSql);\n const result = await client.query(processedSql, paramsArray);\n debug('queryWithClient() success', 'rowCount:', result.rowCount);\n return result;\n } catch (err: any) {\n throw enhanceError(err, sql, params);\n }\n }\n\n /**\n * Performs a query with the given client.\n */\n queryWithClient = callbackify(this.queryWithClientAsync);\n\n /**\n * Performs a query with the given client. Errors if the query returns more\n * than one row.\n */\n async queryWithClientOneRowAsync(\n client: pg.PoolClient,\n sql: string,\n params: QueryParams,\n ): Promise<pg.QueryResult> {\n debug('queryWithClientOneRow()', 'sql:', debugString(sql));\n debug('queryWithClientOneRow()', 'params:', debugParams(params));\n const result = await this.queryWithClientAsync(client, sql, params);\n if (result.rowCount !== 1) {\n throw new PostgresError(`Incorrect rowCount: ${result.rowCount}`, {\n sql,\n sqlParams: params,\n result,\n });\n }\n debug('queryWithClientOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Performs a query with the given client. Errors if the query returns more\n * than one row.\n */\n queryWithClientOneRow = callbackify(this.queryWithClientOneRowAsync);\n\n /**\n * Performs a query with the given client. Errors if the query returns more\n * than one row.\n */\n async queryWithClientZeroOrOneRowAsync(\n client: pg.PoolClient,\n sql: string,\n params: QueryParams,\n ): Promise<QueryResult> {\n debug('queryWithClientZeroOrOneRow()', 'sql:', debugString(sql));\n debug('queryWithClientZeroOrOneRow()', 'params:', debugParams(params));\n const result = await this.queryWithClientAsync(client, sql, params);\n if (result.rowCount == null || result.rowCount > 1) {\n throw new PostgresError(`Incorrect rowCount: ${result.rowCount}`, {\n sql,\n sqlParams: params,\n result,\n });\n }\n debug('queryWithClientZeroOrOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Performs a query with the given client. Errors if the query returns more\n * than one row.\n */\n queryWithClientZeroOrOneRow = callbackify(this.queryWithClientZeroOrOneRowAsync);\n\n /**\n * Rolls back the current transaction for the given client.\n */\n async rollbackWithClientAsync(client: pg.PoolClient) {\n debug('rollbackWithClient()');\n // From https://node-postgres.com/features/transactions\n try {\n await client.query('ROLLBACK');\n // Only release the client if we weren't already inside a transaction.\n if (this.alsClient.getStore() === undefined) {\n client.release();\n }\n } catch (err: any) {\n // If there was a problem rolling back the query, something is\n // seriously messed up. Return the error to the release() function to\n // close & remove this client from the pool. If you leave a client in\n // the pool with an unaborted transaction, weird and hard to diagnose\n // problems might happen.\n client.release(err);\n }\n }\n\n /**\n * Rolls back the current transaction for the given client.\n */\n rollbackWithClient(\n client: pg.PoolClient,\n _done: (release?: any) => void,\n callback: (err: Error | null) => void,\n ) {\n // Note that we can't use `util.callbackify` here because this function\n // has an additional unused `done` parameter for backwards compatibility.\n this.rollbackWithClientAsync(client)\n .then(() => callback(null))\n .catch((err) => callback(err));\n }\n\n /**\n * Begins a new transaction.\n */\n async beginTransactionAsync(): Promise<pg.PoolClient> {\n debug('beginTransaction()');\n const client = await this.getClientAsync();\n try {\n await this.queryWithClientAsync(client, 'START TRANSACTION;', {});\n return client;\n } catch (err) {\n await this.rollbackWithClientAsync(client);\n throw err;\n }\n }\n\n /**\n * Commits the transaction if err is null, otherwise rollbacks the transaction.\n * Also releases the client.\n */\n async endTransactionAsync(client: pg.PoolClient, err: Error | null | undefined) {\n debug('endTransaction()');\n if (err) {\n try {\n await this.rollbackWithClientAsync(client);\n } catch (rollbackErr: any) {\n throw addDataToError(rollbackErr, { prevErr: err, rollback: 'fail' });\n }\n\n // Even though we successfully rolled back the transaction, there was\n // still an error in the first place that necessitated a rollback. Re-throw\n // that error here so that everything downstream of here will know about it.\n throw addDataToError(err, { rollback: 'success' });\n } else {\n try {\n await this.queryWithClientAsync(client, 'COMMIT', {});\n } finally {\n // Only release the client if we aren't nested inside another transaction.\n if (this.alsClient.getStore() === undefined) {\n client.release();\n }\n }\n }\n }\n\n /**\n * Commits the transaction if err is null, otherwise rollbacks the transaction.\n * Also releases the client.\n */\n endTransaction(\n client: pg.PoolClient,\n _done: (rollback?: any) => void,\n err: Error | null | undefined,\n callback: (error: Error | null) => void,\n ): void {\n this.endTransactionAsync(client, err)\n .then(() => callback(null))\n .catch((error) => callback(error));\n }\n\n /**\n * Runs the specified function inside of a transaction. The function will\n * receive a database client as an argument, but it can also make queries\n * as usual, and the correct client will be used automatically.\n *\n * The transaction will be rolled back if the function throws an error, and\n * will be committed otherwise.\n */\n async runInTransactionAsync<T>(fn: (client: pg.PoolClient) => Promise<T>): Promise<T> {\n // Check if we're already inside a transaction. If so, we won't start another one,\n // as Postgres doesn't support nested transactions.\n const client = this.alsClient.getStore();\n const isNestedTransaction = client !== undefined;\n const transactionClient = client ?? (await this.beginTransactionAsync());\n\n let result: T;\n try {\n result = await this.alsClient.run(transactionClient, () => fn(transactionClient));\n } catch (err: any) {\n if (!isNestedTransaction) {\n // If we're inside another transaction, we assume that the root transaction\n // will catch this error and roll back the transaction.\n await this.endTransactionAsync(transactionClient, err);\n }\n throw err;\n }\n\n if (!isNestedTransaction) {\n // If we're inside another transaction; don't commit it prematurely. Allow\n // the root transaction to commit it instead.\n //\n // Note that we don't invoke `endTransactionAsync` inside the `try` block\n // because we don't want an error thrown by it to trigger *another* call\n // to `endTransactionAsync` in the `catch` block.\n await this.endTransactionAsync(transactionClient, null);\n }\n\n return result;\n }\n\n /**\n * Executes a query with the specified parameters.\n */\n async queryAsync(sql: string, params: QueryParams): Promise<QueryResult> {\n debug('query()', 'sql:', debugString(sql));\n debug('query()', 'params:', debugParams(params));\n const client = await this.getClientAsync();\n try {\n return await this.queryWithClientAsync(client, sql, params);\n } finally {\n // Only release if we aren't nested in a transaction.\n if (this.alsClient.getStore() === undefined) {\n client.release();\n }\n }\n }\n\n /**\n * Executes a query with the specified parameters.\n */\n query = callbackify(this.queryAsync);\n\n /**\n * Executes a query with the specified parameters. Errors if the query does\n * not return exactly one row.\n */\n async queryOneRowAsync(sql: string, params: QueryParams): Promise<pg.QueryResult> {\n debug('queryOneRow()', 'sql:', debugString(sql));\n debug('queryOneRow()', 'params:', debugParams(params));\n const result = await this.queryAsync(sql, params);\n if (result.rowCount !== 1) {\n throw new PostgresError(`Incorrect rowCount: ${result.rowCount}`, {\n sql,\n sqlParams: params,\n });\n }\n debug('queryOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Executes a query with the specified parameters. Errors if the query does\n * not return exactly one row.\n */\n queryOneRow = callbackify(this.queryOneRowAsync);\n\n /**\n * Executes a query with the specified parameters. Errors if the query\n * returns more than one row.\n */\n async queryZeroOrOneRowAsync(sql: string, params: QueryParams): Promise<pg.QueryResult> {\n debug('queryZeroOrOneRow()', 'sql:', debugString(sql));\n debug('queryZeroOrOneRow()', 'params:', debugParams(params));\n const result = await this.queryAsync(sql, params);\n if (result.rowCount == null || result.rowCount > 1) {\n throw new PostgresError(`Incorrect rowCount: ${result.rowCount}`, {\n sql,\n sqlParams: params,\n });\n }\n debug('queryZeroOrOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Executes a query with the specified parameters. Errors if the query\n * returns more than one row.\n */\n queryZeroOrOneRow = callbackify(this.queryZeroOrOneRowAsync);\n\n /**\n * Calls the given function with the specified parameters.\n */\n async callAsync(functionName: string, params: any[]): Promise<pg.QueryResult> {\n debug('call()', 'function:', functionName);\n debug('call()', 'params:', debugParams(params));\n const placeholders = _.map(_.range(1, params.length + 1), (v) => '$' + v).join();\n const sql = `SELECT * FROM ${escapeIdentifier(functionName)}(${placeholders});`;\n const result = await this.queryAsync(sql, params);\n debug('call() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Calls the given function with the specified parameters.\n */\n call = callbackify(this.callAsync);\n\n /**\n * Calls the given function with the specified parameters. Errors if the\n * function does not return exactly one row.\n */\n async callOneRowAsync(functionName: string, params: any[]): Promise<pg.QueryResult> {\n debug('callOneRow()', 'function:', functionName);\n debug('callOneRow()', 'params:', debugParams(params));\n const result = await this.callAsync(functionName, params);\n if (result.rowCount !== 1) {\n throw new PostgresError('Incorrect rowCount: ' + result.rowCount, {\n functionName,\n sqlParams: params,\n });\n }\n debug('callOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Calls the given function with the specified parameters. Errors if the\n * function does not return exactly one row.\n */\n callOneRow = callbackify(this.callOneRowAsync);\n\n /**\n * Calls the given function with the specified parameters. Errors if the\n * function returns more than one row.\n */\n async callZeroOrOneRowAsync(functionName: string, params: any[]): Promise<pg.QueryResult> {\n debug('callZeroOrOneRow()', 'function:', functionName);\n debug('callZeroOrOneRow()', 'params:', debugParams(params));\n const result = await this.callAsync(functionName, params);\n if (result.rowCount == null || result.rowCount > 1) {\n throw new PostgresError('Incorrect rowCount: ' + result.rowCount, {\n functionName,\n sqlParams: params,\n });\n }\n debug('callZeroOrOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Calls the given function with the specified parameters. Errors if the\n * function returns more than one row.\n */\n callZeroOrOneRow = callbackify(this.callZeroOrOneRowAsync);\n\n /**\n * Calls a function with the specified parameters using a specific client.\n */\n async callWithClientAsync(\n client: pg.PoolClient,\n functionName: string,\n params: any[],\n ): Promise<pg.QueryResult> {\n debug('callWithClient()', 'function:', functionName);\n debug('callWithClient()', 'params:', debugParams(params));\n const placeholders = _.map(_.range(1, params.length + 1), (v) => '$' + v).join();\n const sql = `SELECT * FROM ${escapeIdentifier(functionName)}(${placeholders})`;\n const result = await this.queryWithClientAsync(client, sql, params);\n debug('callWithClient() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Calls a function with the specified parameters using a specific client.\n */\n callWithClient = callbackify(this.callWithClientAsync);\n\n /**\n * Calls a function with the specified parameters using a specific client.\n * Errors if the function does not return exactly one row.\n */\n async callWithClientOneRowAsync(\n client: pg.PoolClient,\n functionName: string,\n params: any[],\n ): Promise<pg.QueryResult> {\n debug('callWithClientOneRow()', 'function:', functionName);\n debug('callWithClientOneRow()', 'params:', debugParams(params));\n const result = await this.callWithClientAsync(client, functionName, params);\n if (result.rowCount !== 1) {\n throw new PostgresError('Incorrect rowCount: ' + result.rowCount, {\n functionName,\n sqlParams: params,\n });\n }\n debug('callWithClientOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Calls a function with the specified parameters using a specific client.\n * Errors if the function does not return exactly one row.\n */\n callWithClientOneRow = callbackify(this.callWithClientOneRowAsync);\n\n /**\n * Calls a function with the specified parameters using a specific client.\n * Errors if the function returns more than one row.\n */\n async callWithClientZeroOrOneRowAsync(\n client: pg.PoolClient,\n functionName: string,\n params: any[],\n ): Promise<pg.QueryResult> {\n debug('callWithClientZeroOrOneRow()', 'function:', functionName);\n debug('callWithClientZeroOrOneRow()', 'params:', debugParams(params));\n const result = await this.callWithClientAsync(client, functionName, params);\n if (result.rowCount == null || result.rowCount > 1) {\n throw new PostgresError('Incorrect rowCount: ' + result.rowCount, {\n functionName,\n sqlParams: params,\n });\n }\n debug('callWithClientZeroOrOneRow() success', 'rowCount:', result.rowCount);\n return result;\n }\n\n /**\n * Calls a function with the specified parameters using a specific client.\n * Errors if the function returns more than one row.\n */\n callWithClientZeroOrOneRow = callbackify(this.callWithClientZeroOrOneRowAsync);\n\n /**\n * Wrapper around {@link queryAsync} that parses the resulting rows with the\n * given Zod schema. Returns only the rows of the query.\n */\n async queryValidatedRows<Model extends z.ZodTypeAny>(\n query: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model>[]> {\n const results = await this.queryAsync(query, params);\n return z.array(model).parse(results.rows);\n }\n\n /**\n * Wrapper around {@link queryOneRowAsync} that parses the resulting row with\n * the given Zod schema. Returns only a single row of the query.\n */\n async queryValidatedOneRow<Model extends z.ZodTypeAny>(\n query: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model>> {\n const results = await this.queryOneRowAsync(query, params);\n return model.parse(results.rows[0]);\n }\n\n /**\n * Wrapper around {@link queryZeroOrOneRowAsync} that parses the resulting row\n * (if any) with the given Zod schema. Returns either a single row or `null`.\n */\n async queryValidatedZeroOrOneRow<Model extends z.ZodTypeAny>(\n query: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model> | null> {\n const results = await this.queryZeroOrOneRowAsync(query, params);\n if (results.rows.length === 0) {\n return null;\n } else {\n return model.parse(results.rows[0]);\n }\n }\n\n /**\n * Wrapper around {@link queryAsync} that validates that only one column is\n * returned and parses the data in it with the given Zod schema. Returns only\n * the single column of the query as an array.\n */\n async queryValidatedSingleColumnRows<Model extends z.ZodTypeAny>(\n query: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model>[]> {\n const results = await this.queryAsync(query, params);\n if (results.fields.length !== 1) {\n throw new Error(`Expected one column, got ${results.fields.length}`);\n }\n const columnName = results.fields[0].name;\n const rawData = results.rows.map((row) => row[columnName]);\n return z.array(model).parse(rawData);\n }\n\n /**\n * Wrapper around {@link queryOneRowAsync} that validates that only one column\n * is returned and parses the data in it with the given Zod schema. Returns\n * only the single entry.\n */\n async queryValidatedSingleColumnOneRow<Model extends z.ZodTypeAny>(\n query: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model>> {\n const results = await this.queryOneRowAsync(query, params);\n if (results.fields.length !== 1) {\n throw new Error(`Expected one column, got ${results.fields.length}`);\n }\n const columnName = results.fields[0].name;\n return model.parse(results.rows[0][columnName]);\n }\n\n /**\n * Wrapper around {@link queryZeroOrOneRowAsync} that validates that only one\n * column is returned and parses the data in it (if any) with the given Zod\n * schema. Returns either the single row of the query or `null`.\n */\n async queryValidatedSingleColumnZeroOrOneRow<Model extends z.ZodTypeAny>(\n query: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model> | null> {\n const results = await this.queryZeroOrOneRowAsync(query, params);\n if (results.fields.length !== 1) {\n throw new Error(`Expected one column, got ${results.fields.length}`);\n }\n if (results.rows.length === 0) {\n return null;\n } else {\n const columnName = results.fields[0].name;\n return model.parse(results.rows[0][columnName]);\n }\n }\n\n /**\n * Wrapper around {@link callAsync} that parses the resulting rows with the\n * given Zod schema. Returns only the rows.\n */\n async callValidatedRows<Model extends z.ZodTypeAny>(\n sprocName: string,\n params: any[],\n model: Model,\n ): Promise<z.infer<Model>[]> {\n const results = await this.callAsync(sprocName, params);\n return z.array(model).parse(results.rows);\n }\n\n /**\n * Wrapper around {@link callOneRowAsync} that parses the resulting rows with\n * the given Zod schema. Returns only a single row.\n */\n async callValidatedOneRow<Model extends z.ZodTypeAny>(\n sprocName: string,\n params: any[],\n model: Model,\n ): Promise<z.infer<Model>> {\n const results = await this.callOneRowAsync(sprocName, params);\n return model.parse(results.rows[0]);\n }\n\n /**\n * Wrapper around {@link callZeroOrOneRowAsync} that parses the resulting row\n * (if any) with the given Zod schema. Returns at most a single row.\n */\n async callValidatedZeroOrOneRow<Model extends z.ZodTypeAny>(\n sprocName: string,\n params: any[],\n model: Model,\n ): Promise<z.infer<Model> | null> {\n const results = await this.callZeroOrOneRowAsync(sprocName, params);\n if (results.rows.length === 0) {\n return null;\n } else {\n return model.parse(results.rows[0]);\n }\n }\n\n async queryRows<Model extends z.ZodTypeAny>(sql: string, model: Model): Promise<z.infer<Model>[]>;\n async queryRows<Model extends z.ZodTypeAny>(\n sql: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model>[]>;\n async queryRows<Model extends z.ZodTypeAny>(\n sql: string,\n paramsOrSchema: QueryParams | Model,\n maybeModel?: Model,\n ) {\n const params = maybeModel === undefined ? {} : (paramsOrSchema as QueryParams);\n const model = maybeModel === undefined ? (paramsOrSchema as Model) : maybeModel;\n const results = await this.queryAsync(sql, params);\n if (results.fields.length === 1) {\n const columnName = results.fields[0].name;\n const rawData = results.rows.map((row) => row[columnName]);\n return z.array(model).parse(rawData);\n } else {\n return z.array(model).parse(results.rows);\n }\n }\n\n async queryRow<Model extends z.ZodTypeAny>(sql: string, model: Model): Promise<z.infer<Model>>;\n async queryRow<Model extends z.ZodTypeAny>(\n sql: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model>>;\n async queryRow<Model extends z.ZodTypeAny>(\n sql: string,\n paramsOrSchema: QueryParams | Model,\n maybeModel?: Model,\n ) {\n const params = maybeModel === undefined ? {} : (paramsOrSchema as QueryParams);\n const model = maybeModel === undefined ? (paramsOrSchema as Model) : maybeModel;\n const results = await this.queryOneRowAsync(sql, params);\n if (results.fields.length === 1) {\n const columnName = results.fields[0].name;\n return model.parse(results.rows[0][columnName]);\n } else {\n return model.parse(results.rows[0]);\n }\n }\n\n async queryOptionalRow<Model extends z.ZodTypeAny>(\n sql: string,\n model: Model,\n ): Promise<z.infer<Model> | null>;\n async queryOptionalRow<Model extends z.ZodTypeAny>(\n sql: string,\n params: QueryParams,\n model: Model,\n ): Promise<z.infer<Model> | null>;\n async queryOptionalRow<Model extends z.ZodTypeAny>(\n sql: string,\n paramsOrSchema: QueryParams | Model,\n maybeModel?: Model,\n ) {\n const params = maybeModel === undefined ? {} : (paramsOrSchema as QueryParams);\n const model = maybeModel === undefined ? (paramsOrSchema as Model) : maybeModel;\n const results = await this.queryZeroOrOneRowAsync(sql, params);\n if (results.rows.length === 0) {\n return null;\n } else if (results.fields.length === 1) {\n const columnName = results.fields[0].name;\n return model.parse(results.rows[0][columnName]);\n } else {\n return model.parse(results.rows[0]);\n }\n }\n\n async callRows<Model extends z.ZodTypeAny>(sql: string, model: Model): Promise<z.infer<Model>[]>;\n async callRows<Model extends z.ZodTypeAny>(\n sql: string,\n params: any[],\n model: Model,\n ): Promise<z.infer<Model>[]>;\n async callRows<Model extends z.ZodTypeAny>(\n sql: string,\n paramsOrSchema: any[] | Model,\n maybeModel?: Model,\n ) {\n const params = maybeModel === undefined ? [] : (paramsOrSchema as any[]);\n const model = maybeModel === undefined ? (paramsOrSchema as Model) : maybeModel;\n const results = await this.callAsync(sql, params);\n if (results.fields.length === 1) {\n const columnName = results.fields[0].name;\n const rawData = results.rows.map((row) => row[columnName]);\n return z.array(model).parse(rawData);\n } else {\n return z.array(model).parse(results.rows);\n }\n }\n\n async callRow<Model extends z.ZodTypeAny>(sql: string, model: Model): Promise<z.infer<Model>>;\n async callRow<Model extends z.ZodTypeAny>(\n sql: string,\n params: any[],\n model: Model,\n ): Promise<z.infer<Model>>;\n async callRow<Model extends z.ZodTypeAny>(\n sql: string,\n paramsOrSchema: any[] | Model,\n maybeModel?: Model,\n ) {\n const params = maybeModel === undefined ? [] : (paramsOrSchema as any[]);\n const model = maybeModel === undefined ? (paramsOrSchema as Model) : maybeModel;\n const results = await this.callOneRowAsync(sql, params);\n if (results.fields.length === 1) {\n const columnName = results.fields[0].name;\n return model.parse(results.rows[0][columnName]);\n } else {\n return model.parse(results.rows[0]);\n }\n }\n\n async callOptionalRow<Model extends z.ZodTypeAny>(\n sql: string,\n model: Model,\n ): Promise<z.infer<Model> | null>;\n async callOptionalRow<Model extends z.ZodTypeAny>(\n sql: string,\n params: any[],\n model: Model,\n ): Promise<z.infer<Model> | null>;\n async callOptionalRow<Model extends z.ZodTypeAny>(\n sql: string,\n paramsOrSchema: any[] | Model,\n maybeModel?: Model,\n ) {\n const params = maybeModel === undefined ? [] : (paramsOrSchema as any[]);\n const model = maybeModel === undefined ? (paramsOrSchema as Model) : maybeModel;\n const results = await this.callZeroOrOneRowAsync(sql, params);\n if (results.rows.length === 0) {\n return null;\n } else if (results.fields.length === 1) {\n const columnName = results.fields[0].name;\n return model.parse(results.rows[0][columnName]);\n } else {\n return model.parse(results.rows[0]);\n }\n }\n\n /**\n * Returns a {@link Cursor} for the given query. The cursor can be used to\n * read results in batches, which is useful for large result sets.\n */\n async queryCursorWithClient(\n client: pg.PoolClient,\n sql: string,\n params: QueryParams,\n ): Promise<Cursor> {\n this._queryCount += 1;\n debug('queryCursorWithClient()', 'sql:', debugString(sql));\n debug('queryCursorWithClient()', 'params:', debugParams(params));\n const { processedSql, paramsArray } = paramsToArray(sql, params, this.errorOnUnusedParameters);\n lastQueryMap.set(client, processedSql);\n return client.query(new Cursor(processedSql, paramsArray));\n }\n\n /**\n * Returns an {@link CursorIterator} that can be used to iterate over the\n * results of the query in batches, which is useful for large result sets.\n */\n async queryCursor<Model extends z.ZodTypeAny>(\n sql: string,\n params: QueryParams,\n ): Promise<CursorIterator<z.infer<Model>>> {\n return this.queryValidatedCursorInternal(sql, params);\n }\n\n /**\n * Returns an {@link CursorIterator} that can be used to iterate over the\n * results of the query in batches, which is useful for large result sets.\n * Each row will be parsed by the given Zod schema.\n */\n async queryValidatedCursor<Model extends z.ZodTypeAny>(\n sql: string,\n params: QueryParams,\n model: Model,\n ): Promise<CursorIterator<z.infer<Model>>> {\n return this.queryValidatedCursorInternal(sql, params, model);\n }\n\n private async queryValidatedCursorInternal<Model extends z.ZodTypeAny>(\n sql: string,\n params: QueryParams,\n model?: Model,\n ): Promise<CursorIterator<z.infer<Model>>> {\n const client = await this.getClientAsync();\n const cursor = await this.queryCursorWithClient(client, sql, params);\n\n let iterateCalled = false;\n const iterator: CursorIterator<z.infer<Model>> = {\n async *iterate(batchSize: number) {\n // Safety check: if someone calls iterate multiple times, they're\n // definitely doing something wrong.\n if (iterateCalled) {\n throw new Error('iterate() called multiple times');\n }\n iterateCalled = true;\n\n try {\n while (true) {\n const rows = await cursor.read(batchSize);\n if (rows.length === 0) {\n break;\n }\n\n if (model) {\n yield z.array(model).parse(rows);\n } else {\n yield rows;\n }\n }\n } catch (err: any) {\n throw enhanceError(err, sql, params);\n } finally {\n try {\n await cursor.close();\n } finally {\n client.release();\n }\n }\n },\n stream(batchSize: number) {\n const transform = new Transform({\n readableObjectMode: true,\n writableObjectMode: true,\n transform(chunk, _encoding, callback) {\n for (const row of chunk) {\n this.push(row);\n }\n callback();\n },\n });\n\n // TODO: use native `node:stream#compose` once it's stable.\n const generator = iterator.iterate(batchSize);\n const pipe = multipipe(Readable.from(generator), transform);\n\n // When the underlying stream is closed, we need to make sure that the\n // cursor is also closed. We do this by calling `return()` on the generator,\n // which will trigger its `finally` block, which will in turn release\n // the client and close the cursor. The fact that the stream is already\n // closed by this point means that someone reading from the stream will\n // never actually see the `null` value that's returned.\n pipe.once('close', () => {\n generator.return(null);\n });\n\n return pipe;\n },\n };\n return iterator;\n }\n\n /**\n * Set the schema to use for the search path.\n *\n * @param schema The schema name to use (can be \"null\" to unset the search path)\n */\n async setSearchSchema(schema: string) {\n if (schema == null) {\n this.searchSchema = schema;\n return;\n }\n\n await this.queryAsync(`CREATE SCHEMA IF NOT EXISTS ${escapeIdentifier(schema)}`, {});\n // We only set searchSchema after CREATE to avoid the above query() call using searchSchema.\n this.searchSchema = schema;\n }\n\n /**\n * Get the schema that is currently used for the search path.\n *\n * @return schema in use (may be `null` to indicate no schema)\n */\n getSearchSchema(): string | null {\n return this.searchSchema;\n }\n\n /**\n * Generate, set, and return a random schema name.\n *\n * @param prefix The prefix of the new schema, only the first 28 characters will be used (after lowercasing).\n * @returns The randomly-generated search schema.\n */\n async setRandomSearchSchemaAsync(prefix: string): Promise<string> {\n // truncated prefix (max 28 characters)\n const truncPrefix = prefix.substring(0, 28);\n // timestamp in format YYYY-MM-DDTHH:MM:SS.SSSZ (guaranteed to not exceed 27 characters in the spec)\n const timestamp = new Date().toISOString();\n // random 6-character suffix to avoid clashes (approx 2 billion possible values)\n const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');\n const suffix = _.times(6, function () {\n return _.sample(chars);\n }).join('');\n\n // Schema is guaranteed to have length at most 63 (= 28 + 1 + 27 + 1 + 6),\n // which is the default PostgreSQL identifier limit.\n // Note that this schema name will need quoting because of characters like ':', '-', etc\n const schema = `${truncPrefix}_${timestamp}_${suffix}`;\n await this.setSearchSchema(schema);\n return schema;\n }\n\n /**\n * Generate, set, and return a random schema name.\n */\n setRandomSearchSchema = callbackify(this.setRandomSearchSchemaAsync);\n\n /** The number of established connections. */\n get totalCount() {\n return this.pool?.totalCount ?? 0;\n }\n\n /** The number of idle connections. */\n get idleCount() {\n return this.pool?.idleCount ?? 0;\n }\n\n /** The number of queries waiting for a connection to become available. */\n get waitingCount() {\n return this.pool?.waitingCount ?? 0;\n }\n\n /** The total number of queries that have been executed by this pool. */\n get queryCount() {\n return this._queryCount;\n }\n}\n"]}
|
package/dist/pool.test.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import chai from 'chai';
|
|
2
|
-
import chaiAsPromised from 'chai-as-promised';
|
|
3
1
|
import { Writable } from 'node:stream';
|
|
4
2
|
import { pipeline } from 'node:stream/promises';
|
|
3
|
+
import { use as chaiUse, assert } from 'chai';
|
|
4
|
+
import chaiAsPromised from 'chai-as-promised';
|
|
5
5
|
import { z, ZodError } from 'zod';
|
|
6
6
|
import { queryAsync, queryRows, queryRow, queryOptionalRow, callRows, callRow, callOptionalRow, queryCursor, queryValidatedCursor, } from './default-pool.js';
|
|
7
7
|
import { makePostgresTestUtils } from './test-utils.js';
|
|
8
|
-
|
|
9
|
-
const { assert } = chai;
|
|
8
|
+
chaiUse(chaiAsPromised);
|
|
10
9
|
const postgresTestUtils = makePostgresTestUtils({
|
|
11
10
|
database: 'prairielearn_postgres',
|
|
12
11
|
});
|
|
@@ -31,6 +30,26 @@ describe('@prairielearn/postgres', function () {
|
|
|
31
30
|
after(async () => {
|
|
32
31
|
await postgresTestUtils.dropDatabase();
|
|
33
32
|
});
|
|
33
|
+
describe('paramsToArray', () => {
|
|
34
|
+
it('enforces SQL must be a string', async () => {
|
|
35
|
+
// @ts-expect-error SQL must be a string
|
|
36
|
+
const rows = queryAsync({ invalid: true }, {});
|
|
37
|
+
await assert.isRejected(rows, 'SQL must be a string');
|
|
38
|
+
});
|
|
39
|
+
it('enforces params must be array or object', async () => {
|
|
40
|
+
// @ts-expect-error params must be an array or object
|
|
41
|
+
const rows = queryAsync('SELECT 33;', 33);
|
|
42
|
+
await assert.isRejected(rows, 'params must be array or object');
|
|
43
|
+
});
|
|
44
|
+
it('rejects missing parameters', async () => {
|
|
45
|
+
const rows = queryAsync('SELECT $missing;', {});
|
|
46
|
+
await assert.isRejected(rows, 'Missing parameter');
|
|
47
|
+
});
|
|
48
|
+
it('rejects unused parameters in testing', async () => {
|
|
49
|
+
const rows = queryAsync('SELECT 33;', { unsed_parameter: true });
|
|
50
|
+
await assert.isRejected(rows, 'Unused parameter');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
34
53
|
describe('queryRows', () => {
|
|
35
54
|
it('handles single column', async () => {
|
|
36
55
|
const rows = await queryRows('SELECT id FROM workspaces WHERE id <= 10;', z.string());
|
|
@@ -192,7 +211,7 @@ describe('@prairielearn/postgres', function () {
|
|
|
192
211
|
assert.lengthOf(rowBatches[0], 10);
|
|
193
212
|
});
|
|
194
213
|
it('handles errors', async () => {
|
|
195
|
-
const cursor = await queryCursor('NOT VALID SQL', {
|
|
214
|
+
const cursor = await queryCursor('NOT VALID SQL', {});
|
|
196
215
|
async function readAllRows() {
|
|
197
216
|
const allRows = [];
|
|
198
217
|
for await (const rows of cursor.iterate(10)) {
|
|
@@ -205,7 +224,7 @@ describe('@prairielearn/postgres', function () {
|
|
|
205
224
|
assert.match(maybeError.message, /syntax error/);
|
|
206
225
|
assert.isDefined(maybeError.data);
|
|
207
226
|
assert.equal(maybeError.data.sql, 'NOT VALID SQL');
|
|
208
|
-
assert.deepEqual(maybeError.data.sqlParams, {
|
|
227
|
+
assert.deepEqual(maybeError.data.sqlParams, {});
|
|
209
228
|
assert.isDefined(maybeError.data.sqlError);
|
|
210
229
|
assert.equal(maybeError.data.sqlError.severity, 'ERROR');
|
|
211
230
|
});
|
package/dist/pool.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool.test.js","sourceRoot":"","sources":["../src/pool.test.ts"],"names":[],"mappings":"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","sourcesContent":["import chai from 'chai';\nimport chaiAsPromised from 'chai-as-promised';\nimport { Writable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\nimport { z, ZodError } from 'zod';\n\nimport {\n queryAsync,\n queryRows,\n queryRow,\n queryOptionalRow,\n callRows,\n callRow,\n callOptionalRow,\n queryCursor,\n queryValidatedCursor,\n} from './default-pool.js';\nimport { makePostgresTestUtils } from './test-utils.js';\n\nchai.use(chaiAsPromised);\nconst { assert } = chai;\n\nconst postgresTestUtils = makePostgresTestUtils({\n database: 'prairielearn_postgres',\n});\n\nconst WorkspaceSchema = z.object({\n id: z.string(),\n created_at: z.date(),\n});\n\nconst SprocTwoColumnsSchema = z.object({\n id: z.string(),\n negative: z.number(),\n});\n\ndescribe('@prairielearn/postgres', function () {\n before(async () => {\n await postgresTestUtils.createDatabase();\n await queryAsync(\n 'CREATE TABLE workspaces (id BIGSERIAL PRIMARY KEY, created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP);',\n {},\n );\n await queryAsync('INSERT INTO workspaces (id) SELECT s FROM generate_series(1, 100) AS s', {});\n await queryAsync(\n 'CREATE FUNCTION test_sproc_one_column(num_entries INT) RETURNS TABLE (id BIGINT) AS $$ BEGIN RETURN QUERY SELECT s::BIGINT AS id FROM generate_series(1, num_entries) AS s; END; $$ LANGUAGE plpgsql;',\n {},\n );\n await queryAsync(\n 'CREATE FUNCTION test_sproc_two_columns(num_entries INT) RETURNS TABLE (id BIGINT, negative INT) AS $$ BEGIN RETURN QUERY SELECT s::BIGINT AS id, -s AS negative FROM generate_series(1, num_entries) AS s; END; $$ LANGUAGE plpgsql;',\n {},\n );\n await queryAsync(\n 'CREATE FUNCTION test_sproc_one_column_ten_rows() RETURNS TABLE (id BIGINT) AS $$ BEGIN RETURN QUERY SELECT s::BIGINT AS id FROM generate_series(1, 10) AS s; END; $$ LANGUAGE plpgsql;',\n {},\n );\n await queryAsync(\n 'CREATE FUNCTION test_sproc_one_column_one_row(OUT id BIGINT) AS $$ BEGIN id = 1; END; $$ LANGUAGE plpgsql;',\n {},\n );\n });\n\n after(async () => {\n await postgresTestUtils.dropDatabase();\n });\n\n describe('queryRows', () => {\n it('handles single column', async () => {\n const rows = await queryRows('SELECT id FROM workspaces WHERE id <= 10;', z.string());\n assert.lengthOf(rows, 10);\n assert.equal(rows[0], '1');\n });\n\n it('handles multiple columns', async () => {\n const rows = await queryRows('SELECT * FROM workspaces WHERE id <= 10;', WorkspaceSchema);\n assert.lengthOf(rows, 10);\n assert.equal(rows[0].id, '1');\n assert.isNotNull(rows[0].created_at);\n });\n\n it('handles parameters', async () => {\n const rows = await queryRows(\n 'SELECT * FROM workspaces WHERE id <= $1;',\n [10],\n WorkspaceSchema,\n );\n assert.lengthOf(rows, 10);\n });\n });\n\n describe('queryRow', () => {\n it('handles single column', async () => {\n const row = await queryRow('SELECT id FROM workspaces WHERE id = 1;', z.string());\n assert.equal(row, '1');\n });\n\n it('handles multiple columns', async () => {\n const row = await queryRow('SELECT * FROM workspaces WHERE id = 1;', WorkspaceSchema);\n assert.equal(row.id, '1');\n assert.isNotNull(row.created_at);\n });\n\n it('handles parameters', async () => {\n const row = await queryRow('SELECT * FROM workspaces WHERE id = $1;', [1], WorkspaceSchema);\n assert.equal(row.id, '1');\n });\n\n it('rejects results with zero rows', async () => {\n const rows = queryRow('SELECT * FROM workspaces WHERE id = -1;', WorkspaceSchema);\n await assert.isRejected(rows, 'Incorrect rowCount: 0');\n });\n\n it('rejects results with multiple rows', async () => {\n const rows = queryRow('SELECT * FROM workspaces', WorkspaceSchema);\n await assert.isRejected(rows, 'Incorrect rowCount: 100');\n });\n });\n\n describe('queryOptionalRow', () => {\n it('handles single column', async () => {\n const row = await queryRow('SELECT id FROM workspaces WHERE id = 1;', z.string());\n assert.equal(row, '1');\n });\n\n it('handles multiple columns', async () => {\n const row = await queryOptionalRow('SELECT * FROM workspaces WHERE id = 1;', WorkspaceSchema);\n assert.isNotNull(row);\n assert.equal(row?.id, '1');\n assert.isNotNull(row?.created_at);\n });\n\n it('handles parameters', async () => {\n const row = await queryOptionalRow(\n 'SELECT * FROM workspaces WHERE id = $1;',\n [1],\n WorkspaceSchema,\n );\n assert.isNotNull(row);\n assert.equal(row?.id, '1');\n });\n\n it('handles missing result', async () => {\n const row = await queryOptionalRow(\n 'SELECT * FROM workspaces WHERE id = -1;',\n WorkspaceSchema,\n );\n assert.isNull(row);\n });\n\n it('rejects with multiple rows', async () => {\n const rows = queryOptionalRow('SELECT * FROM workspaces', WorkspaceSchema);\n await assert.isRejected(rows, 'Incorrect rowCount: 100');\n });\n });\n\n describe('callRows', () => {\n it('handles single column', async () => {\n const rows = await callRows('test_sproc_one_column_ten_rows', z.string());\n assert.lengthOf(rows, 10);\n assert.equal(rows[0], '1');\n });\n\n it('handles parameters', async () => {\n const rows = await callRows('test_sproc_one_column', [10], z.string());\n assert.lengthOf(rows, 10);\n assert.equal(rows[0], '1');\n });\n\n it('handles multiple columns', async () => {\n const rows = await callRows('test_sproc_two_columns', [20], SprocTwoColumnsSchema);\n assert.lengthOf(rows, 20);\n assert.equal(rows[0].id, '1');\n assert.equal(rows[0].negative, -1);\n assert.equal(rows[19].id, '20');\n assert.equal(rows[19].negative, -20);\n });\n });\n\n describe('callRow', () => {\n it('handles single column', async () => {\n const row = await callRow('test_sproc_one_column_one_row', z.string());\n assert.equal(row, '1');\n });\n\n it('handles parameters', async () => {\n const row = await callRow('test_sproc_one_column', [1], z.string());\n assert.equal(row, '1');\n });\n\n it('handles multiple columns', async () => {\n const row = await callRow('test_sproc_two_columns', [1], SprocTwoColumnsSchema);\n assert.equal(row.id, '1');\n assert.equal(row.negative, -1);\n });\n\n it('rejects results with zero rows', async () => {\n const row = callRow('test_sproc_two_columns', [0], SprocTwoColumnsSchema);\n await assert.isRejected(row, 'Incorrect rowCount: 0');\n });\n\n it('rejects results with multiple rows', async () => {\n const rows = callRow('test_sproc_two_columns', [100], SprocTwoColumnsSchema);\n await assert.isRejected(rows, 'Incorrect rowCount: 100');\n });\n });\n\n describe('callOptionalRow', () => {\n it('handles single column', async () => {\n const row = await callOptionalRow('test_sproc_one_column_one_row', z.string());\n assert.equal(row, '1');\n });\n\n it('handles parameters', async () => {\n const row = await callOptionalRow('test_sproc_one_column', [1], z.string());\n assert.equal(row, '1');\n });\n\n it('handles multiple columns', async () => {\n const row = await callOptionalRow('test_sproc_two_columns', [1], SprocTwoColumnsSchema);\n assert.isNotNull(row);\n assert.equal(row?.id, '1');\n assert.equal(row?.negative, -1);\n });\n\n it('handles results with zero rows', async () => {\n const row = await callOptionalRow('test_sproc_two_columns', [0], SprocTwoColumnsSchema);\n assert.isNull(row);\n });\n\n it('rejects results with multiple rows', async () => {\n const rows = callOptionalRow('test_sproc_two_columns', [100], SprocTwoColumnsSchema);\n await assert.isRejected(rows, 'Incorrect rowCount: 100');\n });\n });\n\n describe('queryCursor', () => {\n it('returns zero rows', async () => {\n const cursor = await queryCursor('SELECT * FROM workspaces WHERE id = 10000;', {});\n const rowBatches = [];\n for await (const rows of cursor.iterate(10)) {\n rowBatches.push(rows);\n }\n assert.lengthOf(rowBatches, 0);\n });\n\n it('returns one row at a time', async () => {\n const cursor = await queryCursor('SELECT * FROM workspaces WHERE id <= 2;', {});\n const rowBatches = [];\n for await (const rows of cursor.iterate(1)) {\n rowBatches.push(rows);\n }\n assert.lengthOf(rowBatches, 2);\n assert.lengthOf(rowBatches[0], 1);\n assert.lengthOf(rowBatches[1], 1);\n });\n\n it('returns all rows at once', async () => {\n const cursor = queryCursor('SELECT * FROM workspaces WHERE id <= 10;', {});\n const rowBatches = [];\n for await (const rows of (await cursor).iterate(10)) {\n rowBatches.push(rows);\n }\n assert.lengthOf(rowBatches, 1);\n assert.lengthOf(rowBatches[0], 10);\n });\n\n it('handles errors', async () => {\n const cursor = await queryCursor('NOT VALID SQL', { foo: 'bar' });\n\n async function readAllRows() {\n const allRows = [];\n for await (const rows of cursor.iterate(10)) {\n allRows.push(...rows);\n }\n return allRows;\n }\n\n const maybeError = await readAllRows().catch((err) => err);\n assert.instanceOf(maybeError, Error);\n assert.match(maybeError.message, /syntax error/);\n assert.isDefined(maybeError.data);\n assert.equal(maybeError.data.sql, 'NOT VALID SQL');\n assert.deepEqual(maybeError.data.sqlParams, { foo: 'bar' });\n assert.isDefined(maybeError.data.sqlError);\n assert.equal(maybeError.data.sqlError.severity, 'ERROR');\n });\n });\n\n describe('queryValidatedCursor', () => {\n const WorkspaceSchema = z.object({\n id: z.string(),\n });\n\n const BadWorkspaceSchema = z.object({\n badProperty: z.string(),\n });\n\n describe('iterator', () => {\n it('validates with provided schema', async () => {\n const cursor = await queryValidatedCursor(\n 'SELECT * FROM workspaces WHERE id <= 10 ORDER BY id ASC;',\n {},\n WorkspaceSchema,\n );\n const allRows = [];\n for await (const rows of cursor.iterate(10)) {\n allRows.push(...rows);\n }\n assert.lengthOf(allRows, 10);\n const workspace = allRows[0] as any;\n assert.equal(workspace.id, '1');\n assert.isUndefined(workspace.state);\n });\n\n it('throws error when validation fails', async () => {\n const cursor = await queryValidatedCursor(\n 'SELECT * FROM workspaces WHERE id <= 10 ORDER BY id ASC;',\n {},\n BadWorkspaceSchema,\n );\n\n async function readAllRows() {\n const allRows = [];\n for await (const rows of cursor.iterate(10)) {\n allRows.push(...rows);\n }\n return allRows;\n }\n\n const maybeError = await readAllRows().catch((err) => err);\n assert.instanceOf(maybeError, ZodError);\n assert.lengthOf(maybeError.errors, 10);\n });\n });\n\n describe('stream', () => {\n it('validates with provided schema', async () => {\n const cursor = await queryValidatedCursor(\n 'SELECT * FROM workspaces WHERE id <= 10 ORDER BY id ASC;',\n {},\n WorkspaceSchema,\n );\n const stream = cursor.stream(1);\n const allRows = [];\n for await (const row of stream) {\n allRows.push(row);\n }\n\n assert.lengthOf(allRows, 10);\n });\n\n it('emits an error when validation fails', async () => {\n const cursor = await queryValidatedCursor(\n 'SELECT * FROM workspaces ORDER BY id ASC;',\n {},\n BadWorkspaceSchema,\n );\n const stream = cursor.stream(1);\n\n async function readAllRows() {\n const allRows = [];\n for await (const row of stream) {\n allRows.push(row);\n }\n return allRows;\n }\n\n const maybeError = await readAllRows().catch((err) => err);\n assert.instanceOf(maybeError, ZodError);\n assert.lengthOf(maybeError.errors, 1);\n });\n\n it('closes the cursor when the stream is closed', async () => {\n const cursor = await queryValidatedCursor('SELECT * FROM workspaces;', {}, WorkspaceSchema);\n const stream = cursor.stream(1);\n\n const rows: any[] = [];\n const ac = new AbortController();\n const writable = new Writable({\n objectMode: true,\n write(chunk, _encoding, callback) {\n rows.push(chunk);\n\n // After receiving the first row, abort the stream. This lets us test\n // that the underlying cursor is closed. If it is *not* closed, this\n // `after` hook will fail with a timeout.\n ac.abort();\n callback();\n },\n });\n\n await assert.isRejected(pipeline(stream, writable, { signal: ac.signal }));\n assert.lengthOf(rows, 1);\n });\n });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"pool.test.js","sourceRoot":"","sources":["../src/pool.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { Writable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\n\nimport { use as chaiUse, assert } from 'chai';\nimport chaiAsPromised from 'chai-as-promised';\nimport { z, ZodError } from 'zod';\n\nimport {\n queryAsync,\n queryRows,\n queryRow,\n queryOptionalRow,\n callRows,\n callRow,\n callOptionalRow,\n queryCursor,\n queryValidatedCursor,\n} from './default-pool.js';\nimport { makePostgresTestUtils } from './test-utils.js';\n\nchaiUse(chaiAsPromised);\n\nconst postgresTestUtils = makePostgresTestUtils({\n database: 'prairielearn_postgres',\n});\n\nconst WorkspaceSchema = z.object({\n id: z.string(),\n created_at: z.date(),\n});\n\nconst SprocTwoColumnsSchema = z.object({\n id: z.string(),\n negative: z.number(),\n});\n\ndescribe('@prairielearn/postgres', function () {\n before(async () => {\n await postgresTestUtils.createDatabase();\n await queryAsync(\n 'CREATE TABLE workspaces (id BIGSERIAL PRIMARY KEY, created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP);',\n {},\n );\n await queryAsync('INSERT INTO workspaces (id) SELECT s FROM generate_series(1, 100) AS s', {});\n await queryAsync(\n 'CREATE FUNCTION test_sproc_one_column(num_entries INT) RETURNS TABLE (id BIGINT) AS $$ BEGIN RETURN QUERY SELECT s::BIGINT AS id FROM generate_series(1, num_entries) AS s; END; $$ LANGUAGE plpgsql;',\n {},\n );\n await queryAsync(\n 'CREATE FUNCTION test_sproc_two_columns(num_entries INT) RETURNS TABLE (id BIGINT, negative INT) AS $$ BEGIN RETURN QUERY SELECT s::BIGINT AS id, -s AS negative FROM generate_series(1, num_entries) AS s; END; $$ LANGUAGE plpgsql;',\n {},\n );\n await queryAsync(\n 'CREATE FUNCTION test_sproc_one_column_ten_rows() RETURNS TABLE (id BIGINT) AS $$ BEGIN RETURN QUERY SELECT s::BIGINT AS id FROM generate_series(1, 10) AS s; END; $$ LANGUAGE plpgsql;',\n {},\n );\n await queryAsync(\n 'CREATE FUNCTION test_sproc_one_column_one_row(OUT id BIGINT) AS $$ BEGIN id = 1; END; $$ LANGUAGE plpgsql;',\n {},\n );\n });\n\n after(async () => {\n await postgresTestUtils.dropDatabase();\n });\n\n describe('paramsToArray', () => {\n it('enforces SQL must be a string', async () => {\n // @ts-expect-error SQL must be a string\n const rows = queryAsync({ invalid: true }, {});\n await assert.isRejected(rows, 'SQL must be a string');\n });\n\n it('enforces params must be array or object', async () => {\n // @ts-expect-error params must be an array or object\n const rows = queryAsync('SELECT 33;', 33);\n await assert.isRejected(rows, 'params must be array or object');\n });\n\n it('rejects missing parameters', async () => {\n const rows = queryAsync('SELECT $missing;', {});\n await assert.isRejected(rows, 'Missing parameter');\n });\n\n it('rejects unused parameters in testing', async () => {\n const rows = queryAsync('SELECT 33;', { unsed_parameter: true });\n await assert.isRejected(rows, 'Unused parameter');\n });\n });\n\n describe('queryRows', () => {\n it('handles single column', async () => {\n const rows = await queryRows('SELECT id FROM workspaces WHERE id <= 10;', z.string());\n assert.lengthOf(rows, 10);\n assert.equal(rows[0], '1');\n });\n\n it('handles multiple columns', async () => {\n const rows = await queryRows('SELECT * FROM workspaces WHERE id <= 10;', WorkspaceSchema);\n assert.lengthOf(rows, 10);\n assert.equal(rows[0].id, '1');\n assert.isNotNull(rows[0].created_at);\n });\n\n it('handles parameters', async () => {\n const rows = await queryRows(\n 'SELECT * FROM workspaces WHERE id <= $1;',\n [10],\n WorkspaceSchema,\n );\n assert.lengthOf(rows, 10);\n });\n });\n\n describe('queryRow', () => {\n it('handles single column', async () => {\n const row = await queryRow('SELECT id FROM workspaces WHERE id = 1;', z.string());\n assert.equal(row, '1');\n });\n\n it('handles multiple columns', async () => {\n const row = await queryRow('SELECT * FROM workspaces WHERE id = 1;', WorkspaceSchema);\n assert.equal(row.id, '1');\n assert.isNotNull(row.created_at);\n });\n\n it('handles parameters', async () => {\n const row = await queryRow('SELECT * FROM workspaces WHERE id = $1;', [1], WorkspaceSchema);\n assert.equal(row.id, '1');\n });\n\n it('rejects results with zero rows', async () => {\n const rows = queryRow('SELECT * FROM workspaces WHERE id = -1;', WorkspaceSchema);\n await assert.isRejected(rows, 'Incorrect rowCount: 0');\n });\n\n it('rejects results with multiple rows', async () => {\n const rows = queryRow('SELECT * FROM workspaces', WorkspaceSchema);\n await assert.isRejected(rows, 'Incorrect rowCount: 100');\n });\n });\n\n describe('queryOptionalRow', () => {\n it('handles single column', async () => {\n const row = await queryRow('SELECT id FROM workspaces WHERE id = 1;', z.string());\n assert.equal(row, '1');\n });\n\n it('handles multiple columns', async () => {\n const row = await queryOptionalRow('SELECT * FROM workspaces WHERE id = 1;', WorkspaceSchema);\n assert.isNotNull(row);\n assert.equal(row?.id, '1');\n assert.isNotNull(row?.created_at);\n });\n\n it('handles parameters', async () => {\n const row = await queryOptionalRow(\n 'SELECT * FROM workspaces WHERE id = $1;',\n [1],\n WorkspaceSchema,\n );\n assert.isNotNull(row);\n assert.equal(row?.id, '1');\n });\n\n it('handles missing result', async () => {\n const row = await queryOptionalRow(\n 'SELECT * FROM workspaces WHERE id = -1;',\n WorkspaceSchema,\n );\n assert.isNull(row);\n });\n\n it('rejects with multiple rows', async () => {\n const rows = queryOptionalRow('SELECT * FROM workspaces', WorkspaceSchema);\n await assert.isRejected(rows, 'Incorrect rowCount: 100');\n });\n });\n\n describe('callRows', () => {\n it('handles single column', async () => {\n const rows = await callRows('test_sproc_one_column_ten_rows', z.string());\n assert.lengthOf(rows, 10);\n assert.equal(rows[0], '1');\n });\n\n it('handles parameters', async () => {\n const rows = await callRows('test_sproc_one_column', [10], z.string());\n assert.lengthOf(rows, 10);\n assert.equal(rows[0], '1');\n });\n\n it('handles multiple columns', async () => {\n const rows = await callRows('test_sproc_two_columns', [20], SprocTwoColumnsSchema);\n assert.lengthOf(rows, 20);\n assert.equal(rows[0].id, '1');\n assert.equal(rows[0].negative, -1);\n assert.equal(rows[19].id, '20');\n assert.equal(rows[19].negative, -20);\n });\n });\n\n describe('callRow', () => {\n it('handles single column', async () => {\n const row = await callRow('test_sproc_one_column_one_row', z.string());\n assert.equal(row, '1');\n });\n\n it('handles parameters', async () => {\n const row = await callRow('test_sproc_one_column', [1], z.string());\n assert.equal(row, '1');\n });\n\n it('handles multiple columns', async () => {\n const row = await callRow('test_sproc_two_columns', [1], SprocTwoColumnsSchema);\n assert.equal(row.id, '1');\n assert.equal(row.negative, -1);\n });\n\n it('rejects results with zero rows', async () => {\n const row = callRow('test_sproc_two_columns', [0], SprocTwoColumnsSchema);\n await assert.isRejected(row, 'Incorrect rowCount: 0');\n });\n\n it('rejects results with multiple rows', async () => {\n const rows = callRow('test_sproc_two_columns', [100], SprocTwoColumnsSchema);\n await assert.isRejected(rows, 'Incorrect rowCount: 100');\n });\n });\n\n describe('callOptionalRow', () => {\n it('handles single column', async () => {\n const row = await callOptionalRow('test_sproc_one_column_one_row', z.string());\n assert.equal(row, '1');\n });\n\n it('handles parameters', async () => {\n const row = await callOptionalRow('test_sproc_one_column', [1], z.string());\n assert.equal(row, '1');\n });\n\n it('handles multiple columns', async () => {\n const row = await callOptionalRow('test_sproc_two_columns', [1], SprocTwoColumnsSchema);\n assert.isNotNull(row);\n assert.equal(row?.id, '1');\n assert.equal(row?.negative, -1);\n });\n\n it('handles results with zero rows', async () => {\n const row = await callOptionalRow('test_sproc_two_columns', [0], SprocTwoColumnsSchema);\n assert.isNull(row);\n });\n\n it('rejects results with multiple rows', async () => {\n const rows = callOptionalRow('test_sproc_two_columns', [100], SprocTwoColumnsSchema);\n await assert.isRejected(rows, 'Incorrect rowCount: 100');\n });\n });\n\n describe('queryCursor', () => {\n it('returns zero rows', async () => {\n const cursor = await queryCursor('SELECT * FROM workspaces WHERE id = 10000;', {});\n const rowBatches = [];\n for await (const rows of cursor.iterate(10)) {\n rowBatches.push(rows);\n }\n assert.lengthOf(rowBatches, 0);\n });\n\n it('returns one row at a time', async () => {\n const cursor = await queryCursor('SELECT * FROM workspaces WHERE id <= 2;', {});\n const rowBatches = [];\n for await (const rows of cursor.iterate(1)) {\n rowBatches.push(rows);\n }\n assert.lengthOf(rowBatches, 2);\n assert.lengthOf(rowBatches[0], 1);\n assert.lengthOf(rowBatches[1], 1);\n });\n\n it('returns all rows at once', async () => {\n const cursor = queryCursor('SELECT * FROM workspaces WHERE id <= 10;', {});\n const rowBatches = [];\n for await (const rows of (await cursor).iterate(10)) {\n rowBatches.push(rows);\n }\n assert.lengthOf(rowBatches, 1);\n assert.lengthOf(rowBatches[0], 10);\n });\n\n it('handles errors', async () => {\n const cursor = await queryCursor('NOT VALID SQL', {});\n\n async function readAllRows() {\n const allRows = [];\n for await (const rows of cursor.iterate(10)) {\n allRows.push(...rows);\n }\n return allRows;\n }\n\n const maybeError = await readAllRows().catch((err) => err);\n assert.instanceOf(maybeError, Error);\n assert.match(maybeError.message, /syntax error/);\n assert.isDefined((maybeError as any).data);\n assert.equal((maybeError as any).data.sql, 'NOT VALID SQL');\n assert.deepEqual((maybeError as any).data.sqlParams, {});\n assert.isDefined((maybeError as any).data.sqlError);\n assert.equal((maybeError as any).data.sqlError.severity, 'ERROR');\n });\n });\n\n describe('queryValidatedCursor', () => {\n const WorkspaceSchema = z.object({\n id: z.string(),\n });\n\n const BadWorkspaceSchema = z.object({\n badProperty: z.string(),\n });\n\n describe('iterator', () => {\n it('validates with provided schema', async () => {\n const cursor = await queryValidatedCursor(\n 'SELECT * FROM workspaces WHERE id <= 10 ORDER BY id ASC;',\n {},\n WorkspaceSchema,\n );\n const allRows = [];\n for await (const rows of cursor.iterate(10)) {\n allRows.push(...rows);\n }\n assert.lengthOf(allRows, 10);\n const workspace = allRows[0] as any;\n assert.equal(workspace.id, '1');\n assert.isUndefined(workspace.state);\n });\n\n it('throws error when validation fails', async () => {\n const cursor = await queryValidatedCursor(\n 'SELECT * FROM workspaces WHERE id <= 10 ORDER BY id ASC;',\n {},\n BadWorkspaceSchema,\n );\n\n async function readAllRows() {\n const allRows = [];\n for await (const rows of cursor.iterate(10)) {\n allRows.push(...rows);\n }\n return allRows;\n }\n\n const maybeError = await readAllRows().catch((err) => err);\n assert.instanceOf(maybeError, ZodError);\n assert.lengthOf(maybeError.errors, 10);\n });\n });\n\n describe('stream', () => {\n it('validates with provided schema', async () => {\n const cursor = await queryValidatedCursor(\n 'SELECT * FROM workspaces WHERE id <= 10 ORDER BY id ASC;',\n {},\n WorkspaceSchema,\n );\n const stream = cursor.stream(1);\n const allRows = [];\n for await (const row of stream) {\n allRows.push(row);\n }\n\n assert.lengthOf(allRows, 10);\n });\n\n it('emits an error when validation fails', async () => {\n const cursor = await queryValidatedCursor(\n 'SELECT * FROM workspaces ORDER BY id ASC;',\n {},\n BadWorkspaceSchema,\n );\n const stream = cursor.stream(1);\n\n async function readAllRows() {\n const allRows = [];\n for await (const row of stream) {\n allRows.push(row);\n }\n return allRows;\n }\n\n const maybeError = await readAllRows().catch((err) => err);\n assert.instanceOf(maybeError, ZodError);\n assert.lengthOf(maybeError.errors, 1);\n });\n\n it('closes the cursor when the stream is closed', async () => {\n const cursor = await queryValidatedCursor('SELECT * FROM workspaces;', {}, WorkspaceSchema);\n const stream = cursor.stream(1);\n\n const rows: any[] = [];\n const ac = new AbortController();\n const writable = new Writable({\n objectMode: true,\n write(chunk, _encoding, callback) {\n rows.push(chunk);\n\n // After receiving the first row, abort the stream. This lets us test\n // that the underlying cursor is closed. If it is *not* closed, this\n // `after` hook will fail with a timeout.\n ac.abort();\n callback();\n },\n });\n\n await assert.isRejected(pipeline(stream, writable, { signal: ac.signal }));\n assert.lengthOf(rows, 1);\n });\n });\n });\n});\n"]}
|
package/dist/test-utils.js
CHANGED
|
@@ -30,6 +30,7 @@ async function createDatabase(options, { dropExistingDatabase = true, configureP
|
|
|
30
30
|
// Offer sensible default, but these can be overridden by `options.poolConfig`.
|
|
31
31
|
max: 10,
|
|
32
32
|
idleTimeoutMillis: 30000,
|
|
33
|
+
errorOnUnusedParameters: true,
|
|
33
34
|
...(options.poolConfig ?? {}),
|
|
34
35
|
}, (err) => {
|
|
35
36
|
throw err;
|
package/dist/test-utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import pg from 'pg';\n\nimport * as defaultPool from './default-pool.js';\n\nconst POSTGRES_USER = 'postgres';\nconst POSTGRES_HOST = 'localhost';\nconst POSTGRES_DATABASE = 'postgres';\n\nexport interface PostgresTestUtilsOptions {\n database: string;\n user?: string;\n host?: string;\n poolConfig?: Pick<pg.PoolConfig, 'max' | 'idleTimeoutMillis'>;\n defaultDatabase?: string;\n prepareAfterReset?: (client: pg.Client) => Promise<void>;\n}\n\ninterface CreateDatabaseOptions {\n dropExistingDatabase?: boolean;\n database?: string;\n templateDatabase?: string;\n configurePool?: boolean;\n prepare?: (client: pg.Client) => Promise<void>;\n}\n\ninterface DropDatabaseOptions {\n database?: string;\n force?: boolean;\n closePool?: boolean;\n}\n\nasync function createDatabase(\n options: PostgresTestUtilsOptions,\n {\n dropExistingDatabase = true,\n configurePool = true,\n database,\n templateDatabase,\n prepare,\n }: CreateDatabaseOptions = {},\n): Promise<void> {\n const client = new pg.Client({\n ...getPoolConfig(options),\n database: options.defaultDatabase ?? POSTGRES_DATABASE,\n });\n await client.connect();\n\n const escapedDatabase = client.escapeIdentifier(\n database ?? getDatabaseNameForCurrentMochaWorker(options.database),\n );\n if (dropExistingDatabase ?? true) {\n await client.query(`DROP DATABASE IF EXISTS ${escapedDatabase}`);\n }\n\n if (templateDatabase) {\n const escapedTemplateDatabase = client.escapeIdentifier(templateDatabase);\n await client.query(`CREATE DATABASE ${escapedDatabase} TEMPLATE ${escapedTemplateDatabase}`);\n } else {\n await client.query(`CREATE DATABASE ${escapedDatabase}`);\n }\n\n await client.end();\n\n await prepare?.(client);\n\n if (configurePool) {\n await defaultPool.initAsync(\n {\n user: options.user ?? POSTGRES_USER,\n host: options.host ?? POSTGRES_HOST,\n database: getDatabaseNameForCurrentMochaWorker(options.database),\n // Offer sensible default, but these can be overridden by `options.poolConfig`.\n max: 10,\n idleTimeoutMillis: 30000,\n ...(options.poolConfig ?? {}),\n },\n (err) => {\n throw err;\n },\n );\n }\n}\n\nasync function resetDatabase(options: PostgresTestUtilsOptions): Promise<void> {\n const client = new pg.Client(getPoolConfig(options));\n await client.connect();\n await client.query(`\n DO\n $func$\n BEGIN\n EXECUTE (\n SELECT 'TRUNCATE TABLE ' || string_agg(oid::regclass::text, ', ') || ' RESTART IDENTITY CASCADE'\n FROM pg_class\n WHERE relkind = 'r'\n AND relnamespace = 'public'::regnamespace\n );\n END\n $func$;\n `);\n await options.prepareAfterReset?.(client);\n await client.end();\n}\n\nasync function dropDatabase(\n options: PostgresTestUtilsOptions,\n { closePool = true, force = false, database }: DropDatabaseOptions = {},\n): Promise<void> {\n if (closePool) {\n await defaultPool.closeAsync();\n }\n\n const databaseName = database ?? getDatabaseNameForCurrentMochaWorker(options.database);\n if ('PL_KEEP_TEST_DB' in process.env && !force) {\n console.log(`PL_KEEP_TEST_DB environment variable set, not dropping database ${databaseName}`);\n return;\n }\n\n const client = new pg.Client({\n ...getPoolConfig(options),\n database: options.defaultDatabase ?? POSTGRES_DATABASE,\n });\n await client.connect();\n await client.query(`DROP DATABASE IF EXISTS ${client.escapeIdentifier(databaseName)}`);\n await client.end();\n}\n\nfunction getDatabaseNameForCurrentMochaWorker(namespace: string): string {\n const workerId = process.env.MOCHA_WORKER_ID ?? '1';\n return `${namespace}_${workerId}`;\n}\n\nfunction getPoolConfig(options: PostgresTestUtilsOptions): pg.PoolConfig {\n return {\n user: options.user ?? POSTGRES_USER,\n host: options.host ?? POSTGRES_HOST,\n database: getDatabaseNameForCurrentMochaWorker(options.database),\n };\n}\n\nexport interface PostgresTestUtils {\n createDatabase: (options?: CreateDatabaseOptions) => Promise<void>;\n resetDatabase: () => Promise<void>;\n dropDatabase: (options?: DropDatabaseOptions) => Promise<void>;\n getDatabaseNameForCurrentMochaWorker: () => string;\n getPoolConfig: () => pg.PoolConfig;\n}\n\nexport function makePostgresTestUtils(options: PostgresTestUtilsOptions): PostgresTestUtils {\n return {\n createDatabase: (createOptions?: CreateDatabaseOptions) =>\n createDatabase(options, createOptions),\n resetDatabase: () => resetDatabase(options),\n dropDatabase: (dropOptions?: DropDatabaseOptions) => dropDatabase(options, dropOptions),\n getDatabaseNameForCurrentMochaWorker: () =>\n getDatabaseNameForCurrentMochaWorker(options.database),\n getPoolConfig: () => getPoolConfig(options),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import pg from 'pg';\n\nimport * as defaultPool from './default-pool.js';\n\nconst POSTGRES_USER = 'postgres';\nconst POSTGRES_HOST = 'localhost';\nconst POSTGRES_DATABASE = 'postgres';\n\nexport interface PostgresTestUtilsOptions {\n database: string;\n user?: string;\n host?: string;\n poolConfig?: Pick<pg.PoolConfig, 'max' | 'idleTimeoutMillis'>;\n defaultDatabase?: string;\n prepareAfterReset?: (client: pg.Client) => Promise<void>;\n}\n\ninterface CreateDatabaseOptions {\n dropExistingDatabase?: boolean;\n database?: string;\n templateDatabase?: string;\n configurePool?: boolean;\n prepare?: (client: pg.Client) => Promise<void>;\n}\n\ninterface DropDatabaseOptions {\n database?: string;\n force?: boolean;\n closePool?: boolean;\n}\n\nasync function createDatabase(\n options: PostgresTestUtilsOptions,\n {\n dropExistingDatabase = true,\n configurePool = true,\n database,\n templateDatabase,\n prepare,\n }: CreateDatabaseOptions = {},\n): Promise<void> {\n const client = new pg.Client({\n ...getPoolConfig(options),\n database: options.defaultDatabase ?? POSTGRES_DATABASE,\n });\n await client.connect();\n\n const escapedDatabase = client.escapeIdentifier(\n database ?? getDatabaseNameForCurrentMochaWorker(options.database),\n );\n if (dropExistingDatabase ?? true) {\n await client.query(`DROP DATABASE IF EXISTS ${escapedDatabase}`);\n }\n\n if (templateDatabase) {\n const escapedTemplateDatabase = client.escapeIdentifier(templateDatabase);\n await client.query(`CREATE DATABASE ${escapedDatabase} TEMPLATE ${escapedTemplateDatabase}`);\n } else {\n await client.query(`CREATE DATABASE ${escapedDatabase}`);\n }\n\n await client.end();\n\n await prepare?.(client);\n\n if (configurePool) {\n await defaultPool.initAsync(\n {\n user: options.user ?? POSTGRES_USER,\n host: options.host ?? POSTGRES_HOST,\n database: getDatabaseNameForCurrentMochaWorker(options.database),\n // Offer sensible default, but these can be overridden by `options.poolConfig`.\n max: 10,\n idleTimeoutMillis: 30000,\n errorOnUnusedParameters: true,\n ...(options.poolConfig ?? {}),\n },\n (err) => {\n throw err;\n },\n );\n }\n}\n\nasync function resetDatabase(options: PostgresTestUtilsOptions): Promise<void> {\n const client = new pg.Client(getPoolConfig(options));\n await client.connect();\n await client.query(`\n DO\n $func$\n BEGIN\n EXECUTE (\n SELECT 'TRUNCATE TABLE ' || string_agg(oid::regclass::text, ', ') || ' RESTART IDENTITY CASCADE'\n FROM pg_class\n WHERE relkind = 'r'\n AND relnamespace = 'public'::regnamespace\n );\n END\n $func$;\n `);\n await options.prepareAfterReset?.(client);\n await client.end();\n}\n\nasync function dropDatabase(\n options: PostgresTestUtilsOptions,\n { closePool = true, force = false, database }: DropDatabaseOptions = {},\n): Promise<void> {\n if (closePool) {\n await defaultPool.closeAsync();\n }\n\n const databaseName = database ?? getDatabaseNameForCurrentMochaWorker(options.database);\n if ('PL_KEEP_TEST_DB' in process.env && !force) {\n console.log(`PL_KEEP_TEST_DB environment variable set, not dropping database ${databaseName}`);\n return;\n }\n\n const client = new pg.Client({\n ...getPoolConfig(options),\n database: options.defaultDatabase ?? POSTGRES_DATABASE,\n });\n await client.connect();\n await client.query(`DROP DATABASE IF EXISTS ${client.escapeIdentifier(databaseName)}`);\n await client.end();\n}\n\nfunction getDatabaseNameForCurrentMochaWorker(namespace: string): string {\n const workerId = process.env.MOCHA_WORKER_ID ?? '1';\n return `${namespace}_${workerId}`;\n}\n\nfunction getPoolConfig(options: PostgresTestUtilsOptions): pg.PoolConfig {\n return {\n user: options.user ?? POSTGRES_USER,\n host: options.host ?? POSTGRES_HOST,\n database: getDatabaseNameForCurrentMochaWorker(options.database),\n };\n}\n\nexport interface PostgresTestUtils {\n createDatabase: (options?: CreateDatabaseOptions) => Promise<void>;\n resetDatabase: () => Promise<void>;\n dropDatabase: (options?: DropDatabaseOptions) => Promise<void>;\n getDatabaseNameForCurrentMochaWorker: () => string;\n getPoolConfig: () => pg.PoolConfig;\n}\n\nexport function makePostgresTestUtils(options: PostgresTestUtilsOptions): PostgresTestUtils {\n return {\n createDatabase: (createOptions?: CreateDatabaseOptions) =>\n createDatabase(options, createOptions),\n resetDatabase: () => resetDatabase(options),\n dropDatabase: (dropOptions?: DropDatabaseOptions) => dropDatabase(options, dropOptions),\n getDatabaseNameForCurrentMochaWorker: () =>\n getDatabaseNameForCurrentMochaWorker(options.database),\n getPoolConfig: () => getPoolConfig(options),\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prairielearn/postgres",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -11,27 +11,40 @@
|
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "tsc",
|
|
13
13
|
"dev": "tsc --watch --preserveWatchOutput",
|
|
14
|
-
"test": "mocha src/**/*.test.ts"
|
|
14
|
+
"test": "c8 mocha src/**/*.test.ts"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@types/debug": "^4.1.12",
|
|
18
|
+
"@types/lodash": "^4.17.1",
|
|
19
|
+
"@types/pg-cursor": "^2.7.2",
|
|
20
|
+
"multipipe": "^4.0.0",
|
|
21
|
+
"pg": "^8.11.5",
|
|
22
|
+
"pg-cursor": "^2.10.5",
|
|
23
|
+
"pg-pool": "^3.6.2",
|
|
24
|
+
"pg-protocol": "^1.6.1",
|
|
25
|
+
"zod": "^3.23.8"
|
|
15
26
|
},
|
|
16
27
|
"devDependencies": {
|
|
17
28
|
"@prairielearn/tsconfig": "^0.0.0",
|
|
18
29
|
"@types/mocha": "^10.0.6",
|
|
19
30
|
"@types/multipipe": "^3.0.5",
|
|
20
|
-
"@types/node": "^20.12.
|
|
21
|
-
"
|
|
22
|
-
"chai
|
|
31
|
+
"@types/node": "^20.12.11",
|
|
32
|
+
"c8": "^9.1.0",
|
|
33
|
+
"chai": "^5.1.1",
|
|
34
|
+
"chai-as-promised": "^7.1.2",
|
|
23
35
|
"mocha": "^10.4.0",
|
|
24
|
-
"tsx": "^4.
|
|
25
|
-
"typescript": "^5.4.
|
|
36
|
+
"tsx": "^4.10.4",
|
|
37
|
+
"typescript": "^5.4.5"
|
|
26
38
|
},
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
39
|
+
"c8": {
|
|
40
|
+
"reporter": [
|
|
41
|
+
"html",
|
|
42
|
+
"text-summary",
|
|
43
|
+
"cobertura"
|
|
44
|
+
],
|
|
45
|
+
"all": true,
|
|
46
|
+
"include": [
|
|
47
|
+
"src/**"
|
|
48
|
+
]
|
|
36
49
|
}
|
|
37
50
|
}
|
package/src/default-pool.test.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { assert } from 'chai';
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import * as pgPool from './default-pool.js';
|
|
4
|
+
import { PostgresPool } from './pool.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Properties on {@link PostgresPool} that should not be available on the default
|
|
@@ -14,6 +15,7 @@ const HIDDEN_PROPERTIES = new Set([
|
|
|
14
15
|
'searchSchema',
|
|
15
16
|
'_queryCount',
|
|
16
17
|
'queryValidatedCursorInternal',
|
|
18
|
+
'errorOnUnusedParameters',
|
|
17
19
|
// Getters
|
|
18
20
|
'totalCount',
|
|
19
21
|
'idleCount',
|
package/src/index.ts
CHANGED
package/src/pool.test.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import chai from 'chai';
|
|
2
|
-
import chaiAsPromised from 'chai-as-promised';
|
|
3
1
|
import { Writable } from 'node:stream';
|
|
4
2
|
import { pipeline } from 'node:stream/promises';
|
|
3
|
+
|
|
4
|
+
import { use as chaiUse, assert } from 'chai';
|
|
5
|
+
import chaiAsPromised from 'chai-as-promised';
|
|
5
6
|
import { z, ZodError } from 'zod';
|
|
6
7
|
|
|
7
8
|
import {
|
|
@@ -17,8 +18,7 @@ import {
|
|
|
17
18
|
} from './default-pool.js';
|
|
18
19
|
import { makePostgresTestUtils } from './test-utils.js';
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
const { assert } = chai;
|
|
21
|
+
chaiUse(chaiAsPromised);
|
|
22
22
|
|
|
23
23
|
const postgresTestUtils = makePostgresTestUtils({
|
|
24
24
|
database: 'prairielearn_postgres',
|
|
@@ -64,6 +64,30 @@ describe('@prairielearn/postgres', function () {
|
|
|
64
64
|
await postgresTestUtils.dropDatabase();
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
+
describe('paramsToArray', () => {
|
|
68
|
+
it('enforces SQL must be a string', async () => {
|
|
69
|
+
// @ts-expect-error SQL must be a string
|
|
70
|
+
const rows = queryAsync({ invalid: true }, {});
|
|
71
|
+
await assert.isRejected(rows, 'SQL must be a string');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('enforces params must be array or object', async () => {
|
|
75
|
+
// @ts-expect-error params must be an array or object
|
|
76
|
+
const rows = queryAsync('SELECT 33;', 33);
|
|
77
|
+
await assert.isRejected(rows, 'params must be array or object');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('rejects missing parameters', async () => {
|
|
81
|
+
const rows = queryAsync('SELECT $missing;', {});
|
|
82
|
+
await assert.isRejected(rows, 'Missing parameter');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('rejects unused parameters in testing', async () => {
|
|
86
|
+
const rows = queryAsync('SELECT 33;', { unsed_parameter: true });
|
|
87
|
+
await assert.isRejected(rows, 'Unused parameter');
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
67
91
|
describe('queryRows', () => {
|
|
68
92
|
it('handles single column', async () => {
|
|
69
93
|
const rows = await queryRows('SELECT id FROM workspaces WHERE id <= 10;', z.string());
|
|
@@ -265,7 +289,7 @@ describe('@prairielearn/postgres', function () {
|
|
|
265
289
|
});
|
|
266
290
|
|
|
267
291
|
it('handles errors', async () => {
|
|
268
|
-
const cursor = await queryCursor('NOT VALID SQL', {
|
|
292
|
+
const cursor = await queryCursor('NOT VALID SQL', {});
|
|
269
293
|
|
|
270
294
|
async function readAllRows() {
|
|
271
295
|
const allRows = [];
|
|
@@ -278,11 +302,11 @@ describe('@prairielearn/postgres', function () {
|
|
|
278
302
|
const maybeError = await readAllRows().catch((err) => err);
|
|
279
303
|
assert.instanceOf(maybeError, Error);
|
|
280
304
|
assert.match(maybeError.message, /syntax error/);
|
|
281
|
-
assert.isDefined(maybeError.data);
|
|
282
|
-
assert.equal(maybeError.data.sql, 'NOT VALID SQL');
|
|
283
|
-
assert.deepEqual(maybeError.data.sqlParams, {
|
|
284
|
-
assert.isDefined(maybeError.data.sqlError);
|
|
285
|
-
assert.equal(maybeError.data.sqlError.severity, 'ERROR');
|
|
305
|
+
assert.isDefined((maybeError as any).data);
|
|
306
|
+
assert.equal((maybeError as any).data.sql, 'NOT VALID SQL');
|
|
307
|
+
assert.deepEqual((maybeError as any).data.sqlParams, {});
|
|
308
|
+
assert.isDefined((maybeError as any).data.sqlError);
|
|
309
|
+
assert.equal((maybeError as any).data.sqlError.severity, 'ERROR');
|
|
286
310
|
});
|
|
287
311
|
});
|
|
288
312
|
|
package/src/pool.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { Readable, Transform } from 'node:stream';
|
|
3
|
+
import { callbackify } from 'node:util';
|
|
4
|
+
|
|
5
|
+
import debugfn from 'debug';
|
|
1
6
|
import _ from 'lodash';
|
|
7
|
+
import multipipe from 'multipipe';
|
|
2
8
|
import pg, { QueryResult } from 'pg';
|
|
3
9
|
import Cursor from 'pg-cursor';
|
|
4
|
-
import
|
|
5
|
-
import { callbackify } from 'node:util';
|
|
6
|
-
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
10
|
+
import { DatabaseError } from 'pg-protocol';
|
|
7
11
|
import { z } from 'zod';
|
|
8
|
-
import { Readable, Transform } from 'node:stream';
|
|
9
|
-
import multipipe from 'multipipe';
|
|
10
12
|
|
|
11
13
|
export type QueryParams = Record<string, any> | any[];
|
|
12
14
|
|
|
@@ -15,6 +17,10 @@ export interface CursorIterator<T> {
|
|
|
15
17
|
stream: (batchSize: number) => NodeJS.ReadWriteStream;
|
|
16
18
|
}
|
|
17
19
|
|
|
20
|
+
export interface PostgresPoolConfig extends pg.PoolConfig {
|
|
21
|
+
errorOnUnusedParameters?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
18
24
|
const debug = debugfn('@prairielearn/postgres');
|
|
19
25
|
const lastQueryMap = new WeakMap<pg.PoolClient, string>();
|
|
20
26
|
const searchSchemaMap = new WeakMap<pg.PoolClient, string>();
|
|
@@ -68,6 +74,7 @@ function debugParams(params: QueryParams): string {
|
|
|
68
74
|
function paramsToArray(
|
|
69
75
|
sql: string,
|
|
70
76
|
params: QueryParams,
|
|
77
|
+
errorOnUnusedParameters: boolean,
|
|
71
78
|
): { processedSql: string; paramsArray: any } {
|
|
72
79
|
if (typeof sql !== 'string') throw new Error('SQL must be a string');
|
|
73
80
|
if (Array.isArray(params)) {
|
|
@@ -87,9 +94,9 @@ function paramsToArray(
|
|
|
87
94
|
let paramsArray: any[] = [];
|
|
88
95
|
while ((result = re.exec(remainingSql)) !== null) {
|
|
89
96
|
const v = result[1];
|
|
90
|
-
if (!
|
|
91
|
-
if (!
|
|
92
|
-
if (
|
|
97
|
+
if (!(v in map)) {
|
|
98
|
+
if (!(v in params)) throw new Error(`Missing parameter: ${v}`);
|
|
99
|
+
if (Array.isArray(params[v])) {
|
|
93
100
|
map[v] =
|
|
94
101
|
'ARRAY[' +
|
|
95
102
|
_.map(_.range(nParams + 1, nParams + params[v].length + 1), function (n) {
|
|
@@ -109,6 +116,12 @@ function paramsToArray(
|
|
|
109
116
|
}
|
|
110
117
|
processedSql += remainingSql;
|
|
111
118
|
remainingSql = '';
|
|
119
|
+
if (errorOnUnusedParameters) {
|
|
120
|
+
const difference = _.difference(Object.keys(params), Object.keys(map));
|
|
121
|
+
if (difference.length) {
|
|
122
|
+
throw new Error(`Unused parameters in SQL query: ${JSON.stringify(difference)}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
112
125
|
return { processedSql, paramsArray };
|
|
113
126
|
}
|
|
114
127
|
|
|
@@ -133,9 +146,14 @@ function enhanceError(err: Error, sql: string, params: QueryParams): Error {
|
|
|
133
146
|
// the error object.
|
|
134
147
|
sqlError.message = err.message;
|
|
135
148
|
|
|
149
|
+
const errorHasPosition = err instanceof DatabaseError && err.position != null;
|
|
150
|
+
|
|
136
151
|
return addDataToError(err, {
|
|
137
152
|
sqlError,
|
|
138
|
-
|
|
153
|
+
// If the error has a `position` field, we need to use the processed source
|
|
154
|
+
// (where e.g. `$foobar` has been replaced with `$1`) so that the position
|
|
155
|
+
// is accurate.
|
|
156
|
+
sql: errorHasPosition ? paramsToArray(sql, params, false).processedSql : sql,
|
|
139
157
|
sqlParams: params,
|
|
140
158
|
});
|
|
141
159
|
}
|
|
@@ -153,14 +171,16 @@ export class PostgresPool {
|
|
|
153
171
|
private searchSchema: string | null = null;
|
|
154
172
|
/** Tracks the total number of queries executed by this pool. */
|
|
155
173
|
private _queryCount = 0;
|
|
174
|
+
private errorOnUnusedParameters = false;
|
|
156
175
|
|
|
157
176
|
/**
|
|
158
177
|
* Creates a new connection pool and attempts to connect to the database.
|
|
159
178
|
*/
|
|
160
179
|
async initAsync(
|
|
161
|
-
pgConfig:
|
|
180
|
+
pgConfig: PostgresPoolConfig,
|
|
162
181
|
idleErrorHandler: (error: Error, client: pg.PoolClient) => void,
|
|
163
182
|
): Promise<void> {
|
|
183
|
+
this.errorOnUnusedParameters = pgConfig.errorOnUnusedParameters ?? false;
|
|
164
184
|
this.pool = new pg.Pool(pgConfig);
|
|
165
185
|
this.pool.on('error', function (err, client) {
|
|
166
186
|
const lastQuery = lastQueryMap.get(client);
|
|
@@ -293,7 +313,7 @@ export class PostgresPool {
|
|
|
293
313
|
this._queryCount += 1;
|
|
294
314
|
debug('queryWithClient()', 'sql:', debugString(sql));
|
|
295
315
|
debug('queryWithClient()', 'params:', debugParams(params));
|
|
296
|
-
const { processedSql, paramsArray } = paramsToArray(sql, params);
|
|
316
|
+
const { processedSql, paramsArray } = paramsToArray(sql, params, this.errorOnUnusedParameters);
|
|
297
317
|
try {
|
|
298
318
|
lastQueryMap.set(client, processedSql);
|
|
299
319
|
const result = await client.query(processedSql, paramsArray);
|
|
@@ -1018,7 +1038,7 @@ export class PostgresPool {
|
|
|
1018
1038
|
this._queryCount += 1;
|
|
1019
1039
|
debug('queryCursorWithClient()', 'sql:', debugString(sql));
|
|
1020
1040
|
debug('queryCursorWithClient()', 'params:', debugParams(params));
|
|
1021
|
-
const { processedSql, paramsArray } = paramsToArray(sql, params);
|
|
1041
|
+
const { processedSql, paramsArray } = paramsToArray(sql, params, this.errorOnUnusedParameters);
|
|
1022
1042
|
lastQueryMap.set(client, processedSql);
|
|
1023
1043
|
return client.query(new Cursor(processedSql, paramsArray));
|
|
1024
1044
|
}
|
package/src/test-utils.ts
CHANGED