@prairielearn/postgres 5.0.3 → 6.0.1

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/dist/pool.test.js CHANGED
@@ -2,7 +2,7 @@ import { Writable } from 'node:stream';
2
2
  import { pipeline } from 'node:stream/promises';
3
3
  import { afterAll, assert, beforeAll, describe, expect, it } from 'vitest';
4
4
  import { ZodError, z } from 'zod';
5
- import { callOptionalRow, callRow, callRows, execute, queryAsync, queryCursor, queryOptionalRow, queryRow, queryRows, } from './default-pool.js';
5
+ import { callOptionalRow, callOptionalScalar, callRow, callRows, callScalar, callScalars, execute, queryCursor, queryOptionalRow, queryOptionalScalar, queryRow, queryRows, queryScalar, queryScalars, } from './default-pool.js';
6
6
  import { makePostgresTestUtils } from './test-utils.js';
7
7
  const postgresTestUtils = makePostgresTestUtils({
8
8
  database: 'prairielearn_postgres',
@@ -31,28 +31,28 @@ describe('@prairielearn/postgres', function () {
31
31
  describe('paramsToArray', () => {
32
32
  it('enforces SQL must be a string', async () => {
33
33
  // @ts-expect-error SQL must be a string
34
- const rows = queryAsync({ invalid: true }, {});
34
+ const rows = execute({ invalid: true }, {});
35
35
  await expect(rows).rejects.toThrow('SQL must be a string');
36
36
  });
37
37
  it('enforces params must be array or object', async () => {
38
38
  // @ts-expect-error params must be an array or object
39
- const rows = queryAsync('SELECT 33;', 33);
39
+ const rows = execute('SELECT 33;', 33);
40
40
  await expect(rows).rejects.toThrow('params must be array or object');
41
41
  });
42
42
  it('rejects missing parameters', async () => {
43
- const rows = queryAsync('SELECT $missing;', {});
43
+ const rows = execute('SELECT $missing;', {});
44
44
  await expect(rows).rejects.toThrow('Missing parameter');
45
45
  });
46
46
  it('rejects unused parameters in testing', async () => {
47
- const rows = queryAsync('SELECT 33;', { unsed_parameter: true });
47
+ const rows = execute('SELECT 33;', { unsed_parameter: true });
48
48
  await expect(rows).rejects.toThrow('Unused parameter');
49
49
  });
50
50
  });
51
51
  describe('queryRows', () => {
52
52
  it('handles single column', async () => {
53
- const rows = await queryRows('SELECT id FROM workspaces WHERE id <= 10;', z.string());
53
+ const rows = await queryRows('SELECT id FROM workspaces WHERE id <= 10;', z.object({ id: z.string() }));
54
54
  assert.lengthOf(rows, 10);
55
- assert.equal(rows[0], '1');
55
+ assert.equal(rows[0].id, '1');
56
56
  });
57
57
  it('handles multiple columns', async () => {
58
58
  const rows = await queryRows('SELECT * FROM workspaces WHERE id <= 10;', WorkspaceSchema);
@@ -67,8 +67,8 @@ describe('@prairielearn/postgres', function () {
67
67
  });
68
68
  describe('queryRow', () => {
69
69
  it('handles single column', async () => {
70
- const row = await queryRow('SELECT id FROM workspaces WHERE id = 1;', z.string());
71
- assert.equal(row, '1');
70
+ const row = await queryRow('SELECT id FROM workspaces WHERE id = 1;', z.object({ id: z.string() }));
71
+ assert.equal(row.id, '1');
72
72
  });
73
73
  it('handles multiple columns', async () => {
74
74
  const row = await queryRow('SELECT * FROM workspaces WHERE id = 1;', WorkspaceSchema);
@@ -90,8 +90,8 @@ describe('@prairielearn/postgres', function () {
90
90
  });
91
91
  describe('queryOptionalRow', () => {
92
92
  it('handles single column', async () => {
93
- const row = await queryRow('SELECT id FROM workspaces WHERE id = 1;', z.string());
94
- assert.equal(row, '1');
93
+ const row = await queryRow('SELECT id FROM workspaces WHERE id = 1;', z.object({ id: z.string() }));
94
+ assert.equal(row.id, '1');
95
95
  });
96
96
  it('handles multiple columns', async () => {
97
97
  const row = await queryOptionalRow('SELECT * FROM workspaces WHERE id = 1;', WorkspaceSchema);
@@ -115,14 +115,14 @@ describe('@prairielearn/postgres', function () {
115
115
  });
116
116
  describe('callRows', () => {
117
117
  it('handles single column', async () => {
118
- const rows = await callRows('test_sproc_one_column_ten_rows', z.string());
118
+ const rows = await callRows('test_sproc_one_column_ten_rows', z.object({ id: z.string() }));
119
119
  assert.lengthOf(rows, 10);
120
- assert.equal(rows[0], '1');
120
+ assert.equal(rows[0].id, '1');
121
121
  });
122
122
  it('handles parameters', async () => {
123
- const rows = await callRows('test_sproc_one_column', [10], z.string());
123
+ const rows = await callRows('test_sproc_one_column', [10], z.object({ id: z.string() }));
124
124
  assert.lengthOf(rows, 10);
125
- assert.equal(rows[0], '1');
125
+ assert.equal(rows[0].id, '1');
126
126
  });
127
127
  it('handles multiple columns', async () => {
128
128
  const rows = await callRows('test_sproc_two_columns', [20], SprocTwoColumnsSchema);
@@ -135,12 +135,12 @@ describe('@prairielearn/postgres', function () {
135
135
  });
136
136
  describe('callRow', () => {
137
137
  it('handles single column', async () => {
138
- const row = await callRow('test_sproc_one_column_one_row', z.string());
139
- assert.equal(row, '1');
138
+ const row = await callRow('test_sproc_one_column_one_row', z.object({ id: z.string() }));
139
+ assert.equal(row.id, '1');
140
140
  });
141
141
  it('handles parameters', async () => {
142
- const row = await callRow('test_sproc_one_column', [1], z.string());
143
- assert.equal(row, '1');
142
+ const row = await callRow('test_sproc_one_column', [1], z.object({ id: z.string() }));
143
+ assert.equal(row.id, '1');
144
144
  });
145
145
  it('handles multiple columns', async () => {
146
146
  const row = await callRow('test_sproc_two_columns', [1], SprocTwoColumnsSchema);
@@ -158,12 +158,12 @@ describe('@prairielearn/postgres', function () {
158
158
  });
159
159
  describe('callOptionalRow', () => {
160
160
  it('handles single column', async () => {
161
- const row = await callOptionalRow('test_sproc_one_column_one_row', z.string());
162
- assert.equal(row, '1');
161
+ const row = await callOptionalRow('test_sproc_one_column_one_row', z.object({ id: z.string() }));
162
+ assert.equal(row?.id, '1');
163
163
  });
164
164
  it('handles parameters', async () => {
165
- const row = await callOptionalRow('test_sproc_one_column', [1], z.string());
166
- assert.equal(row, '1');
165
+ const row = await callOptionalRow('test_sproc_one_column', [1], z.object({ id: z.string() }));
166
+ assert.equal(row?.id, '1');
167
167
  });
168
168
  it('handles multiple columns', async () => {
169
169
  const row = await callOptionalRow('test_sproc_two_columns', [1], SprocTwoColumnsSchema);
@@ -180,14 +180,133 @@ describe('@prairielearn/postgres', function () {
180
180
  await expect(rows).rejects.toThrow('Incorrect rowCount: 100');
181
181
  });
182
182
  });
183
+ describe('queryScalars', () => {
184
+ it('returns all scalar values', async () => {
185
+ const ids = await queryScalars('SELECT id FROM workspaces WHERE id <= 10 ORDER BY id ASC;', z.string());
186
+ assert.lengthOf(ids, 10);
187
+ assert.equal(ids[0], '1');
188
+ assert.equal(ids[9], '10');
189
+ });
190
+ it('handles parameters', async () => {
191
+ const ids = await queryScalars('SELECT id FROM workspaces WHERE id <= $1 ORDER BY id ASC;', [5], z.string());
192
+ assert.lengthOf(ids, 5);
193
+ });
194
+ it('rejects multi-column queries', async () => {
195
+ const result = queryScalars('SELECT * FROM workspaces WHERE id <= 10;', z.string());
196
+ await expect(result).rejects.toThrow('Expected exactly one column');
197
+ });
198
+ });
199
+ describe('queryScalar', () => {
200
+ it('returns a single scalar value', async () => {
201
+ const id = await queryScalar('SELECT id FROM workspaces WHERE id = 1;', z.string());
202
+ assert.equal(id, '1');
203
+ });
204
+ it('handles parameters', async () => {
205
+ const id = await queryScalar('SELECT id FROM workspaces WHERE id = $1;', [1], z.string());
206
+ assert.equal(id, '1');
207
+ });
208
+ it('rejects results with zero rows', async () => {
209
+ const result = queryScalar('SELECT id FROM workspaces WHERE id = -1;', z.string());
210
+ await expect(result).rejects.toThrow('Incorrect rowCount: 0');
211
+ });
212
+ it('rejects results with multiple rows', async () => {
213
+ const result = queryScalar('SELECT id FROM workspaces;', z.string());
214
+ await expect(result).rejects.toThrow('Incorrect rowCount: 100');
215
+ });
216
+ it('rejects multi-column queries', async () => {
217
+ const result = queryScalar('SELECT * FROM workspaces WHERE id = 1;', z.string());
218
+ await expect(result).rejects.toThrow('Expected exactly one column');
219
+ });
220
+ });
221
+ describe('queryOptionalScalar', () => {
222
+ it('returns a scalar value when present', async () => {
223
+ const id = await queryOptionalScalar('SELECT id FROM workspaces WHERE id = 1;', z.string());
224
+ assert.equal(id, '1');
225
+ });
226
+ it('handles parameters', async () => {
227
+ const id = await queryOptionalScalar('SELECT id FROM workspaces WHERE id = $1;', [1], z.string());
228
+ assert.equal(id, '1');
229
+ });
230
+ it('returns null for zero rows', async () => {
231
+ const id = await queryOptionalScalar('SELECT id FROM workspaces WHERE id = -1;', z.string());
232
+ assert.isNull(id);
233
+ });
234
+ it('rejects results with multiple rows', async () => {
235
+ const result = queryOptionalScalar('SELECT id FROM workspaces;', z.string());
236
+ await expect(result).rejects.toThrow('Incorrect rowCount: 100');
237
+ });
238
+ it('rejects multi-column queries', async () => {
239
+ const result = queryOptionalScalar('SELECT * FROM workspaces WHERE id = 1;', z.string());
240
+ await expect(result).rejects.toThrow('Expected exactly one column');
241
+ });
242
+ });
243
+ describe('callScalars', () => {
244
+ it('returns all scalar values', async () => {
245
+ const ids = await callScalars('test_sproc_one_column', [10], z.string());
246
+ assert.lengthOf(ids, 10);
247
+ assert.equal(ids[0], '1');
248
+ });
249
+ it('handles no parameters', async () => {
250
+ const ids = await callScalars('test_sproc_one_column_ten_rows', z.string());
251
+ assert.lengthOf(ids, 10);
252
+ });
253
+ it('rejects multi-column sprocs', async () => {
254
+ const result = callScalars('test_sproc_two_columns', [10], z.string());
255
+ await expect(result).rejects.toThrow('Expected exactly one column');
256
+ });
257
+ });
258
+ describe('callScalar', () => {
259
+ it('returns a single scalar value', async () => {
260
+ const id = await callScalar('test_sproc_one_column_one_row', z.string());
261
+ assert.equal(id, '1');
262
+ });
263
+ it('handles parameters', async () => {
264
+ const id = await callScalar('test_sproc_one_column', [1], z.string());
265
+ assert.equal(id, '1');
266
+ });
267
+ it('rejects results with zero rows', async () => {
268
+ const result = callScalar('test_sproc_one_column', [0], z.string());
269
+ await expect(result).rejects.toThrow('Incorrect rowCount: 0');
270
+ });
271
+ it('rejects results with multiple rows', async () => {
272
+ const result = callScalar('test_sproc_one_column', [100], z.string());
273
+ await expect(result).rejects.toThrow('Incorrect rowCount: 100');
274
+ });
275
+ it('rejects multi-column sprocs', async () => {
276
+ const result = callScalar('test_sproc_two_columns', [1], z.string());
277
+ await expect(result).rejects.toThrow('Expected exactly one column');
278
+ });
279
+ });
280
+ describe('callOptionalScalar', () => {
281
+ it('returns a scalar value when present', async () => {
282
+ const id = await callOptionalScalar('test_sproc_one_column_one_row', z.string());
283
+ assert.equal(id, '1');
284
+ });
285
+ it('handles parameters', async () => {
286
+ const id = await callOptionalScalar('test_sproc_one_column', [1], z.string());
287
+ assert.equal(id, '1');
288
+ });
289
+ it('returns null for zero rows', async () => {
290
+ const id = await callOptionalScalar('test_sproc_one_column', [0], z.string());
291
+ assert.isNull(id);
292
+ });
293
+ it('rejects results with multiple rows', async () => {
294
+ const result = callOptionalScalar('test_sproc_one_column', [100], z.string());
295
+ await expect(result).rejects.toThrow('Incorrect rowCount: 100');
296
+ });
297
+ it('rejects multi-column sprocs', async () => {
298
+ const result = callOptionalScalar('test_sproc_two_columns', [1], z.string());
299
+ await expect(result).rejects.toThrow('Expected exactly one column');
300
+ });
301
+ });
183
302
  describe('queryCursor', () => {
184
303
  it('handles single column', async () => {
185
- const cursor = await queryCursor('SELECT id FROM workspaces WHERE id = 1;', z.string());
304
+ const cursor = await queryCursor('SELECT id FROM workspaces WHERE id = 1;', z.object({ id: z.string() }));
186
305
  const allRows = [];
187
306
  for await (const rows of cursor.iterate(10)) {
188
307
  allRows.push(...rows);
189
308
  }
190
- assert.equal(allRows[0], '1');
309
+ assert.equal(allRows[0].id, '1');
191
310
  });
192
311
  it('handles multiple columns', async () => {
193
312
  const cursor = await queryCursor('SELECT * FROM workspaces WHERE id = 1;', WorkspaceSchema);
@@ -1 +1 @@
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 { afterAll, assert, beforeAll, describe, expect, it } from 'vitest';\nimport { ZodError, z } from 'zod';\n\nimport {\n callOptionalRow,\n callRow,\n callRows,\n execute,\n queryAsync,\n queryCursor,\n queryOptionalRow,\n queryRow,\n queryRows,\n} from './default-pool.js';\nimport { makePostgresTestUtils } from './test-utils.js';\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 beforeAll(async () => {\n await postgresTestUtils.createDatabase();\n await execute(\n 'CREATE TABLE workspaces (id BIGSERIAL PRIMARY KEY, created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP);',\n );\n await execute('INSERT INTO workspaces (id) SELECT s FROM generate_series(1, 100) AS s');\n await execute(\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 await execute(\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 await execute(\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 await execute(\n 'CREATE FUNCTION test_sproc_one_column_one_row(OUT id BIGINT) AS $$ BEGIN id = 1; END; $$ LANGUAGE plpgsql;',\n );\n });\n\n afterAll(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 expect(rows).rejects.toThrow('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 expect(rows).rejects.toThrow('params must be array or object');\n });\n\n it('rejects missing parameters', async () => {\n const rows = queryAsync('SELECT $missing;', {});\n await expect(rows).rejects.toThrow('Missing parameter');\n });\n\n it('rejects unused parameters in testing', async () => {\n const rows = queryAsync('SELECT 33;', { unsed_parameter: true });\n await expect(rows).rejects.toThrow('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 expect(rows).rejects.toThrow('Incorrect rowCount: 0');\n });\n\n it('rejects results with multiple rows', async () => {\n const rows = queryRow('SELECT * FROM workspaces', WorkspaceSchema);\n await expect(rows).rejects.toThrow('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 expect(rows).rejects.toThrow('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 expect(row).rejects.toThrow('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 expect(rows).rejects.toThrow('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 expect(rows).rejects.toThrow('Incorrect rowCount: 100');\n });\n });\n\n describe('queryCursor', () => {\n it('handles single column', async () => {\n const cursor = await queryCursor('SELECT id FROM workspaces WHERE id = 1;', z.string());\n const allRows: string[] = [];\n for await (const rows of cursor.iterate(10)) {\n allRows.push(...rows);\n }\n assert.equal(allRows[0], '1');\n });\n\n it('handles multiple columns', async () => {\n const cursor = await queryCursor('SELECT * FROM workspaces WHERE id = 1;', WorkspaceSchema);\n const allRows: z.infer<typeof WorkspaceSchema>[] = [];\n for await (const rows of cursor.iterate(10)) {\n allRows.push(...rows);\n }\n assert.equal(allRows[0].id, '1');\n assert.isNotNull(allRows[0].created_at);\n });\n it('returns zero rows', async () => {\n const cursor = await queryCursor('SELECT * FROM workspaces WHERE id = 10000;', z.unknown());\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;', z.unknown());\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;', z.unknown());\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', z.unknown());\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('queryCursor', () => {\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 queryCursor(\n 'SELECT * FROM workspaces WHERE id <= 10 ORDER BY id ASC;',\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 queryCursor(\n 'SELECT * FROM workspaces WHERE id <= 10 ORDER BY id ASC;',\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 queryCursor(\n 'SELECT * FROM workspaces WHERE id <= 10 ORDER BY id ASC;',\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 queryCursor(\n 'SELECT * FROM workspaces ORDER BY id ASC;',\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 queryCursor('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 expect(pipeline(stream, writable, { signal: ac.signal })).rejects.toThrow();\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 { afterAll, assert, beforeAll, describe, expect, it } from 'vitest';\nimport { ZodError, z } from 'zod';\n\nimport {\n callOptionalRow,\n callOptionalScalar,\n callRow,\n callRows,\n callScalar,\n callScalars,\n execute,\n queryCursor,\n queryOptionalRow,\n queryOptionalScalar,\n queryRow,\n queryRows,\n queryScalar,\n queryScalars,\n} from './default-pool.js';\nimport { makePostgresTestUtils } from './test-utils.js';\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 beforeAll(async () => {\n await postgresTestUtils.createDatabase();\n await execute(\n 'CREATE TABLE workspaces (id BIGSERIAL PRIMARY KEY, created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP);',\n );\n await execute('INSERT INTO workspaces (id) SELECT s FROM generate_series(1, 100) AS s');\n await execute(\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 await execute(\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 await execute(\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 await execute(\n 'CREATE FUNCTION test_sproc_one_column_one_row(OUT id BIGINT) AS $$ BEGIN id = 1; END; $$ LANGUAGE plpgsql;',\n );\n });\n\n afterAll(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 = execute({ invalid: true }, {});\n await expect(rows).rejects.toThrow('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 = execute('SELECT 33;', 33);\n await expect(rows).rejects.toThrow('params must be array or object');\n });\n\n it('rejects missing parameters', async () => {\n const rows = execute('SELECT $missing;', {});\n await expect(rows).rejects.toThrow('Missing parameter');\n });\n\n it('rejects unused parameters in testing', async () => {\n const rows = execute('SELECT 33;', { unsed_parameter: true });\n await expect(rows).rejects.toThrow('Unused parameter');\n });\n });\n\n describe('queryRows', () => {\n it('handles single column', async () => {\n const rows = await queryRows(\n 'SELECT id FROM workspaces WHERE id <= 10;',\n z.object({ id: z.string() }),\n );\n assert.lengthOf(rows, 10);\n assert.equal(rows[0].id, '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(\n 'SELECT id FROM workspaces WHERE id = 1;',\n z.object({ id: z.string() }),\n );\n assert.equal(row.id, '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 expect(rows).rejects.toThrow('Incorrect rowCount: 0');\n });\n\n it('rejects results with multiple rows', async () => {\n const rows = queryRow('SELECT * FROM workspaces', WorkspaceSchema);\n await expect(rows).rejects.toThrow('Incorrect rowCount: 100');\n });\n });\n\n describe('queryOptionalRow', () => {\n it('handles single column', async () => {\n const row = await queryRow(\n 'SELECT id FROM workspaces WHERE id = 1;',\n z.object({ id: z.string() }),\n );\n assert.equal(row.id, '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 expect(rows).rejects.toThrow('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.object({ id: z.string() }));\n assert.lengthOf(rows, 10);\n assert.equal(rows[0].id, '1');\n });\n\n it('handles parameters', async () => {\n const rows = await callRows('test_sproc_one_column', [10], z.object({ id: z.string() }));\n assert.lengthOf(rows, 10);\n assert.equal(rows[0].id, '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.object({ id: z.string() }));\n assert.equal(row.id, '1');\n });\n\n it('handles parameters', async () => {\n const row = await callRow('test_sproc_one_column', [1], z.object({ id: z.string() }));\n assert.equal(row.id, '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 expect(row).rejects.toThrow('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 expect(rows).rejects.toThrow('Incorrect rowCount: 100');\n });\n });\n\n describe('callOptionalRow', () => {\n it('handles single column', async () => {\n const row = await callOptionalRow(\n 'test_sproc_one_column_one_row',\n z.object({ id: z.string() }),\n );\n assert.equal(row?.id, '1');\n });\n\n it('handles parameters', async () => {\n const row = await callOptionalRow('test_sproc_one_column', [1], z.object({ id: z.string() }));\n assert.equal(row?.id, '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 expect(rows).rejects.toThrow('Incorrect rowCount: 100');\n });\n });\n\n describe('queryScalars', () => {\n it('returns all scalar values', async () => {\n const ids = await queryScalars(\n 'SELECT id FROM workspaces WHERE id <= 10 ORDER BY id ASC;',\n z.string(),\n );\n assert.lengthOf(ids, 10);\n assert.equal(ids[0], '1');\n assert.equal(ids[9], '10');\n });\n\n it('handles parameters', async () => {\n const ids = await queryScalars(\n 'SELECT id FROM workspaces WHERE id <= $1 ORDER BY id ASC;',\n [5],\n z.string(),\n );\n assert.lengthOf(ids, 5);\n });\n\n it('rejects multi-column queries', async () => {\n const result = queryScalars('SELECT * FROM workspaces WHERE id <= 10;', z.string());\n await expect(result).rejects.toThrow('Expected exactly one column');\n });\n });\n\n describe('queryScalar', () => {\n it('returns a single scalar value', async () => {\n const id = await queryScalar('SELECT id FROM workspaces WHERE id = 1;', z.string());\n assert.equal(id, '1');\n });\n\n it('handles parameters', async () => {\n const id = await queryScalar('SELECT id FROM workspaces WHERE id = $1;', [1], z.string());\n assert.equal(id, '1');\n });\n\n it('rejects results with zero rows', async () => {\n const result = queryScalar('SELECT id FROM workspaces WHERE id = -1;', z.string());\n await expect(result).rejects.toThrow('Incorrect rowCount: 0');\n });\n\n it('rejects results with multiple rows', async () => {\n const result = queryScalar('SELECT id FROM workspaces;', z.string());\n await expect(result).rejects.toThrow('Incorrect rowCount: 100');\n });\n\n it('rejects multi-column queries', async () => {\n const result = queryScalar('SELECT * FROM workspaces WHERE id = 1;', z.string());\n await expect(result).rejects.toThrow('Expected exactly one column');\n });\n });\n\n describe('queryOptionalScalar', () => {\n it('returns a scalar value when present', async () => {\n const id = await queryOptionalScalar('SELECT id FROM workspaces WHERE id = 1;', z.string());\n assert.equal(id, '1');\n });\n\n it('handles parameters', async () => {\n const id = await queryOptionalScalar(\n 'SELECT id FROM workspaces WHERE id = $1;',\n [1],\n z.string(),\n );\n assert.equal(id, '1');\n });\n\n it('returns null for zero rows', async () => {\n const id = await queryOptionalScalar('SELECT id FROM workspaces WHERE id = -1;', z.string());\n assert.isNull(id);\n });\n\n it('rejects results with multiple rows', async () => {\n const result = queryOptionalScalar('SELECT id FROM workspaces;', z.string());\n await expect(result).rejects.toThrow('Incorrect rowCount: 100');\n });\n\n it('rejects multi-column queries', async () => {\n const result = queryOptionalScalar('SELECT * FROM workspaces WHERE id = 1;', z.string());\n await expect(result).rejects.toThrow('Expected exactly one column');\n });\n });\n\n describe('callScalars', () => {\n it('returns all scalar values', async () => {\n const ids = await callScalars('test_sproc_one_column', [10], z.string());\n assert.lengthOf(ids, 10);\n assert.equal(ids[0], '1');\n });\n\n it('handles no parameters', async () => {\n const ids = await callScalars('test_sproc_one_column_ten_rows', z.string());\n assert.lengthOf(ids, 10);\n });\n\n it('rejects multi-column sprocs', async () => {\n const result = callScalars('test_sproc_two_columns', [10], z.string());\n await expect(result).rejects.toThrow('Expected exactly one column');\n });\n });\n\n describe('callScalar', () => {\n it('returns a single scalar value', async () => {\n const id = await callScalar('test_sproc_one_column_one_row', z.string());\n assert.equal(id, '1');\n });\n\n it('handles parameters', async () => {\n const id = await callScalar('test_sproc_one_column', [1], z.string());\n assert.equal(id, '1');\n });\n\n it('rejects results with zero rows', async () => {\n const result = callScalar('test_sproc_one_column', [0], z.string());\n await expect(result).rejects.toThrow('Incorrect rowCount: 0');\n });\n\n it('rejects results with multiple rows', async () => {\n const result = callScalar('test_sproc_one_column', [100], z.string());\n await expect(result).rejects.toThrow('Incorrect rowCount: 100');\n });\n\n it('rejects multi-column sprocs', async () => {\n const result = callScalar('test_sproc_two_columns', [1], z.string());\n await expect(result).rejects.toThrow('Expected exactly one column');\n });\n });\n\n describe('callOptionalScalar', () => {\n it('returns a scalar value when present', async () => {\n const id = await callOptionalScalar('test_sproc_one_column_one_row', z.string());\n assert.equal(id, '1');\n });\n\n it('handles parameters', async () => {\n const id = await callOptionalScalar('test_sproc_one_column', [1], z.string());\n assert.equal(id, '1');\n });\n\n it('returns null for zero rows', async () => {\n const id = await callOptionalScalar('test_sproc_one_column', [0], z.string());\n assert.isNull(id);\n });\n\n it('rejects results with multiple rows', async () => {\n const result = callOptionalScalar('test_sproc_one_column', [100], z.string());\n await expect(result).rejects.toThrow('Incorrect rowCount: 100');\n });\n\n it('rejects multi-column sprocs', async () => {\n const result = callOptionalScalar('test_sproc_two_columns', [1], z.string());\n await expect(result).rejects.toThrow('Expected exactly one column');\n });\n });\n\n describe('queryCursor', () => {\n it('handles single column', async () => {\n const cursor = await queryCursor(\n 'SELECT id FROM workspaces WHERE id = 1;',\n z.object({ id: z.string() }),\n );\n const allRows: { id: string }[] = [];\n for await (const rows of cursor.iterate(10)) {\n allRows.push(...rows);\n }\n assert.equal(allRows[0].id, '1');\n });\n\n it('handles multiple columns', async () => {\n const cursor = await queryCursor('SELECT * FROM workspaces WHERE id = 1;', WorkspaceSchema);\n const allRows: z.infer<typeof WorkspaceSchema>[] = [];\n for await (const rows of cursor.iterate(10)) {\n allRows.push(...rows);\n }\n assert.equal(allRows[0].id, '1');\n assert.isNotNull(allRows[0].created_at);\n });\n it('returns zero rows', async () => {\n const cursor = await queryCursor('SELECT * FROM workspaces WHERE id = 10000;', z.unknown());\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;', z.unknown());\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;', z.unknown());\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', z.unknown());\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('queryCursor', () => {\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 queryCursor(\n 'SELECT * FROM workspaces WHERE id <= 10 ORDER BY id ASC;',\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 queryCursor(\n 'SELECT * FROM workspaces WHERE id <= 10 ORDER BY id ASC;',\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 queryCursor(\n 'SELECT * FROM workspaces WHERE id <= 10 ORDER BY id ASC;',\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 queryCursor(\n 'SELECT * FROM workspaces ORDER BY id ASC;',\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 queryCursor('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 expect(pipeline(stream, writable, { signal: ac.signal })).rejects.toThrow();\n assert.lengthOf(rows, 1);\n });\n });\n });\n});\n"]}
@@ -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\ntype PostgresTestPoolConfig = Required<Pick<pg.PoolConfig, 'user' | 'host' | 'database'>>;\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<PostgresTestPoolConfig> {\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 ?? getDatabaseNameForCurrentTestWorker(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 const poolConfig = getPoolConfig(options);\n\n if (configurePool) {\n await defaultPool.initAsync(\n {\n ...poolConfig,\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 return poolConfig;\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 ?? getDatabaseNameForCurrentTestWorker(options.database);\n if ('PL_KEEP_TEST_DB' in process.env && !force) {\n // eslint-disable-next-line no-console\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 getDatabaseNameForCurrentTestWorker(namespace: string): string {\n // https://playwright.dev/docs/test-parallel#isolate-test-data-between-parallel-workers\n const workerId = process.env.TEST_WORKER_INDEX ?? process.env.VITEST_POOL_ID ?? '1';\n return `${namespace}_${workerId}`;\n}\n\nfunction getPoolConfig(options: PostgresTestUtilsOptions): PostgresTestPoolConfig {\n return {\n user: options.user ?? POSTGRES_USER,\n host: options.host ?? POSTGRES_HOST,\n database: getDatabaseNameForCurrentTestWorker(options.database),\n };\n}\n\nexport interface PostgresTestUtils {\n createDatabase: (options?: CreateDatabaseOptions) => Promise<pg.PoolConfig>;\n resetDatabase: () => Promise<void>;\n dropDatabase: (options?: DropDatabaseOptions) => Promise<void>;\n getDatabaseNameForCurrentTestWorker: () => 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 getDatabaseNameForCurrentTestWorker: () =>\n getDatabaseNameForCurrentTestWorker(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\ntype PostgresTestPoolConfig = Required<Pick<pg.PoolConfig, 'user' | 'host' | 'database'>>;\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<PostgresTestPoolConfig> {\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 ?? getDatabaseNameForCurrentTestWorker(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 const poolConfig = getPoolConfig(options);\n\n if (configurePool) {\n await defaultPool.initAsync(\n {\n ...poolConfig,\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 return poolConfig;\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 ?? getDatabaseNameForCurrentTestWorker(options.database);\n if ('PL_KEEP_TEST_DB' in process.env && !force) {\n // eslint-disable-next-line no-console\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 getDatabaseNameForCurrentTestWorker(namespace: string): string {\n // https://playwright.dev/docs/test-parallel#isolate-test-data-between-parallel-workers\n const workerId = process.env.TEST_WORKER_INDEX ?? process.env.VITEST_POOL_ID ?? '1';\n return `${namespace}_${workerId}`;\n}\n\nfunction getPoolConfig(options: PostgresTestUtilsOptions): PostgresTestPoolConfig {\n return {\n user: options.user ?? POSTGRES_USER,\n host: options.host ?? POSTGRES_HOST,\n database: getDatabaseNameForCurrentTestWorker(options.database),\n };\n}\n\nexport interface PostgresTestUtils {\n createDatabase: (options?: CreateDatabaseOptions) => Promise<pg.PoolConfig>;\n resetDatabase: () => Promise<void>;\n dropDatabase: (options?: DropDatabaseOptions) => Promise<void>;\n getDatabaseNameForCurrentTestWorker: () => 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 getDatabaseNameForCurrentTestWorker: () =>\n getDatabaseNameForCurrentTestWorker(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": "5.0.3",
3
+ "version": "6.0.1",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -19,19 +19,19 @@
19
19
  "dependencies": {
20
20
  "@types/debug": "^4.1.12",
21
21
  "@types/pg-cursor": "^2.7.2",
22
- "es-toolkit": "^1.44.0",
22
+ "es-toolkit": "^1.45.1",
23
23
  "multipipe": "^4.0.0",
24
- "pg": "^8.18.0",
25
- "pg-cursor": "^2.17.0",
26
- "pg-pool": "^3.11.0",
27
- "pg-protocol": "^1.11.0",
24
+ "pg": "^8.20.0",
25
+ "pg-cursor": "^2.19.0",
26
+ "pg-pool": "^3.13.0",
27
+ "pg-protocol": "^1.13.0",
28
28
  "zod": "^3.25.76"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@prairielearn/tsconfig": "^2.0.0",
32
32
  "@types/multipipe": "^3.0.5",
33
- "@types/node": "^24.10.9",
34
- "@typescript/native-preview": "^7.0.0-dev.20260203.1",
33
+ "@types/node": "^24.11.0",
34
+ "@typescript/native-preview": "^7.0.0-dev.20260305.1",
35
35
  "@vitest/coverage-v8": "^4.0.18",
36
36
  "tsx": "^4.21.0",
37
37
  "typescript": "^5.9.3",
@@ -22,6 +22,13 @@ const HIDDEN_PROPERTIES = new Set([
22
22
  'idleCount',
23
23
  'waitingCount',
24
24
  'queryCount',
25
+ // Deprecated methods not re-exported from the default pool
26
+ 'queryAsync',
27
+ 'queryOneRowAsync',
28
+ 'queryZeroOrOneRowAsync',
29
+ 'callAsync',
30
+ 'callOneRowAsync',
31
+ 'callZeroOrOneRowAsync',
25
32
  ]);
26
33
 
27
34
  describe('sqldb', () => {