@prairielearn/postgres 5.0.2 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/pool.test.ts CHANGED
@@ -6,14 +6,19 @@ import { ZodError, z } from 'zod';
6
6
 
7
7
  import {
8
8
  callOptionalRow,
9
+ callOptionalScalar,
9
10
  callRow,
10
11
  callRows,
12
+ callScalar,
13
+ callScalars,
11
14
  execute,
12
- queryAsync,
13
15
  queryCursor,
14
16
  queryOptionalRow,
17
+ queryOptionalScalar,
15
18
  queryRow,
16
19
  queryRows,
20
+ queryScalar,
21
+ queryScalars,
17
22
  } from './default-pool.js';
18
23
  import { makePostgresTestUtils } from './test-utils.js';
19
24
 
@@ -59,32 +64,35 @@ describe('@prairielearn/postgres', function () {
59
64
  describe('paramsToArray', () => {
60
65
  it('enforces SQL must be a string', async () => {
61
66
  // @ts-expect-error SQL must be a string
62
- const rows = queryAsync({ invalid: true }, {});
67
+ const rows = execute({ invalid: true }, {});
63
68
  await expect(rows).rejects.toThrow('SQL must be a string');
64
69
  });
65
70
 
66
71
  it('enforces params must be array or object', async () => {
67
72
  // @ts-expect-error params must be an array or object
68
- const rows = queryAsync('SELECT 33;', 33);
73
+ const rows = execute('SELECT 33;', 33);
69
74
  await expect(rows).rejects.toThrow('params must be array or object');
70
75
  });
71
76
 
72
77
  it('rejects missing parameters', async () => {
73
- const rows = queryAsync('SELECT $missing;', {});
78
+ const rows = execute('SELECT $missing;', {});
74
79
  await expect(rows).rejects.toThrow('Missing parameter');
75
80
  });
76
81
 
77
82
  it('rejects unused parameters in testing', async () => {
78
- const rows = queryAsync('SELECT 33;', { unsed_parameter: true });
83
+ const rows = execute('SELECT 33;', { unsed_parameter: true });
79
84
  await expect(rows).rejects.toThrow('Unused parameter');
80
85
  });
81
86
  });
82
87
 
83
88
  describe('queryRows', () => {
84
89
  it('handles single column', async () => {
85
- const rows = await queryRows('SELECT id FROM workspaces WHERE id <= 10;', z.string());
90
+ const rows = await queryRows(
91
+ 'SELECT id FROM workspaces WHERE id <= 10;',
92
+ z.object({ id: z.string() }),
93
+ );
86
94
  assert.lengthOf(rows, 10);
87
- assert.equal(rows[0], '1');
95
+ assert.equal(rows[0].id, '1');
88
96
  });
89
97
 
90
98
  it('handles multiple columns', async () => {
@@ -106,8 +114,11 @@ describe('@prairielearn/postgres', function () {
106
114
 
107
115
  describe('queryRow', () => {
108
116
  it('handles single column', async () => {
109
- const row = await queryRow('SELECT id FROM workspaces WHERE id = 1;', z.string());
110
- assert.equal(row, '1');
117
+ const row = await queryRow(
118
+ 'SELECT id FROM workspaces WHERE id = 1;',
119
+ z.object({ id: z.string() }),
120
+ );
121
+ assert.equal(row.id, '1');
111
122
  });
112
123
 
113
124
  it('handles multiple columns', async () => {
@@ -134,8 +145,11 @@ describe('@prairielearn/postgres', function () {
134
145
 
135
146
  describe('queryOptionalRow', () => {
136
147
  it('handles single column', async () => {
137
- const row = await queryRow('SELECT id FROM workspaces WHERE id = 1;', z.string());
138
- assert.equal(row, '1');
148
+ const row = await queryRow(
149
+ 'SELECT id FROM workspaces WHERE id = 1;',
150
+ z.object({ id: z.string() }),
151
+ );
152
+ assert.equal(row.id, '1');
139
153
  });
140
154
 
141
155
  it('handles multiple columns', async () => {
@@ -171,15 +185,15 @@ describe('@prairielearn/postgres', function () {
171
185
 
172
186
  describe('callRows', () => {
173
187
  it('handles single column', async () => {
174
- const rows = await callRows('test_sproc_one_column_ten_rows', z.string());
188
+ const rows = await callRows('test_sproc_one_column_ten_rows', z.object({ id: z.string() }));
175
189
  assert.lengthOf(rows, 10);
176
- assert.equal(rows[0], '1');
190
+ assert.equal(rows[0].id, '1');
177
191
  });
178
192
 
179
193
  it('handles parameters', async () => {
180
- const rows = await callRows('test_sproc_one_column', [10], z.string());
194
+ const rows = await callRows('test_sproc_one_column', [10], z.object({ id: z.string() }));
181
195
  assert.lengthOf(rows, 10);
182
- assert.equal(rows[0], '1');
196
+ assert.equal(rows[0].id, '1');
183
197
  });
184
198
 
185
199
  it('handles multiple columns', async () => {
@@ -194,13 +208,13 @@ describe('@prairielearn/postgres', function () {
194
208
 
195
209
  describe('callRow', () => {
196
210
  it('handles single column', async () => {
197
- const row = await callRow('test_sproc_one_column_one_row', z.string());
198
- assert.equal(row, '1');
211
+ const row = await callRow('test_sproc_one_column_one_row', z.object({ id: z.string() }));
212
+ assert.equal(row.id, '1');
199
213
  });
200
214
 
201
215
  it('handles parameters', async () => {
202
- const row = await callRow('test_sproc_one_column', [1], z.string());
203
- assert.equal(row, '1');
216
+ const row = await callRow('test_sproc_one_column', [1], z.object({ id: z.string() }));
217
+ assert.equal(row.id, '1');
204
218
  });
205
219
 
206
220
  it('handles multiple columns', async () => {
@@ -222,13 +236,16 @@ describe('@prairielearn/postgres', function () {
222
236
 
223
237
  describe('callOptionalRow', () => {
224
238
  it('handles single column', async () => {
225
- const row = await callOptionalRow('test_sproc_one_column_one_row', z.string());
226
- assert.equal(row, '1');
239
+ const row = await callOptionalRow(
240
+ 'test_sproc_one_column_one_row',
241
+ z.object({ id: z.string() }),
242
+ );
243
+ assert.equal(row?.id, '1');
227
244
  });
228
245
 
229
246
  it('handles parameters', async () => {
230
- const row = await callOptionalRow('test_sproc_one_column', [1], z.string());
231
- assert.equal(row, '1');
247
+ const row = await callOptionalRow('test_sproc_one_column', [1], z.object({ id: z.string() }));
248
+ assert.equal(row?.id, '1');
232
249
  });
233
250
 
234
251
  it('handles multiple columns', async () => {
@@ -249,14 +266,173 @@ describe('@prairielearn/postgres', function () {
249
266
  });
250
267
  });
251
268
 
269
+ describe('queryScalars', () => {
270
+ it('returns all scalar values', async () => {
271
+ const ids = await queryScalars(
272
+ 'SELECT id FROM workspaces WHERE id <= 10 ORDER BY id ASC;',
273
+ z.string(),
274
+ );
275
+ assert.lengthOf(ids, 10);
276
+ assert.equal(ids[0], '1');
277
+ assert.equal(ids[9], '10');
278
+ });
279
+
280
+ it('handles parameters', async () => {
281
+ const ids = await queryScalars(
282
+ 'SELECT id FROM workspaces WHERE id <= $1 ORDER BY id ASC;',
283
+ [5],
284
+ z.string(),
285
+ );
286
+ assert.lengthOf(ids, 5);
287
+ });
288
+
289
+ it('rejects multi-column queries', async () => {
290
+ const result = queryScalars('SELECT * FROM workspaces WHERE id <= 10;', z.string());
291
+ await expect(result).rejects.toThrow('Expected exactly one column');
292
+ });
293
+ });
294
+
295
+ describe('queryScalar', () => {
296
+ it('returns a single scalar value', async () => {
297
+ const id = await queryScalar('SELECT id FROM workspaces WHERE id = 1;', z.string());
298
+ assert.equal(id, '1');
299
+ });
300
+
301
+ it('handles parameters', async () => {
302
+ const id = await queryScalar('SELECT id FROM workspaces WHERE id = $1;', [1], z.string());
303
+ assert.equal(id, '1');
304
+ });
305
+
306
+ it('rejects results with zero rows', async () => {
307
+ const result = queryScalar('SELECT id FROM workspaces WHERE id = -1;', z.string());
308
+ await expect(result).rejects.toThrow('Incorrect rowCount: 0');
309
+ });
310
+
311
+ it('rejects results with multiple rows', async () => {
312
+ const result = queryScalar('SELECT id FROM workspaces;', z.string());
313
+ await expect(result).rejects.toThrow('Incorrect rowCount: 100');
314
+ });
315
+
316
+ it('rejects multi-column queries', async () => {
317
+ const result = queryScalar('SELECT * FROM workspaces WHERE id = 1;', z.string());
318
+ await expect(result).rejects.toThrow('Expected exactly one column');
319
+ });
320
+ });
321
+
322
+ describe('queryOptionalScalar', () => {
323
+ it('returns a scalar value when present', async () => {
324
+ const id = await queryOptionalScalar('SELECT id FROM workspaces WHERE id = 1;', z.string());
325
+ assert.equal(id, '1');
326
+ });
327
+
328
+ it('handles parameters', async () => {
329
+ const id = await queryOptionalScalar(
330
+ 'SELECT id FROM workspaces WHERE id = $1;',
331
+ [1],
332
+ z.string(),
333
+ );
334
+ assert.equal(id, '1');
335
+ });
336
+
337
+ it('returns null for zero rows', async () => {
338
+ const id = await queryOptionalScalar('SELECT id FROM workspaces WHERE id = -1;', z.string());
339
+ assert.isNull(id);
340
+ });
341
+
342
+ it('rejects results with multiple rows', async () => {
343
+ const result = queryOptionalScalar('SELECT id FROM workspaces;', z.string());
344
+ await expect(result).rejects.toThrow('Incorrect rowCount: 100');
345
+ });
346
+
347
+ it('rejects multi-column queries', async () => {
348
+ const result = queryOptionalScalar('SELECT * FROM workspaces WHERE id = 1;', z.string());
349
+ await expect(result).rejects.toThrow('Expected exactly one column');
350
+ });
351
+ });
352
+
353
+ describe('callScalars', () => {
354
+ it('returns all scalar values', async () => {
355
+ const ids = await callScalars('test_sproc_one_column', [10], z.string());
356
+ assert.lengthOf(ids, 10);
357
+ assert.equal(ids[0], '1');
358
+ });
359
+
360
+ it('handles no parameters', async () => {
361
+ const ids = await callScalars('test_sproc_one_column_ten_rows', z.string());
362
+ assert.lengthOf(ids, 10);
363
+ });
364
+
365
+ it('rejects multi-column sprocs', async () => {
366
+ const result = callScalars('test_sproc_two_columns', [10], z.string());
367
+ await expect(result).rejects.toThrow('Expected exactly one column');
368
+ });
369
+ });
370
+
371
+ describe('callScalar', () => {
372
+ it('returns a single scalar value', async () => {
373
+ const id = await callScalar('test_sproc_one_column_one_row', z.string());
374
+ assert.equal(id, '1');
375
+ });
376
+
377
+ it('handles parameters', async () => {
378
+ const id = await callScalar('test_sproc_one_column', [1], z.string());
379
+ assert.equal(id, '1');
380
+ });
381
+
382
+ it('rejects results with zero rows', async () => {
383
+ const result = callScalar('test_sproc_one_column', [0], z.string());
384
+ await expect(result).rejects.toThrow('Incorrect rowCount: 0');
385
+ });
386
+
387
+ it('rejects results with multiple rows', async () => {
388
+ const result = callScalar('test_sproc_one_column', [100], z.string());
389
+ await expect(result).rejects.toThrow('Incorrect rowCount: 100');
390
+ });
391
+
392
+ it('rejects multi-column sprocs', async () => {
393
+ const result = callScalar('test_sproc_two_columns', [1], z.string());
394
+ await expect(result).rejects.toThrow('Expected exactly one column');
395
+ });
396
+ });
397
+
398
+ describe('callOptionalScalar', () => {
399
+ it('returns a scalar value when present', async () => {
400
+ const id = await callOptionalScalar('test_sproc_one_column_one_row', z.string());
401
+ assert.equal(id, '1');
402
+ });
403
+
404
+ it('handles parameters', async () => {
405
+ const id = await callOptionalScalar('test_sproc_one_column', [1], z.string());
406
+ assert.equal(id, '1');
407
+ });
408
+
409
+ it('returns null for zero rows', async () => {
410
+ const id = await callOptionalScalar('test_sproc_one_column', [0], z.string());
411
+ assert.isNull(id);
412
+ });
413
+
414
+ it('rejects results with multiple rows', async () => {
415
+ const result = callOptionalScalar('test_sproc_one_column', [100], z.string());
416
+ await expect(result).rejects.toThrow('Incorrect rowCount: 100');
417
+ });
418
+
419
+ it('rejects multi-column sprocs', async () => {
420
+ const result = callOptionalScalar('test_sproc_two_columns', [1], z.string());
421
+ await expect(result).rejects.toThrow('Expected exactly one column');
422
+ });
423
+ });
424
+
252
425
  describe('queryCursor', () => {
253
426
  it('handles single column', async () => {
254
- const cursor = await queryCursor('SELECT id FROM workspaces WHERE id = 1;', z.string());
255
- const allRows: string[] = [];
427
+ const cursor = await queryCursor(
428
+ 'SELECT id FROM workspaces WHERE id = 1;',
429
+ z.object({ id: z.string() }),
430
+ );
431
+ const allRows: { id: string }[] = [];
256
432
  for await (const rows of cursor.iterate(10)) {
257
433
  allRows.push(...rows);
258
434
  }
259
- assert.equal(allRows[0], '1');
435
+ assert.equal(allRows[0].id, '1');
260
436
  });
261
437
 
262
438
  it('handles multiple columns', async () => {