pqb 0.64.0 → 0.65.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.
@@ -1,555 +1,137 @@
1
- import postgres from 'postgres';
2
- import { returnArg, emptyObject, setConnectRetryConfig, wrapAdapterFnWithConnectRetry } from 'pqb/internal';
3
- import { createDbWithAdapter } from 'pqb';
4
-
5
- const transactionArgs = {
6
- cb: void 0,
7
- options: void 0
8
- };
9
- const getTransactionArgs = (args) => {
10
- if (args[1]) {
11
- transactionArgs.options = args[0];
12
- transactionArgs.cb = args[1];
13
- } else {
14
- transactionArgs.cb = args[0];
15
- }
16
- return transactionArgs;
17
- };
18
- const mergeLocals = (locals, options) => options?.locals ? { ...locals, ...options.locals } : locals;
19
- const getSetLocalsSql = (options) => {
20
- if (!options?.locals) return;
21
- return Object.entries(options.locals).map(([key, value]) => `SET LOCAL ${key}=${value}`).join("; ");
22
- };
23
- const getResetLocalsSql = (parentLocals, options) => {
24
- if (!options?.locals) return;
25
- return Object.entries(options.locals).reduce((acc, [key, value]) => {
26
- if (parentLocals[key] !== value) {
27
- acc.push(`SET LOCAL ${key}=${parentLocals[key]}`);
28
- }
29
- return acc;
30
- }, []).join("; ");
31
- };
32
-
33
- const quoteRoleIdentifier = (role) => {
34
- return `"${role.replace(/"/g, '""')}"`;
35
- };
36
- const buildConfigRestoreExpression = (key, value) => {
37
- const escapedKey = key.replace(/'/g, "''");
38
- if (value === null || value === void 0) {
39
- value = "";
40
- }
41
- return `set_config('${escapedKey}', '${value.replace(/'/g, "''")}', false) as "${key}"`;
42
- };
43
- const sqlSessionContextComputeSetup = (desired) => {
44
- if (!desired) return void 0;
45
- const role = desired.role;
46
- const hasRole = role !== void 0;
47
- const { setConfig } = desired;
48
- const configKeys = setConfig && Object.keys(setConfig);
49
- const hasConfig = configKeys && configKeys.length > 0;
50
- if (!hasRole && !hasConfig) return void 0;
51
- const result = {};
52
- if (hasRole) {
53
- result.roleSetupSql = `SET ROLE ${quoteRoleIdentifier(role)}`;
54
- result.captureRoleSql = "SELECT current_user";
55
- }
56
- if (hasConfig && setConfig) {
57
- result.captureConfigValues = configKeys;
58
- const captureColumns = configKeys.map((key, i) => `current_setting($${i + 1}, true) as "${key}"`).join(", ");
59
- result.captureConfigSql = `SELECT ${captureColumns}`;
60
- const setColumns = configKeys.map((key) => {
61
- const value = setConfig[key];
62
- return `set_config('${key.replace(/'/g, "''")}', '${typeof value === "string" ? value.replace(/'/g, "''") : value}', false) as "${key}"`;
63
- }).join(", ");
64
- result.configSetupSql = `SELECT ${setColumns}`;
65
- }
66
- return result;
67
- };
68
- const sqlSessionContextBuildConfigRestoreBatchSql = (configs) => {
69
- const keys = Object.keys(configs);
70
- if (keys.length === 0) return void 0;
71
- const expressions = keys.map((key) => buildConfigRestoreExpression(key, configs[key])).join(", ");
72
- return `SELECT ${expressions}`;
73
- };
74
- const sqlSessionContextExecute = async (query, setup, mainQuery, release) => {
75
- if (!setup) {
76
- return mainQuery();
77
- }
78
- const captured = {};
79
- const {
80
- captureRoleSql,
81
- roleSetupSql,
82
- captureConfigSql,
83
- captureConfigValues,
84
- configSetupSql
85
- } = setup;
86
- const setupPromises = [];
87
- if (captureRoleSql) {
88
- setupPromises.push(
89
- query(captureRoleSql).then((res) => {
90
- captured.previousRole = res.rows[0]?.[0];
91
- })
92
- );
93
- setupPromises.push(query(roleSetupSql));
94
- }
95
- if (captureConfigSql && captureConfigValues && configSetupSql) {
96
- captured.previousConfigs = {};
97
- const previousConfigs = captured.previousConfigs;
98
- setupPromises.push(
99
- query(captureConfigSql, captureConfigValues).then((res) => {
100
- const row = res.rows[0];
101
- captureConfigValues.forEach((key, i) => {
102
- previousConfigs[key] = row[i];
103
- });
104
- })
105
- );
106
- setupPromises.push(query(configSetupSql));
107
- }
108
- try {
109
- await Promise.all(setupPromises);
110
- return await mainQuery();
111
- } finally {
112
- try {
113
- const cleanupPromises = [];
114
- if (roleSetupSql && captured.previousRole !== void 0) {
115
- cleanupPromises.push(
116
- query(`SET ROLE ${quoteRoleIdentifier(captured.previousRole)}`)
117
- );
118
- }
119
- if (captured.previousConfigs) {
120
- const restoreSql = sqlSessionContextBuildConfigRestoreBatchSql(
121
- captured.previousConfigs
122
- );
123
- if (restoreSql) {
124
- cleanupPromises.push(query(restoreSql));
125
- }
126
- }
127
- await Promise.all(cleanupPromises);
128
- } finally {
129
- if (release) {
130
- await release();
131
- }
132
- }
133
- }
134
- };
135
-
1
+ import postgres from "postgres";
2
+ import { AdapterClass, returnArg } from "pqb/internal";
3
+ import { createDbWithAdapter } from "pqb";
136
4
  const createDb = (options) => {
137
- return createDbWithAdapter({
138
- ...options,
139
- adapter: new PostgresJsAdapter(options)
140
- });
5
+ return createDbWithAdapter({
6
+ ...options,
7
+ adapter: new AdapterClass({
8
+ driverAdapter: PostgresJsAdapter,
9
+ config: options
10
+ })
11
+ });
12
+ };
13
+ var PostgresJsResult = class {
14
+ constructor(result) {
15
+ this.rowCount = result.count;
16
+ this.rows = result;
17
+ this.fields = result.statement.columns;
18
+ }
141
19
  };
142
- class PostgresJsResult {
143
- constructor(result) {
144
- this.rowCount = result.count;
145
- this.rows = result;
146
- this.fields = result.statement.columns;
147
- }
148
- }
149
20
  const wrapResult = (result) => {
150
- if (result.constructor === Array) {
151
- return result.map(
152
- (res) => new PostgresJsResult(res)
153
- );
154
- } else {
155
- return new PostgresJsResult(result);
156
- }
21
+ if (result.constructor === Array) return result.map((res) => new PostgresJsResult(res));
22
+ else return new PostgresJsResult(result);
157
23
  };
158
24
  const types = {
159
- bytea: {
160
- to: 17,
161
- from: 17,
162
- serialize: (x) => "\\x" + Buffer.from(x).toString("hex")
163
- // omit parse, let bytea return a string, so it remains consistent with when it's selected via JSON
164
- },
165
- dateAndTimestampAsStrings: {
166
- to: 25,
167
- from: [1082, 1114, 1184],
168
- parse: returnArg
169
- },
170
- interval: {
171
- from: [1186],
172
- serialize: returnArg,
173
- parse(str) {
174
- const [years, , months, , days, , time] = str.split(" ");
175
- const [hours, minutes, seconds] = time.split(":");
176
- return {
177
- years: years ? Number(years) : 0,
178
- months: months ? Number(months) : 0,
179
- days: days ? Number(days) : 0,
180
- hours: hours ? Number(hours) : 0,
181
- minutes: minutes ? Number(minutes) : 0,
182
- seconds: seconds ? Number(seconds) : 0
183
- };
184
- }
185
- },
186
- // overrides the built-in json type to not serialize it, because it incorrectly serializes
187
- json: {
188
- to: 114,
189
- from: [114, 3802],
190
- serialize: returnArg,
191
- parse: (x) => {
192
- return JSON.parse(x);
193
- }
194
- }
195
- };
196
- class PostgresJsAdapter {
197
- constructor(config) {
198
- this.errorClass = postgres.PostgresError;
199
- this.config = { ...config, types };
200
- this.sql = this.configure(config);
201
- this.locals = config.searchPath ? {
202
- search_path: config.searchPath
203
- } : emptyObject;
204
- }
205
- isInTransaction() {
206
- return false;
207
- }
208
- configure(config) {
209
- this.searchPath = config.searchPath;
210
- if (this.searchPath) {
211
- this.config.connection = {
212
- ...config.connection,
213
- search_path: this.searchPath
214
- };
215
- }
216
- let sql;
217
- if (this.config.databaseURL) {
218
- const urlString = this.config.databaseURL;
219
- const url = new URL(urlString);
220
- const ssl = url.searchParams.get("ssl");
221
- if (ssl === "false" || ssl === "true") {
222
- this.config.ssl = ssl === "true";
223
- }
224
- const searchPath = url.searchParams.get("searchPath");
225
- if (searchPath) {
226
- this.searchPath = searchPath;
227
- url.searchParams.delete("searchPath");
228
- this.config.connection = {
229
- ...config.connection,
230
- search_path: searchPath
231
- };
232
- }
233
- sql = postgres(url.toString(), this.config);
234
- } else {
235
- sql = postgres(this.config);
236
- }
237
- if (config.connectRetry) {
238
- setConnectRetryConfig(
239
- this,
240
- config.connectRetry === true ? emptyObject : config.connectRetry
241
- );
242
- if (!this.wrappedWithConnectRetry) {
243
- this.query = wrapAdapterFnWithConnectRetry(this, this.query);
244
- this.arrays = wrapAdapterFnWithConnectRetry(this, this.arrays);
245
- this.wrappedWithConnectRetry = true;
246
- }
247
- }
248
- return sql;
249
- }
250
- getURL() {
251
- return this.config.databaseURL ? new URL(this.config.databaseURL) : void 0;
252
- }
253
- replaceSql(config) {
254
- const { sql } = this;
255
- this.sql = this.configure(config);
256
- return sql.end();
257
- }
258
- async updateConfig(config) {
259
- await this.replaceSql({ ...this.config, ...config });
260
- }
261
- reconfigure(params) {
262
- const url = this.getURL();
263
- if (url) {
264
- if ("database" in params) {
265
- url.pathname = `/${params.database}`;
266
- }
267
- if (params.user !== void 0) {
268
- url.username = params.user;
269
- }
270
- if (params.password !== void 0) {
271
- url.password = params.password;
272
- }
273
- if (params.searchPath !== void 0) {
274
- url.searchParams.set("searchPath", params.searchPath);
275
- }
276
- return new PostgresJsAdapter({
277
- ...this.config,
278
- databaseURL: url.toString()
279
- });
280
- } else {
281
- return new PostgresJsAdapter({ ...this.config, ...params });
282
- }
283
- }
284
- getDatabase() {
285
- const url = this.getURL();
286
- return url ? url.pathname.slice(1) : this.config.database;
287
- }
288
- getUser() {
289
- const url = this.getURL();
290
- return url ? url.username : this.config.user;
291
- }
292
- getSearchPath() {
293
- return this.searchPath;
294
- }
295
- getHost() {
296
- const url = this.getURL();
297
- return url ? url.hostname : this.config.host;
298
- }
299
- getSchema() {
300
- return this.config.schema;
301
- }
302
- query(text, values, startingSavepoint, releasingSavepoint, sqlSessionState) {
303
- return queryWithSqlSession(
304
- this.sql,
305
- text,
306
- values,
307
- sqlSessionState,
308
- startingSavepoint,
309
- releasingSavepoint,
310
- false,
311
- true
312
- );
313
- }
314
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
315
- arrays(text, values, startingSavepoint, releasingSavepoint, sqlSessionState) {
316
- return queryWithSqlSession(
317
- this.sql,
318
- text,
319
- values,
320
- sqlSessionState,
321
- startingSavepoint,
322
- releasingSavepoint,
323
- true,
324
- true
325
- );
326
- }
327
- async transaction(...args) {
328
- let ok;
329
- let result;
330
- const { cb, options } = getTransactionArgs(args);
331
- const fn = (sql) => {
332
- if (options?.sqlSessionState) {
333
- const { role, setConfig } = options.sqlSessionState;
334
- if (role) {
335
- sql.unsafe(`SET ROLE ${role}`).execute();
336
- }
337
- if (setConfig && Object.keys(setConfig).length > 0) {
338
- const setExpressions = Object.entries(setConfig).map(
339
- ([key, value]) => `set_config('${key.replace(/'/g, "''")}', '${typeof value === "string" ? value.replace(/'/g, "''") : value}', true)`
340
- ).join(", ");
341
- sql.unsafe(`SELECT ${setExpressions}`).execute();
342
- }
343
- }
344
- const localsSql = getSetLocalsSql(options);
345
- if (localsSql) {
346
- sql.unsafe(localsSql).execute();
347
- }
348
- const locals = mergeLocals(this.locals, options);
349
- return cb(
350
- new PostgresJsTransactionAdapter(this, sql, this, locals)
351
- ).then((res) => {
352
- ok = true;
353
- return result = res;
354
- });
355
- };
356
- return (options?.options ? this.sql.begin(options.options, fn) : this.sql.begin(fn)).catch((err) => {
357
- if (ok) return result;
358
- throw err;
359
- });
360
- }
361
- close() {
362
- return this.replaceSql(this.config);
363
- }
364
- assignError(to, dbError) {
365
- const from = dbError;
366
- to.message = from.message;
367
- to.severity = from.severity;
368
- to.code = from.code;
369
- to.detail = from.detail;
370
- to.schema = from.schema_name;
371
- to.table = from.table_name;
372
- to.constraint = from.constraint_name;
373
- to.hint = from.hint;
374
- to.position = from.position;
375
- to.where = from.where;
376
- to.file = from.file;
377
- to.line = from.line;
378
- to.routine = from.routine;
379
- }
380
- }
381
- const query = (sql, text, values, startingSavepoint, releasingSavepoint, arrays) => {
382
- let query2 = sql.unsafe(text, values);
383
- if (arrays) query2 = query2.values();
384
- if (!startingSavepoint && !releasingSavepoint) {
385
- return query2.then(wrapResult);
386
- }
387
- return Promise.all([
388
- startingSavepoint && sql.unsafe(`SAVEPOINT "${startingSavepoint}"`),
389
- query2,
390
- releasingSavepoint && sql.unsafe(`RELEASE SAVEPOINT "${releasingSavepoint}"`)
391
- ]).then(
392
- (results) => {
393
- return wrapResult(results[1]);
394
- },
395
- (err) => {
396
- if (!releasingSavepoint) {
397
- throw err;
398
- }
399
- return sql.unsafe(`ROLLBACK TO SAVEPOINT "${releasingSavepoint}"`).then(() => {
400
- throw err;
401
- });
402
- }
403
- );
25
+ bytea: {
26
+ to: 17,
27
+ from: 17,
28
+ serialize: (x) => "\\x" + Buffer.from(x).toString("hex")
29
+ },
30
+ dateAndTimestampAsStrings: {
31
+ to: 25,
32
+ from: [
33
+ 1082,
34
+ 1114,
35
+ 1184
36
+ ],
37
+ parse: returnArg
38
+ },
39
+ interval: {
40
+ from: [1186],
41
+ serialize: returnArg,
42
+ parse(str) {
43
+ const [years, , months, , days, , time] = str.split(" ");
44
+ const [hours, minutes, seconds] = time.split(":");
45
+ return {
46
+ years: years ? Number(years) : 0,
47
+ months: months ? Number(months) : 0,
48
+ days: days ? Number(days) : 0,
49
+ hours: hours ? Number(hours) : 0,
50
+ minutes: minutes ? Number(minutes) : 0,
51
+ seconds: seconds ? Number(seconds) : 0
52
+ };
53
+ }
54
+ },
55
+ json: {
56
+ to: 114,
57
+ from: [114, 3802],
58
+ serialize: returnArg,
59
+ parse: (x) => {
60
+ return JSON.parse(x);
61
+ }
62
+ }
404
63
  };
405
- const queryWithSqlSession = async (sql, text, values, sessionState, startingSavepoint, releasingSavepoint, arraysMode, borrowConnection = false) => {
406
- const setup = sqlSessionContextComputeSetup(sessionState);
407
- if (!setup) {
408
- return query(
409
- sql,
410
- text,
411
- values,
412
- startingSavepoint,
413
- releasingSavepoint,
414
- arraysMode
415
- );
416
- }
417
- const connection = borrowConnection ? await sql.reserve() : sql;
418
- const queryFn = async (sqlStr, vals) => {
419
- const result = await connection.unsafe(sqlStr, vals).values();
420
- return {
421
- rows: result,
422
- rowCount: result.length,
423
- fields: []
424
- };
425
- };
426
- const releaseFn = borrowConnection ? async () => {
427
- await connection.release();
428
- } : void 0;
429
- const mainQuery = () => query(
430
- connection,
431
- text,
432
- values,
433
- startingSavepoint,
434
- releasingSavepoint,
435
- arraysMode
436
- );
437
- return sqlSessionContextExecute(queryFn, setup, mainQuery, releaseFn);
64
+ const PostgresJsAdapter = {
65
+ manualPool: false,
66
+ errorClass: postgres.PostgresError,
67
+ errorFields: {
68
+ message: "message",
69
+ severity: "severity",
70
+ code: "code",
71
+ detail: "detail",
72
+ schema: "schema_name",
73
+ table: "table_name",
74
+ constraint: "constraint_name",
75
+ hint: "hint",
76
+ position: "position",
77
+ where: "where",
78
+ file: "file",
79
+ line: "line",
80
+ routine: "routine"
81
+ },
82
+ configure(params) {
83
+ const config = {
84
+ ...params,
85
+ types
86
+ };
87
+ if (config.locals?.search_path) config.connection = {
88
+ ...config.connection,
89
+ search_path: config.locals.search_path
90
+ };
91
+ let sql;
92
+ if (config.databaseURL) sql = postgres(config.databaseURL, config);
93
+ else sql = postgres(config);
94
+ return sql;
95
+ },
96
+ queryClient(client, text, values, startingSavepoint, releasingSavepoint, arraysMode) {
97
+ let query = client.unsafe(text, values);
98
+ if (arraysMode) query = query.values();
99
+ if (!startingSavepoint && !releasingSavepoint) return query.then(wrapResult);
100
+ return Promise.all([
101
+ startingSavepoint && client.unsafe(`SAVEPOINT "${startingSavepoint}"`),
102
+ query,
103
+ releasingSavepoint && client.unsafe(`RELEASE SAVEPOINT "${releasingSavepoint}"`)
104
+ ]).then((results) => {
105
+ return wrapResult(results[1]);
106
+ }, (err) => {
107
+ if (!releasingSavepoint) throw err;
108
+ return client.unsafe(`ROLLBACK TO SAVEPOINT "${releasingSavepoint}"`).then(() => {
109
+ throw err;
110
+ });
111
+ });
112
+ },
113
+ borrow(client) {
114
+ return client.reserve();
115
+ },
116
+ release(client) {
117
+ client.release();
118
+ },
119
+ begin(client, cb, options) {
120
+ let ok;
121
+ let result;
122
+ const fn = (sql) => cb(sql).then((res) => {
123
+ ok = true;
124
+ return result = res;
125
+ });
126
+ return (options ? client.begin(options, fn) : client.begin(fn)).catch((err) => {
127
+ if (ok) return result;
128
+ throw err;
129
+ });
130
+ },
131
+ close(client) {
132
+ return client.end();
133
+ }
438
134
  };
439
- class PostgresJsTransactionAdapter {
440
- constructor(adapter, sql, parent, locals) {
441
- this.adapter = adapter;
442
- this.sql = sql;
443
- this.parent = parent;
444
- this.locals = locals;
445
- this.errorClass = postgres.PostgresError;
446
- }
447
- isInTransaction() {
448
- return true;
449
- }
450
- updateConfig(config) {
451
- return this.adapter.updateConfig(config);
452
- }
453
- reconfigure(params) {
454
- return this.adapter.reconfigure(params);
455
- }
456
- getDatabase() {
457
- return this.adapter.getDatabase();
458
- }
459
- getUser() {
460
- return this.adapter.getUser();
461
- }
462
- getSearchPath() {
463
- return this.adapter.searchPath;
464
- }
465
- getHost() {
466
- return this.adapter.getHost();
467
- }
468
- getSchema() {
469
- return this.adapter.getSchema();
470
- }
471
- query(text, values, startingSavepoint, releasingSavepoint, sqlSessionState) {
472
- return queryWithSqlSession(
473
- this.sql,
474
- text,
475
- values,
476
- sqlSessionState,
477
- startingSavepoint,
478
- releasingSavepoint,
479
- false,
480
- false
481
- );
482
- }
483
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
484
- arrays(text, values, startingSavepoint, releasingSavepoint, sqlSessionState) {
485
- return queryWithSqlSession(
486
- this.sql,
487
- text,
488
- values,
489
- sqlSessionState,
490
- startingSavepoint,
491
- releasingSavepoint,
492
- true,
493
- false
494
- );
495
- }
496
- async transaction(...args) {
497
- const { cb, options } = getTransactionArgs(args);
498
- let capturedRole;
499
- const capturedConfigs = {};
500
- const sqlSession = options?.sqlSessionState;
501
- if (sqlSession) {
502
- if (sqlSession.role) {
503
- const roleResult = await this.query(
504
- "SELECT current_role as role"
505
- );
506
- capturedRole = roleResult.rows[0].role;
507
- }
508
- if (sqlSession.setConfig && Object.keys(sqlSession.setConfig).length > 0) {
509
- for (const key of Object.keys(sqlSession.setConfig)) {
510
- const configResult = await this.query(
511
- `SELECT current_setting('${key.replace(/'/g, "''")}', true) as val`
512
- );
513
- capturedConfigs[key] = configResult.rows[0].val;
514
- }
515
- }
516
- }
517
- const localsSql = getSetLocalsSql(options);
518
- if (localsSql) {
519
- this.sql.unsafe(localsSql).execute();
520
- }
521
- const locals = mergeLocals(this.locals, options);
522
- let res;
523
- try {
524
- res = await cb(
525
- new PostgresJsTransactionAdapter(this.adapter, this.sql, this, locals)
526
- );
527
- } finally {
528
- if (sqlSession) {
529
- if (capturedRole !== void 0) {
530
- await this.query(`SET ROLE ${capturedRole}`);
531
- }
532
- for (const [key, value] of Object.entries(capturedConfigs)) {
533
- const restoreValue = value === null ? "" : value;
534
- await this.query(
535
- `SELECT set_config('${key.replace(/'/g, "''")}', '${restoreValue.replace(/'/g, "''")}', true)`
536
- );
537
- }
538
- }
539
- const resetLocalsSql = getResetLocalsSql(this.locals, options);
540
- if (resetLocalsSql) {
541
- await this.sql.unsafe(resetLocalsSql);
542
- }
543
- }
544
- return res;
545
- }
546
- close() {
547
- return this.sql.end();
548
- }
549
- assignError(to, from) {
550
- return this.adapter.assignError(to, from);
551
- }
552
- }
135
+ export { PostgresJsAdapter, createDb };
553
136
 
554
- export { PostgresJsAdapter, PostgresJsTransactionAdapter, createDb };
555
- //# sourceMappingURL=postgres-js.mjs.map
137
+ //# sourceMappingURL=postgres-js.mjs.map