@devopsplaybook.io/common-utils 1.10.1-beta.23.b1906d7 → 1.11.0-beta.24.d8f9aef

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.
Files changed (69) hide show
  1. package/README.md +73 -27
  2. package/dist/src/ConfigBase.d.ts +31 -0
  3. package/dist/src/ConfigBase.js +58 -16
  4. package/dist/src/DbUtils.d.ts +20 -3
  5. package/dist/src/DbUtils.js +93 -2
  6. package/dist/src/DbUtilsNoTelemetry.d.ts +4 -1
  7. package/dist/src/DbUtilsNoTelemetry.js +62 -6
  8. package/dist/src/PostgresDbUtils.d.ts +41 -10
  9. package/dist/src/PostgresDbUtils.js +357 -304
  10. package/dist/src/SqlDbUtils.d.ts +12 -4
  11. package/dist/src/SqlDbUtils.js +76 -30
  12. package/dist/src/users/Auth.d.ts +11 -1
  13. package/dist/src/users/Auth.js +160 -44
  14. package/dist/src/users/User.d.ts +10 -0
  15. package/dist/src/users/User.js +30 -10
  16. package/dist/src/users/UserApiToken.d.ts +4 -0
  17. package/dist/src/users/UserApiToken.js +11 -0
  18. package/dist/src/users/UsersApiTokensData.d.ts +12 -0
  19. package/dist/src/users/UsersApiTokensData.js +130 -33
  20. package/dist/src/users/UsersData.d.ts +20 -1
  21. package/dist/src/users/UsersData.js +150 -52
  22. package/dist/src/users/UsersRoutes.js +178 -61
  23. package/dist/src/users/index.d.ts +8 -0
  24. package/dist/src/users/index.js +24 -0
  25. package/package.json +58 -1
  26. package/.github/workflows/main-build.yml +0 -18
  27. package/.github/workflows/pr-check.yml +0 -27
  28. package/.github/workflows/reusable-merge-build.yml +0 -197
  29. package/.github/workflows/reusable-npm-merge.yml +0 -135
  30. package/.github/workflows/reusable-npm-pr.yml +0 -183
  31. package/.github/workflows/reusable-npm-upgrade.yml +0 -92
  32. package/.github/workflows/reusable-pr-verify.yml +0 -181
  33. package/AGENTS.md +0 -105
  34. package/index.ts +0 -18
  35. package/jest.config.js +0 -17
  36. package/prettierrc.json +0 -5
  37. package/src/ConfigBase.spec.ts +0 -108
  38. package/src/ConfigBase.ts +0 -297
  39. package/src/DbUtils.spec.ts +0 -23
  40. package/src/DbUtils.ts +0 -116
  41. package/src/DbUtilsNoTelemetry.spec.ts +0 -168
  42. package/src/DbUtilsNoTelemetry.ts +0 -117
  43. package/src/LLM.spec.ts +0 -303
  44. package/src/LLM.ts +0 -204
  45. package/src/Notifications.spec.ts +0 -265
  46. package/src/Notifications.ts +0 -201
  47. package/src/OTelContext.spec.ts +0 -58
  48. package/src/OTelContext.ts +0 -63
  49. package/src/PostgresDbUtils.spec.ts +0 -153
  50. package/src/PostgresDbUtils.ts +0 -666
  51. package/src/SqlDbUtils.spec.ts +0 -108
  52. package/src/SqlDbUtils.ts +0 -152
  53. package/src/SystemCommand.spec.ts +0 -18
  54. package/src/SystemCommand.ts +0 -23
  55. package/src/Timeout.spec.ts +0 -18
  56. package/src/Timeout.ts +0 -12
  57. package/src/users/Auth.spec.ts +0 -268
  58. package/src/users/Auth.ts +0 -202
  59. package/src/users/User.ts +0 -75
  60. package/src/users/UserApiToken.ts +0 -55
  61. package/src/users/UserPassword.spec.ts +0 -28
  62. package/src/users/UserPassword.ts +0 -20
  63. package/src/users/UserSession.ts +0 -9
  64. package/src/users/UsersApiTokensData.spec.ts +0 -158
  65. package/src/users/UsersApiTokensData.ts +0 -125
  66. package/src/users/UsersData.ts +0 -141
  67. package/src/users/UsersRoutes.ts +0 -374
  68. package/tsconfig.json +0 -15
  69. package/tsconfig.spec.json +0 -8
@@ -1,666 +0,0 @@
1
- import { Pool } from "pg";
2
- import * as fs from "fs-extra";
3
- import { Span } from "@opentelemetry/sdk-trace-base";
4
- import { SpanStatusCode } from "@opentelemetry/api";
5
- import {
6
- StandardTracer,
7
- StandardLogger,
8
- ModuleLogger,
9
- } from "@devopsplaybook.io/otel-utils";
10
-
11
- /**
12
- * Configuration subset required by the Postgres module.
13
- */
14
- export interface PostgresDbConfig {
15
- DATABASE_POSTGRES_HOST: string;
16
- DATABASE_POSTGRES_PORT: number;
17
- DATABASE_POSTGRES_USER: string;
18
- DATABASE_POSTGRES_PASSWORD: string;
19
- DATABASE_POSTGRES_DATABASE: string;
20
- }
21
-
22
- // ---------------------------------------------------------------------------
23
- // Module-level state
24
- // ---------------------------------------------------------------------------
25
-
26
- let pool: Pool;
27
- let tracer: StandardTracer;
28
- let logger: ModuleLogger;
29
- let standardLogger: StandardLogger;
30
-
31
- // ---------------------------------------------------------------------------
32
- // Class-based API – supports per-schema pools + shared runtime pool
33
- // ---------------------------------------------------------------------------
34
-
35
- /**
36
- * Class-based PostgreSQL utility that manages a schema-specific pool (used
37
- * during migrations) and an optional shared runtime pool (used for
38
- * application queries).
39
- *
40
- * Multiple instances can coexist, each bound to a different PostgreSQL
41
- * schema, while sharing a single runtime pool that has all schemas in its
42
- * `search_path`.
43
- */
44
- export class PostgresSchemaDbUtils {
45
- private schemaPool: Pool | null = null;
46
- private runtimePool: Pool | null = null;
47
- private readonly schemaName: string;
48
- private _moduleLogger: ModuleLogger | null = null;
49
-
50
- constructor(schemaName: string) {
51
- this.schemaName = schemaName;
52
- }
53
-
54
- private get moduleLogger(): ModuleLogger {
55
- if (!this._moduleLogger) {
56
- this._moduleLogger = standardLogger.createModuleLogger(
57
- `PostgresSchemaDbUtils[${this.schemaName}]`,
58
- );
59
- }
60
- return this._moduleLogger;
61
- }
62
-
63
- /**
64
- * Create the schema-specific pool, ensure the schema exists, and apply
65
- * any pending migration files from `sqlDir`.
66
- */
67
- async initSchema(
68
- context: Span,
69
- config: PostgresDbConfig,
70
- sqlDir: string,
71
- ): Promise<void> {
72
- const span = tracer.startSpan("PostgresSchemaDbUtilsInit", context);
73
-
74
- const poolOptions = {
75
- host: config.DATABASE_POSTGRES_HOST,
76
- port: config.DATABASE_POSTGRES_PORT || 5432,
77
- user: config.DATABASE_POSTGRES_USER,
78
- password: config.DATABASE_POSTGRES_PASSWORD,
79
- database: config.DATABASE_POSTGRES_DATABASE,
80
- options: `-c search_path=${this.schemaName}`,
81
- max: 5,
82
- idleTimeoutMillis: 30000,
83
- connectionTimeoutMillis: 10000,
84
- };
85
-
86
- if (this.schemaPool) {
87
- this.moduleLogger.info("Closing existing schema pool");
88
- await this.schemaPool.end().catch(() => {
89
- // Ignore errors on close
90
- });
91
- }
92
- this.schemaPool = new Pool(poolOptions);
93
- this.moduleLogger.info(
94
- `Schema pool initialized with search_path: ${this.schemaName}`,
95
- );
96
-
97
- // Create schema if not exists
98
- await this.execSQLForSchema(
99
- span,
100
- `CREATE SCHEMA IF NOT EXISTS ${this.schemaName};`,
101
- );
102
- await this.execSQLForSchema(span, `SET search_path TO ${this.schemaName};`);
103
-
104
- // Run init SQL files
105
- await this.execSQLFileForSchema(span, `${sqlDir}/init-0000.sql`);
106
- const initFiles = (await fs.readdir(sqlDir)).sort();
107
- let dbVersionApplied = 0;
108
-
109
- try {
110
- const dbVersionQuery = await this.querySQLForSchema(
111
- span,
112
- "SELECT MAX(value) as version FROM metadata WHERE type='db_version'",
113
- );
114
- if ((dbVersionQuery[0] as Record<string, unknown>).version) {
115
- dbVersionApplied = Number(
116
- (dbVersionQuery[0] as Record<string, unknown>).version,
117
- );
118
- }
119
- } catch {
120
- // Table might not exist yet
121
- }
122
-
123
- this.moduleLogger.info(`Current DB Version: ${dbVersionApplied}`);
124
-
125
- for (const initFile of initFiles) {
126
- const regex = /init-(\d+)\.sql/g;
127
- const match = regex.exec(initFile);
128
- if (match) {
129
- const dbVersionInitFile = Number(match[1]);
130
- if (dbVersionInitFile > dbVersionApplied) {
131
- this.moduleLogger.info(`Applying migration: ${initFile}`);
132
- await this.execSQLFileForSchema(span, `${sqlDir}/${initFile}`);
133
- await this.querySQLForSchema(
134
- span,
135
- 'INSERT INTO metadata ("type", "value", "dateCreated") VALUES ($1, $2, $3)',
136
- ["db_version", dbVersionInitFile, new Date().toISOString()],
137
- );
138
- }
139
- }
140
- }
141
-
142
- span.end();
143
- }
144
-
145
- /**
146
- * Initialise (or replace) the shared runtime pool.
147
- * Typically called once with a pool whose `search_path` includes all
148
- * application schemas.
149
- */
150
- initRuntimePool(config: PostgresDbConfig, searchPath?: string): void {
151
- if (this.runtimePool) {
152
- this.runtimePool.end().catch(() => {
153
- // Ignore errors on close
154
- });
155
- }
156
- this.runtimePool = new Pool({
157
- host: config.DATABASE_POSTGRES_HOST,
158
- port: config.DATABASE_POSTGRES_PORT || 5432,
159
- user: config.DATABASE_POSTGRES_USER,
160
- password: config.DATABASE_POSTGRES_PASSWORD,
161
- database: config.DATABASE_POSTGRES_DATABASE,
162
- options: searchPath
163
- ? `-c search_path=${searchPath}`
164
- : `-c search_path=${this.schemaName}`,
165
- max: 20,
166
- idleTimeoutMillis: 30000,
167
- connectionTimeoutMillis: 10000,
168
- keepAlive: true,
169
- });
170
- this.moduleLogger.info(
171
- `Runtime pool initialized (search_path: ${searchPath || this.schemaName})`,
172
- );
173
- }
174
-
175
- /**
176
- * Execute a write SQL statement with OTel tracing.
177
- * @param useSchemaPool When `true` use the schema-specific pool;
178
- * otherwise use the runtime pool (default).
179
- * @returns Number of rows changed.
180
- */
181
- execSQL(
182
- context: Span,
183
- sql: string,
184
- params: any[] = [],
185
- useSchemaPool = false,
186
- ): Promise<number> {
187
- const span = tracer.startSpan("PostgresSchemaDbUtilsExecSQL", context);
188
- const pool = useSchemaPool ? this.schemaPool : this.runtimePool;
189
-
190
- if (!pool) {
191
- throw new Error(
192
- `Pool not initialized${useSchemaPool ? ` for schema: ${this.schemaName}` : ""}`,
193
- );
194
- }
195
-
196
- return new Promise((resolve, reject) => {
197
- pool.query(
198
- sql,
199
- params,
200
- (error: Error | null, result: { rowCount: number | null }) => {
201
- span.end();
202
- if (error) {
203
- span.setStatus({
204
- code: SpanStatusCode.ERROR,
205
- message: error.message,
206
- });
207
- this.moduleLogger.error(
208
- `[${useSchemaPool ? this.schemaName : "RUNTIME"}] SQL EXEC ERROR: ${sql}`,
209
- error,
210
- );
211
- reject(error);
212
- } else {
213
- resolve(result.rowCount || 0);
214
- }
215
- },
216
- );
217
- });
218
- }
219
-
220
- /** Execute an entire SQL file (used for migrations). */
221
- async execSQLFile(
222
- context: Span,
223
- filename: string,
224
- useSchemaPool = false,
225
- ): Promise<void> {
226
- const span = tracer.startSpan("PostgresSchemaDbUtilsExecSQLFile", context);
227
- const sql = (await fs.readFile(filename)).toString();
228
- const pool = useSchemaPool ? this.schemaPool : this.runtimePool;
229
-
230
- if (!pool) {
231
- throw new Error(
232
- `Pool not initialized${useSchemaPool ? ` for schema: ${this.schemaName}` : ""}`,
233
- );
234
- }
235
-
236
- return new Promise((resolve, reject) => {
237
- pool.query(sql, (error: Error | null) => {
238
- span.end();
239
- if (error) {
240
- span.setStatus({
241
- code: SpanStatusCode.ERROR,
242
- message: error.message,
243
- });
244
- reject(error);
245
- } else {
246
- resolve();
247
- }
248
- });
249
- });
250
- }
251
-
252
- /**
253
- * Execute a read SQL query with OTel tracing.
254
- * @returns Array of row objects.
255
- */
256
- querySQL(
257
- context: Span,
258
- sql: string,
259
- params: any[] = [],
260
- useSchemaPool = false,
261
- ): Promise<any[]> {
262
- const span = tracer.startSpan("PostgresSchemaDbUtilsQuerySQL", context);
263
- const pool = useSchemaPool ? this.schemaPool : this.runtimePool;
264
-
265
- if (!pool) {
266
- throw new Error(
267
- `Pool not initialized${useSchemaPool ? ` for schema: ${this.schemaName}` : ""}`,
268
- );
269
- }
270
-
271
- return new Promise((resolve, reject) => {
272
- pool.query(
273
- sql,
274
- params,
275
- (error: Error | null, result: { rows: unknown[] }) => {
276
- span.end();
277
- if (error) {
278
- span.setStatus({
279
- code: SpanStatusCode.ERROR,
280
- message: error.message,
281
- });
282
- this.moduleLogger.error(
283
- `[${useSchemaPool ? this.schemaName : "RUNTIME"}] SQL QUERY ERROR: ${sql}`,
284
- error,
285
- );
286
- reject(error);
287
- } else {
288
- resolve(result.rows);
289
- }
290
- },
291
- );
292
- });
293
- }
294
-
295
- /**
296
- * Run a callback inside a transaction.
297
- */
298
- async transaction(
299
- context: Span,
300
- callback: (client: any) => Promise<void>,
301
- useSchemaPool = false,
302
- ): Promise<void> {
303
- const span = tracer.startSpan("PostgresSchemaDbUtilsTransaction", context);
304
- const pool = useSchemaPool ? this.schemaPool : this.runtimePool;
305
-
306
- if (!pool) {
307
- throw new Error(
308
- `Pool not initialized${useSchemaPool ? ` for schema: ${this.schemaName}` : ""}`,
309
- );
310
- }
311
-
312
- this.moduleLogger.info(
313
- `[${useSchemaPool ? this.schemaName : "RUNTIME"}] Starting transaction`,
314
- );
315
- const client = await pool.connect();
316
- try {
317
- await client.query("BEGIN");
318
- await callback(client);
319
- await client.query("COMMIT");
320
- this.moduleLogger.info(
321
- `[${useSchemaPool ? this.schemaName : "RUNTIME"}] Transaction committed`,
322
- );
323
- } catch (error) {
324
- await client.query("ROLLBACK");
325
- this.moduleLogger.error(
326
- `[${useSchemaPool ? this.schemaName : "RUNTIME"}] Transaction rolled back`,
327
- error as Error,
328
- );
329
- throw error;
330
- } finally {
331
- client.release();
332
- span.end();
333
- }
334
- }
335
-
336
- /** Close both the schema pool and the runtime pool. */
337
- async closeAll(): Promise<void> {
338
- const promises: Promise<void>[] = [];
339
-
340
- if (this.schemaPool) {
341
- this.moduleLogger.info("Closing schema pool");
342
- promises.push(
343
- this.schemaPool.end().catch(() => {
344
- this.moduleLogger.warn("Error closing schema pool");
345
- }),
346
- );
347
- this.schemaPool = null;
348
- }
349
-
350
- if (this.runtimePool) {
351
- this.moduleLogger.info("Closing runtime pool");
352
- promises.push(
353
- this.runtimePool.end().catch(() => {
354
- this.moduleLogger.warn("Error closing runtime pool");
355
- }),
356
- );
357
- this.runtimePool = null;
358
- }
359
-
360
- await Promise.all(promises);
361
- this.moduleLogger.info("All database pools closed");
362
- }
363
-
364
- // -- Internal helpers (schema pool only) ----------------------------------
365
-
366
- private execSQLForSchema(
367
- context: Span,
368
- sql: string,
369
- params: any[] = [],
370
- ): Promise<void> {
371
- const span = tracer.startSpan(
372
- "PostgresSchemaDbUtilsExecSQLForSchema",
373
- context,
374
- );
375
-
376
- if (!this.schemaPool) {
377
- throw new Error(`Pool not initialized for schema: ${this.schemaName}`);
378
- }
379
-
380
- return new Promise((resolve, reject) => {
381
- this.schemaPool!.query(sql, params, (error: Error | null) => {
382
- span.end();
383
- if (error) {
384
- reject(error);
385
- } else {
386
- resolve();
387
- }
388
- });
389
- });
390
- }
391
-
392
- private async execSQLFileForSchema(
393
- context: Span,
394
- filename: string,
395
- ): Promise<void> {
396
- try {
397
- const span = tracer.startSpan(
398
- "PostgresSchemaDbUtilsExecSQLFileForSchema",
399
- context,
400
- );
401
- const sql = (await fs.readFile(filename)).toString();
402
-
403
- if (!this.schemaPool) {
404
- throw new Error(`Pool not initialized for schema: ${this.schemaName}`);
405
- }
406
-
407
- return new Promise((resolve, reject) => {
408
- this.schemaPool!.query(sql, (error: Error | null) => {
409
- span.end();
410
- if (error) {
411
- if ((error as any).code === "ENOENT") {
412
- resolve();
413
- } else {
414
- reject(error);
415
- }
416
- } else {
417
- resolve();
418
- }
419
- });
420
- });
421
- } catch (error) {
422
- if ((error as any).code === "ENOENT") {
423
- return;
424
- }
425
- throw error;
426
- }
427
- }
428
-
429
- private querySQLForSchema(
430
- context: Span,
431
- sql: string,
432
- params: any[] = [],
433
- ): Promise<any[]> {
434
- const span = tracer.startSpan(
435
- "PostgresSchemaDbUtilsQuerySQLForSchema",
436
- context,
437
- );
438
-
439
- if (!this.schemaPool) {
440
- throw new Error(`Pool not initialized for schema: ${this.schemaName}`);
441
- }
442
-
443
- return new Promise((resolve, reject) => {
444
- this.schemaPool!.query(
445
- sql,
446
- params,
447
- (error: Error | null, result: { rows: unknown[] }) => {
448
- span.end();
449
- if (error) {
450
- reject(error);
451
- } else {
452
- resolve(result.rows);
453
- }
454
- },
455
- );
456
- });
457
- }
458
- }
459
-
460
- // ---------------------------------------------------------------------------
461
- // Functional API – single-pool mode used by the DbUtils facade.
462
- // An internal PostgresSchemaDbUtils instance backs these functions so the
463
- // behaviour is identical to before.
464
- // ---------------------------------------------------------------------------
465
-
466
- /**
467
- * Injects the OTel tracer and logger instances used by all Postgres operations.
468
- * Must be called once at startup, before {@link PostgresDbUtilsInit}.
469
- */
470
- export function PostgresDbUtilsSetOTel(
471
- tracerIn: StandardTracer,
472
- loggerIn: StandardLogger,
473
- ): void {
474
- tracer = tracerIn;
475
- standardLogger = loggerIn;
476
- logger = loggerIn.createModuleLogger("PostgresDbUtils");
477
- }
478
-
479
- /**
480
- * Creates the Postgres connection pool and applies pending migration files
481
- * from `sqlDir`.
482
- */
483
- export async function PostgresDbUtilsInit(
484
- context: Span,
485
- config: PostgresDbConfig,
486
- sqlDir: string,
487
- ): Promise<void> {
488
- const span = tracer.startSpan("PostgresDbUtilsInit", context);
489
-
490
- // Use the schema-level init but without schema creation (single-pool mode)
491
- const poolOptions = {
492
- host: config.DATABASE_POSTGRES_HOST,
493
- port: config.DATABASE_POSTGRES_PORT || 5432,
494
- user: config.DATABASE_POSTGRES_USER,
495
- password: config.DATABASE_POSTGRES_PASSWORD,
496
- database: config.DATABASE_POSTGRES_DATABASE,
497
- max: 20,
498
- idleTimeoutMillis: 30000,
499
- connectionTimeoutMillis: 10000,
500
- keepAlive: true,
501
- };
502
-
503
- // Create a simple pool directly for the functional API
504
- pool = new Pool(poolOptions);
505
-
506
- pool.on("error", (err: Error) => {
507
- logger.error("PostgreSQL pool connection error", err);
508
- });
509
-
510
- await PostgresDbUtilsExecSQLFile(span, `${sqlDir}/init-0000.sql`);
511
- const initFiles = (await fs.readdir(sqlDir)).sort();
512
- let dbVersionApplied = 0;
513
- const dbVersionQuery = await PostgresDbUtilsQuerySQL(
514
- span,
515
- "SELECT MAX(value) as version FROM metadata WHERE \"type\" = 'db_version'",
516
- );
517
- if (dbVersionQuery.length > 0 && dbVersionQuery[0].version) {
518
- dbVersionApplied = Number(dbVersionQuery[0].version);
519
- }
520
- logger.info(`Current DB Version: ${dbVersionApplied}`, span);
521
- for (const initFile of initFiles) {
522
- const regex = /init-(\d+).sql/g;
523
- const match = regex.exec(initFile);
524
- if (match) {
525
- const dbVersionInitFile = Number(match[1]);
526
- if (dbVersionInitFile > dbVersionApplied) {
527
- logger.info(`Loading init file: ${initFile}`, span);
528
- await PostgresDbUtilsExecSQLFile(span, `${sqlDir}/${initFile}`);
529
- await PostgresDbUtilsQuerySQL(
530
- span,
531
- 'INSERT INTO metadata ("type", "value", "dateCreated") VALUES ($1, $2, $3)',
532
- ["db_version", dbVersionInitFile, new Date().toISOString()],
533
- );
534
- }
535
- }
536
- }
537
- span.end();
538
- }
539
-
540
- /** Returns the underlying `pg.Pool` instance. */
541
- export function PostgresDbUtilsGetPool(): Pool {
542
- return pool;
543
- }
544
-
545
- /**
546
- * Execute a write SQL statement with OTel tracing.
547
- * @returns Number of rows changed.
548
- */
549
- export function PostgresDbUtilsExecSQL(
550
- context: Span,
551
- sql: string,
552
- params: unknown[] = [],
553
- ): Promise<number> {
554
- const span = tracer.startSpan("PostgresDbUtilsExecSQL", context);
555
- return new Promise((resolve, reject) => {
556
- pool.query(
557
- sql,
558
- params,
559
- (error: Error | null, result: { rowCount: number | null }) => {
560
- if (error) {
561
- span.setStatus({
562
- code: SpanStatusCode.ERROR,
563
- message: error.message,
564
- });
565
- span.end();
566
- reject(error);
567
- } else {
568
- span.addEvent(`Impacted Rows: ${result.rowCount || 0}`);
569
- span.end();
570
- resolve(result.rowCount || 0);
571
- }
572
- },
573
- );
574
- });
575
- }
576
-
577
- /** Execute an entire SQL file (used for migrations). */
578
- export async function PostgresDbUtilsExecSQLFile(
579
- context: Span,
580
- filename: string,
581
- ): Promise<void> {
582
- const span = tracer.startSpan("PostgresDbUtilsExecSQLFile", context);
583
- const sql = (await fs.readFile(filename)).toString();
584
- return new Promise((resolve, reject) => {
585
- pool.query(sql, (error: Error | null) => {
586
- if (error) {
587
- span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
588
- span.end();
589
- reject(error);
590
- } else {
591
- span.end();
592
- resolve();
593
- }
594
- });
595
- });
596
- }
597
-
598
- /**
599
- * Execute a read SQL query with OTel tracing.
600
- * @returns Array of row objects.
601
- */
602
- export function PostgresDbUtilsQuerySQL(
603
- context: Span,
604
- sql: string,
605
- params: unknown[] = [],
606
- debug = false,
607
- ): Promise<any[]> {
608
- const span = tracer.startSpan("PostgresDbUtilsQuerySQL", context);
609
- if (debug) {
610
- console.log(sql);
611
- }
612
- return new Promise((resolve, reject) => {
613
- pool.query(
614
- sql,
615
- params,
616
- (error: Error | null, result: { rows: unknown[] }) => {
617
- if (error) {
618
- span.setStatus({
619
- code: SpanStatusCode.ERROR,
620
- message: error.message,
621
- });
622
- logger.error(`SQL ERROR: ${sql}`, error, span);
623
- span.end();
624
- reject(error);
625
- } else {
626
- span.end();
627
- resolve(result.rows);
628
- }
629
- },
630
- );
631
- });
632
- }
633
-
634
- /** Start a transaction. */
635
- export function PostgresDbUtilsTransactionStart(context: Span): Promise<void> {
636
- const span = tracer.startSpan("PostgresDbUtilsTransactionStart", context);
637
- return new Promise((resolve, reject) => {
638
- pool.query("BEGIN", (error: Error | null) => {
639
- if (error) {
640
- span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
641
- span.end();
642
- reject(error);
643
- } else {
644
- span.end();
645
- resolve();
646
- }
647
- });
648
- });
649
- }
650
-
651
- /** Commit a transaction. */
652
- export function PostgresDbUtilsTransactionCommit(context: Span): Promise<void> {
653
- const span = tracer.startSpan("PostgresDbUtilsTransactionCommit", context);
654
- return new Promise((resolve, reject) => {
655
- pool.query("COMMIT", (error: Error | null) => {
656
- if (error) {
657
- span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
658
- span.end();
659
- reject(error);
660
- } else {
661
- span.end();
662
- resolve();
663
- }
664
- });
665
- });
666
- }