pipework 0.281.0 → 0.283.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/REFERENCE.md +13 -0
  3. package/dist/core/config/load.d.ts +3 -1
  4. package/dist/core/config/load.d.ts.map +1 -1
  5. package/dist/core/config/load.js +1 -0
  6. package/dist/core/config/load.js.map +1 -1
  7. package/dist/core/config/namespace.d.ts +1 -0
  8. package/dist/core/config/namespace.d.ts.map +1 -1
  9. package/dist/core/config/schema.d.ts +3 -1
  10. package/dist/core/config/schema.d.ts.map +1 -1
  11. package/dist/core/config/schema.js +3 -0
  12. package/dist/core/config/schema.js.map +1 -1
  13. package/dist/core/config/statement-observer.d.ts +58 -0
  14. package/dist/core/config/statement-observer.d.ts.map +1 -1
  15. package/dist/core/surface/types.d.ts +1 -0
  16. package/dist/core/surface/types.d.ts.map +1 -1
  17. package/dist/data/db/instrumentation.d.ts +6 -4
  18. package/dist/data/db/instrumentation.d.ts.map +1 -1
  19. package/dist/data/db/instrumentation.js +12 -14
  20. package/dist/data/db/instrumentation.js.map +1 -1
  21. package/dist/data/db/namespace.d.ts +3 -0
  22. package/dist/data/db/namespace.d.ts.map +1 -1
  23. package/dist/data/db/namespace.js +3 -0
  24. package/dist/data/db/namespace.js.map +1 -1
  25. package/dist/data/db/pool.js +4 -4
  26. package/dist/data/db/pool.js.map +1 -1
  27. package/dist/data/db/query-watch.d.ts +8 -0
  28. package/dist/data/db/query-watch.d.ts.map +1 -1
  29. package/dist/data/db/query-watch.js +70 -2
  30. package/dist/data/db/query-watch.js.map +1 -1
  31. package/dist/data/db/raw-client-warning.js +1 -1
  32. package/dist/data/db/raw-client-warning.js.map +1 -1
  33. package/dist/data/db/rows.d.ts +35 -0
  34. package/dist/data/db/rows.d.ts.map +1 -0
  35. package/dist/data/db/rows.js +91 -0
  36. package/dist/data/db/rows.js.map +1 -0
  37. package/dist/data/query/postgres-js/session.d.ts +1 -1
  38. package/dist/data/query/postgres-js/session.d.ts.map +1 -1
  39. package/dist/data/query/postgres-js/session.js +16 -9
  40. package/dist/data/query/postgres-js/session.js.map +1 -1
  41. package/dist/index.d.ts +2 -1
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/test/plugin.js +6 -6
  45. package/dist/test/plugin.js.map +1 -1
  46. package/package.json +1 -1
  47. package/src/core/config/load.ts +4 -1
  48. package/src/core/config/schema.ts +4 -1
  49. package/src/core/config/statement-observer.ts +61 -0
  50. package/src/core/surface/types.ts +1 -0
  51. package/src/data/db/instrumentation.ts +15 -14
  52. package/src/data/db/namespace.ts +4 -0
  53. package/src/data/db/pool.ts +4 -4
  54. package/src/data/db/query-watch.ts +72 -3
  55. package/src/data/db/raw-client-warning.ts +1 -1
  56. package/src/data/db/rows.ts +120 -0
  57. package/src/data/query/postgres-js/session.ts +20 -11
  58. package/src/index.ts +2 -1
  59. package/src/test/plugin.ts +6 -6
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -80,11 +80,11 @@ export async function endTestIsolation(instance, ctx) {
80
80
  instance.isolation.markEnd();
81
81
  }
82
82
  async function createIsolatedConnection(testDb, connections, name, observability, withSystem) {
83
- const debug = createDebugFn(observability);
83
+ const watch = createStatementWatch({ database: name, url: testDb.url, slowQueryMs: observability.slowQueryMs, inFlightQueryMs: observability.inFlightQueryMs, onSettled: observability.onStatementSettled });
84
+ const debug = createDebugFn(observability, watch.noteConnection);
84
85
  const client = postgres(testDb.url, { max: 1, onnotice: () => { }, ...(debug ? { debug } : {}) });
85
86
  if (isObserverOnly(observability))
86
87
  markObservedConnection(client);
87
- const watch = createStatementWatch({ database: name, url: testDb.url, slowQueryMs: observability.slowQueryMs, inFlightQueryMs: observability.inFlightQueryMs });
88
88
  const db = drizzle(client, { statementWatch: watch.watch });
89
89
  await db.execute(sql.raw('BEGIN'));
90
90
  const join = collapseTransactionsToSavepoints(db, client);
@@ -119,13 +119,13 @@ export async function propagateTestSessionVars(instance, testConnections, tenant
119
119
  }
120
120
  }
121
121
  export function createSetupConnection(testDb, observability) {
122
- const debug = observability ? createDebugFn(observability) : undefined;
122
+ const watch = observability
123
+ ? createStatementWatch({ database: 'setup', url: testDb.url, slowQueryMs: observability.slowQueryMs, inFlightQueryMs: observability.inFlightQueryMs, onSettled: observability.onStatementSettled })
124
+ : undefined;
125
+ const debug = observability ? createDebugFn(observability, watch?.noteConnection) : undefined;
123
126
  const client = postgres(testDb.url, { max: 1, onnotice: () => { }, ...(debug ? { debug } : {}) });
124
127
  if (observability && isObserverOnly(observability))
125
128
  markObservedConnection(client);
126
- const watch = observability
127
- ? createStatementWatch({ database: 'setup', url: testDb.url, slowQueryMs: observability.slowQueryMs, inFlightQueryMs: observability.inFlightQueryMs })
128
- : undefined;
129
129
  const db = splitLargeInserts(drizzle(client, watch ? { statementWatch: watch.watch } : {}));
130
130
  return { drizzle: db, close: async () => { await watch?.close(); await client.end(); } };
131
131
  }
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/test/plugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/test/plugin.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pipework",
3
- "version": "0.281.0",
3
+ "version": "0.283.0",
4
4
  "description": "TypeScript framework for multi-tenant SaaS applications. PostgreSQL-only.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -4,7 +4,7 @@ import { resolveEnvironment, resolveEnvironmentStrict, resolveDbUrl, resolveTest
4
4
  import { ConfigError } from './errors.js'
5
5
  import { resolveEnvVars } from './env-resolve.js'
6
6
  import { consumeConfigBaseDir } from './base-dir.js'
7
- import type { StatementObserver } from './statement-observer.js'
7
+ import type { StatementObserver, StatementSettledObserver } from './statement-observer.js'
8
8
 
9
9
  export interface ResolvedObservability {
10
10
  readonly slowQueryMs: number
@@ -14,6 +14,8 @@ export interface ResolvedObservability {
14
14
  readonly poolMetricsInterval: number
15
15
  /** Caller-supplied per-statement observer; undefined when not configured. */
16
16
  readonly onStatement: StatementObserver | undefined
17
+ /** Caller-supplied per-statement completion hook; undefined when not configured. */
18
+ readonly onStatementSettled?: StatementSettledObserver | undefined
17
19
  }
18
20
 
19
21
  export interface ResolvedTrace {
@@ -247,6 +249,7 @@ function buildResolved(config: Blueprint, environment: Environment, baseDir: str
247
249
  logAllQueries: config.observability?.logAllQueries ?? false,
248
250
  poolMetricsInterval: config.observability?.poolMetricsInterval ?? 0,
249
251
  onStatement: config.observability?.onStatement,
252
+ onStatementSettled: config.observability?.onStatementSettled,
250
253
  },
251
254
  trace: {
252
255
  hotRetentionDays: config.trace?.hotRetentionDays ?? 7,
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod/v4'
2
- import type { StatementObserver } from './statement-observer.js'
2
+ import type { StatementObserver, StatementSettledObserver } from './statement-observer.js'
3
3
 
4
4
  const SETTING_NAME = /^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)?$/
5
5
 
@@ -181,6 +181,9 @@ const observabilitySchema = z.object({
181
181
  onStatement: z.custom<StatementObserver>(v => typeof v === 'function', { message: 'Expected a function' })
182
182
  .optional()
183
183
  .describe('Per-statement observer — fires once per statement written to the wire, including driver-issued BEGIN/SAVEPOINT/COMMIT/ROLLBACK'),
184
+ onStatementSettled: z.custom<StatementSettledObserver>(v => typeof v === 'function', { message: 'Expected a function' })
185
+ .optional()
186
+ .describe('Per-statement completion hook — fires once per statement when it settles, with label, durationMs, rows, connectionId and (on failure) a sanitized error'),
184
187
  })
185
188
 
186
189
  const envVarDefSchema = z.discriminatedUnion('type', [
@@ -46,3 +46,64 @@ export interface StatementEvent {
46
46
  * database.
47
47
  */
48
48
  export type StatementObserver = (event: StatementEvent) => void
49
+
50
+ /**
51
+ * A failed statement's error, reduced to what is safe to hand to a hook:
52
+ * the driver's own error objects carry the statement text and bind parameters
53
+ * (and, on an observed connection, make them enumerable), so the hook never
54
+ * sees the error object itself.
55
+ */
56
+ export interface StatementSettledError {
57
+ readonly name: string
58
+ readonly message: string
59
+ /** The PostgreSQL SQLSTATE (or the driver's error code) when the error carries one. */
60
+ readonly code?: string
61
+ }
62
+
63
+ /**
64
+ * One statement as it settles — the completion counterpart to `StatementEvent`.
65
+ * Fields are only ever added to this payload, never reshaped.
66
+ */
67
+ export interface StatementSettledEvent {
68
+ /**
69
+ * The `pipe.labelled` label in effect when the statement settled; null when
70
+ * none. This is the label alone: unlike `query:slow`, it never falls back to
71
+ * the statement text.
72
+ */
73
+ readonly label: string | null
74
+ /**
75
+ * Wall-clock milliseconds the statement took, measured by the same timer as
76
+ * `query:slow` (so for one statement the two agree exactly).
77
+ */
78
+ readonly durationMs: number
79
+ /**
80
+ * Rows the statement returned, or, for a write with no `RETURNING`, rows it
81
+ * affected: the command tag's count. 0 for a statement with no count
82
+ * (DDL, `SET`, ...) and for a failed statement.
83
+ */
84
+ readonly rows: number
85
+ /**
86
+ * The same ordinal `StatementEvent.connectionId` carries for this statement;
87
+ * null when the statement never reached a connection (it failed before being
88
+ * written).
89
+ */
90
+ readonly connectionId: number | null
91
+ /** Present exactly when the statement failed. Never carries parameters. */
92
+ readonly error?: StatementSettledError
93
+ }
94
+
95
+ /**
96
+ * Caller-supplied completion hook. Fires once per statement that settles, on
97
+ * every statement pipework runs through its own query path: `pipe()`, every
98
+ * `pipe.*` write, `connection.drizzle`, transactions and savepoints, and the
99
+ * test harness's connections. It does not fire for the driver's own
100
+ * transaction control (`BEGIN`/`SAVEPOINT`/`COMMIT`/`ROLLBACK`), nor for the
101
+ * raw `ManagedConnection.client` door, nor for the migration runner's own
102
+ * connection; `onStatement` is the hook that sees wire truth.
103
+ *
104
+ * Pure observation, fired after the statement has settled and its result is on
105
+ * its way back: a hook that throws, or returns a promise that rejects, is
106
+ * logged (`statement:settled-hook-failed`) and never affects the statement.
107
+ * A returned promise is not awaited.
108
+ */
109
+ export type StatementSettledObserver = (event: StatementSettledEvent) => void | Promise<void>
@@ -73,6 +73,7 @@ export interface SurfaceContext {
73
73
  readonly logAllQueries: boolean
74
74
  readonly poolMetricsInterval: number
75
75
  readonly onStatement: import('../config/statement-observer.js').StatementObserver | undefined
76
+ readonly onStatementSettled?: import('../config/statement-observer.js').StatementSettledObserver | undefined
76
77
  }
77
78
  readonly raw: unknown
78
79
  }
@@ -5,6 +5,9 @@ import type { ResolvedObservability } from '../../core/config/load.js'
5
5
  const DEADLOCK_CODE = '40P01'
6
6
  const QUERY_TRUNCATE_LENGTH = 500
7
7
 
8
+ /** Records which connection a statement's parameter array was written on; see `createStatementWatch`. */
9
+ export type ConnectionNote = (connectionId: number, parameters: readonly unknown[]) => void
10
+
8
11
  /** postgres.js's `debug` hook signature. */
9
12
  type DebugFn = (connection: number, query: string, parameters: unknown[]) => void
10
13
 
@@ -15,30 +18,28 @@ type DebugFn = (connection: number, query: string, parameters: unknown[]) => voi
15
18
  * are today, that mode having already opted into verbose errors.
16
19
  */
17
20
  export function isObserverOnly(config: ResolvedObservability): boolean {
18
- return config.onStatement !== undefined && !config.logAllQueries
21
+ return (config.onStatement !== undefined || config.onStatementSettled !== undefined) && !config.logAllQueries
19
22
  }
20
23
 
21
24
  /**
22
25
  * The driver's `debug` hook for a connection, or undefined when nothing is
23
- * observing. Query logging and the caller-supplied `onStatement` observer are
24
- * independent: either alone installs the hook, and with both configured both
25
- * fire for every statement.
26
+ * observing. Query logging, the caller-supplied `onStatement` observer and the
27
+ * connection note behind `onStatementSettled` are independent: any one alone
28
+ * installs the hook, and with several configured all fire for every statement.
26
29
  */
27
- export function createDebugFn(config: ResolvedObservability): DebugFn | undefined {
30
+ export function createDebugFn(config: ResolvedObservability, noteConnection?: ConnectionNote): DebugFn | undefined {
28
31
  const logQuery = config.logAllQueries ? createQueryLogFn() : undefined
29
32
  const observer = config.onStatement
33
+ // The completion hook needs the connection a statement ran on, which only this hook is told.
34
+ const note = config.onStatementSettled !== undefined ? noteConnection : undefined
30
35
 
31
- if (!logQuery && !observer) return undefined
32
- if (!observer) return logQuery
33
- if (!logQuery) {
34
- return (connection, query, parameters) => {
35
- observer({ connectionId: connection, query, parameters })
36
- }
37
- }
36
+ if (!logQuery && !observer && !note) return undefined
37
+ if (!observer && !note) return logQuery
38
38
 
39
39
  return (connection, query, parameters) => {
40
- logQuery(connection, query, parameters)
41
- observer({ connectionId: connection, query, parameters })
40
+ logQuery?.(connection, query, parameters)
41
+ note?.(connection, parameters)
42
+ observer?.({ connectionId: connection, query, parameters })
42
43
  }
43
44
  }
44
45
 
@@ -9,6 +9,7 @@ import { serializable } from './serializable.js'
9
9
  import { withTimeouts } from './timeouts.js'
10
10
  import { bulkSet } from './bulk-set.js'
11
11
  import { values } from './values.js'
12
+ import { rows } from './rows.js'
12
13
  import { fn } from './function-source.js'
13
14
  import { update, insert, remove, upsert } from '../write/index.js'
14
15
 
@@ -84,6 +85,9 @@ export const pipe = Object.assign(getDb, {
84
85
  /** Produces a typed VALUES clause for bulk operations — the base primitive for bulkSet and bulkUpsert. */
85
86
  values,
86
87
 
88
+ /** A typed rowset from parallel array parameters, one parameter per column whatever the row count, as a source for `.from()` and joins — `pipe.rows({ g: 'text', id: 'int' }, { g: [...], id: [...] })` renders `unnest($1::text[], $2::int[]) AS rows(g, id)`. For composite-key matches that would otherwise be a union or a JS-side tuple match. */
89
+ rows,
90
+
87
91
  /** A set-returning SQL function as a typed source for `.from()` and joins — `pipe.fn('schema.f', { args: [field.uuid()], columns: { path: field.text() } })`. Arguments are bound and cast to their declared types. */
88
92
  fn,
89
93
 
@@ -166,7 +166,10 @@ export function createManagedConnection(
166
166
  observability?: ResolvedObservability,
167
167
  applicationName?: string,
168
168
  ): ManagedConnection {
169
- const baseDebug = observability ? createDebugFn(observability) : undefined
169
+ const statementWatch = observability
170
+ ? createStatementWatch({ database: config.name, url: config.url, slowQueryMs: observability.slowQueryMs, inFlightQueryMs: observability.inFlightQueryMs, onSettled: observability.onStatementSettled })
171
+ : undefined
172
+ const baseDebug = observability ? createDebugFn(observability, statementWatch?.noteConnection) : undefined
170
173
  const slot: ProbeSlot | undefined = baseDebug ? { current: null } : undefined
171
174
  const debug = baseDebug && slot
172
175
  ? ((connection, query, parameters) => {
@@ -187,9 +190,6 @@ export function createManagedConnection(
187
190
  const observerOnly = observability !== undefined && isObserverOnly(observability)
188
191
  if (observerOnly) markObservedConnection(client)
189
192
 
190
- const statementWatch = observability
191
- ? createStatementWatch({ database: config.name, url: config.url, slowQueryMs: observability.slowQueryMs, inFlightQueryMs: observability.inFlightQueryMs })
192
- : undefined
193
193
  const db = splitLargeInserts(drizzle(client, statementWatch ? { statementWatch: statementWatch.watch } : {}))
194
194
  const canceller = createCanceller(config.url)
195
195
 
@@ -1,7 +1,9 @@
1
1
  import postgres from 'postgres'
2
2
  import { getLogger } from '../../core/logging/logger.js'
3
3
  import { currentQueryLabel } from './query-label.js'
4
+ import { DrizzleQueryError } from '../query/errors.js'
4
5
  import type { StatementWatch } from '../query/postgres-js/session.js'
6
+ import type { StatementSettledError, StatementSettledObserver } from '../../core/config/statement-observer.js'
5
7
 
6
8
  const LABEL_SQL_CHARS = 120
7
9
  const SAMPLE_TIMEOUT_MS = 2_000
@@ -23,13 +25,42 @@ export interface StatementWatchOptions {
23
25
  readonly slowQueryMs: number
24
26
  /** Undefined: no timer is ever created. */
25
27
  readonly inFlightQueryMs: number | undefined
28
+ /** `observability.onStatementSettled`; undefined: nothing extra is tracked or fired. */
29
+ readonly onSettled?: StatementSettledObserver | undefined
26
30
  }
27
31
 
28
32
  export interface StatementWatchHandle {
29
33
  readonly watch: StatementWatch
34
+ /**
35
+ * Pass to `createDebugFn` for the same pool: the driver's debug hook is the only place that
36
+ * learns a statement's connection. Undefined when no `onSettled` hook is configured.
37
+ */
38
+ readonly noteConnection: ((connectionId: number, parameters: readonly unknown[]) => void) | undefined
30
39
  close(): Promise<void>
31
40
  }
32
41
 
42
+ /** Rows a settled statement returned, or affected for a write: the driver's command-tag count, else the row count. */
43
+ function rowsOf(result: unknown): number {
44
+ if (typeof result !== 'object' || result === null) return 0
45
+ const count = (result as { count?: unknown }).count
46
+ if (typeof count === 'number') return count
47
+ return Array.isArray(result) ? result.length : 0
48
+ }
49
+
50
+ /** Name, message and code only: the driver's error object carries the statement text and bind parameters. */
51
+ function settledError(raw: unknown): StatementSettledError {
52
+ // Drizzle wraps a driver failure in an error whose message is `Failed query: <sql>\nparams: <values>`: report the cause.
53
+ let err = raw
54
+ while (err instanceof DrizzleQueryError && err.cause !== undefined) err = err.cause
55
+ if (typeof err !== 'object' || err === null) return { name: 'Error', message: String(err) }
56
+ const { name, message, code } = err as { name?: unknown; message?: unknown; code?: unknown }
57
+ return {
58
+ name: typeof name === 'string' ? name : 'Error',
59
+ message: typeof message === 'string' ? message : '',
60
+ ...(typeof code === 'string' ? { code } : {}),
61
+ }
62
+ }
63
+
33
64
  function labelFor(sqlText: string): string {
34
65
  return currentQueryLabel() ?? sqlText.replace(/\s+/g, ' ').trim().slice(0, LABEL_SQL_CHARS)
35
66
  }
@@ -41,7 +72,10 @@ function labelFor(sqlText: string): string {
41
72
  * dedicated connection, never the statement's own and never the app pool.
42
73
  */
43
74
  export function createStatementWatch(options: StatementWatchOptions): StatementWatchHandle {
44
- const { database, url, slowQueryMs, inFlightQueryMs } = options
75
+ const { database, url, slowQueryMs, inFlightQueryMs, onSettled } = options
76
+ // Keyed on the parameter array the driver builds for a statement: the same array reaches the
77
+ // debug hook (with the connection ordinal) and sits on the pending query the session hands us.
78
+ const connections = onSettled ? new WeakMap<object, number>() : undefined
45
79
  let sampler: postgres.Sql | undefined
46
80
  let sampling = false
47
81
  let closed = false
@@ -72,8 +106,24 @@ export function createStatementWatch(options: StatementWatchOptions): StatementW
72
106
  return Promise.race([run, timeout]).catch(() => UNKNOWN_BACKEND).finally(() => { clearTimeout(timer) })
73
107
  }
74
108
 
75
- const watch: StatementWatch = async <T>(sqlText: string, run: () => Promise<T>): Promise<T> => {
109
+ function fireSettled(event: Parameters<StatementSettledObserver>[0]): void {
110
+ if (!onSettled) return
111
+ const failed = (err: unknown): void => {
112
+ getLogger().warn({ err, database }, 'statement:settled-hook-failed')
113
+ }
114
+ try {
115
+ const out = onSettled(event)
116
+ if (out !== undefined && typeof (out as Promise<void>).then === 'function') void Promise.resolve(out).catch(failed)
117
+ } catch (err) {
118
+ failed(err)
119
+ }
120
+ }
121
+
122
+ const watch: StatementWatch = async <T>(sqlText: string, run: (seen: (pending: object) => void) => Promise<T>): Promise<T> => {
76
123
  const startedMs = Date.now()
124
+ let pendingQuery: object | undefined
125
+ let outcome: { result: unknown } | { error: unknown } | undefined
126
+ const seen = (pending: object): void => { pendingQuery = pending }
77
127
  let interval: NodeJS.Timeout | undefined
78
128
  let settled = false
79
129
  if (inFlightQueryMs !== undefined) {
@@ -93,7 +143,12 @@ export function createStatementWatch(options: StatementWatchOptions): StatementW
93
143
  interval.unref()
94
144
  }
95
145
  try {
96
- return await run()
146
+ const result = await run(seen)
147
+ if (onSettled) outcome = { result }
148
+ return result
149
+ } catch (err) {
150
+ if (onSettled) outcome = { error: err }
151
+ throw err
97
152
  } finally {
98
153
  settled = true
99
154
  if (interval !== undefined) clearInterval(interval)
@@ -101,11 +156,25 @@ export function createStatementWatch(options: StatementWatchOptions): StatementW
101
156
  if (slowQueryMs > 0 && durationMs > slowQueryMs) {
102
157
  getLogger().warn({ label: labelFor(sqlText), durationMs, database }, 'query:slow')
103
158
  }
159
+ if (onSettled && outcome !== undefined) {
160
+ const parameters = pendingQuery === undefined ? undefined : (pendingQuery as { parameters?: unknown }).parameters
161
+ const connectionId = typeof parameters === 'object' && parameters !== null ? connections?.get(parameters) ?? null : null
162
+ fireSettled({
163
+ label: currentQueryLabel() ?? null,
164
+ durationMs,
165
+ rows: 'result' in outcome ? rowsOf(outcome.result) : 0,
166
+ connectionId,
167
+ ...('error' in outcome ? { error: settledError(outcome.error) } : {}),
168
+ })
169
+ }
104
170
  }
105
171
  }
106
172
 
107
173
  return {
108
174
  watch,
175
+ noteConnection: connections
176
+ ? (connectionId, parameters) => { connections.set(parameters, connectionId) }
177
+ : undefined,
109
178
  async close() {
110
179
  closed = true
111
180
  const client = sampler
@@ -23,7 +23,7 @@ export function warnRawClientIsUnsanitized(database: string): void {
23
23
 
24
24
  getBaseLogger().warn(
25
25
  { database },
26
- '[pipework] raw .client read on a connection with observability.onStatement configured. ' +
26
+ '[pipework] raw .client read on a connection with observability.onStatement or onStatementSettled configured. ' +
27
27
  'Queries issued through .client bypass pipework\'s driver error boundary, so their errors ' +
28
28
  'serialize bind parameters (postgres.js marks query/parameters/args enumerable whenever its ' +
29
29
  'debug hook is installed). Use connection.drizzle — or pipe() inside a managed context — to ' +
@@ -0,0 +1,120 @@
1
+ import { sql } from './sql.js'
2
+ import type { SQL } from './types.js'
3
+ import { Subquery } from '../query/subquery.js'
4
+ import { SelectionProxyHandler } from '../query/selection-proxy.js'
5
+
6
+ const CAST = /^[a-z_][a-z0-9_]*( [a-z_][a-z0-9_]*)*(\([0-9, ]+\))?$/i
7
+ const COLUMN_NAME = /^[a-z_][a-z0-9_]*$/i
8
+
9
+ type TextLike = 'text' | 'uuid' | 'varchar' | 'char' | 'citext'
10
+ type NumberLike = 'int' | 'integer' | 'int4' | 'smallint' | 'int2' | 'real' | 'float4' | 'double precision' | 'float8'
11
+ type DateLike = 'timestamptz' | 'timestamp' | 'date'
12
+
13
+ /** The JS type a column of this SQL type reads as: text and uuid as string, ints and floats as number, bigint and numeric as string (as postgres.js returns them), dates as Date, boolean as boolean; any other type name as unknown. A cell may be null. */
14
+ export type RowsColumnValue<T extends string> =
15
+ T extends TextLike ? string
16
+ : T extends NumberLike ? number
17
+ : T extends 'bigint' | 'int8' | 'numeric' ? string
18
+ : T extends 'boolean' | 'bool' ? boolean
19
+ : T extends DateLike ? Date | string
20
+ : unknown
21
+
22
+ /** Column name to SQL type name: `{ g: 'text', id: 'int' }`. */
23
+ export type RowsColumns = Readonly<Record<string, string>>
24
+
25
+ /** One array per column, all the same length: `{ g: ['a', 'b'], id: [1, 2] }` is two rows. */
26
+ export type RowsData<TColumns extends RowsColumns> = { readonly [K in keyof TColumns]: ReadonlyArray<RowsColumnValue<TColumns[K]> | null> }
27
+
28
+ type RowsFields<TColumns extends RowsColumns> = {
29
+ [K in keyof TColumns]: SQL<RowsColumnValue<TColumns[K]> | null>
30
+ }
31
+
32
+ /** A rowset usable in `.from()` and joins; its columns are properties of it. */
33
+ export type RowsSource<TAlias extends string, TColumns extends RowsColumns> =
34
+ & Subquery<TAlias, RowsFields<TColumns>>
35
+ & RowsFields<TColumns>
36
+ & {
37
+ /** The same rowset under another alias, to use it twice in a query. */
38
+ as<TNew extends string>(alias: TNew): RowsSource<TNew, TColumns>
39
+ }
40
+
41
+ function fail(problem: string, fix: string): never {
42
+ throw new Error(`[pipework] rows: ${problem}\n\n Fix: ${fix}\n`)
43
+ }
44
+
45
+ function quote(name: string): string {
46
+ return `"${name.replace(/"/g, '""')}"`
47
+ }
48
+
49
+ // One column as a Postgres array literal, sent as a single text parameter and cast to `T[]`. postgres.js
50
+ // serialises a JS array only for the few element types it knows (text, int, uuid ...), so a `timestamptz[]`
51
+ // parameter would throw; a literal string is parsed by Postgres for any type.
52
+ function arrayLiteral(cells: readonly unknown[]): string {
53
+ const item = (v: unknown): string => {
54
+ if (v === null || v === undefined) return 'NULL'
55
+ const text = v instanceof Date ? v.toISOString()
56
+ : typeof v === 'string' ? v
57
+ : typeof v === 'number' || typeof v === 'bigint' || typeof v === 'boolean' ? String(v)
58
+ : JSON.stringify(v)
59
+ return `"${text.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`
60
+ }
61
+ return `{${cells.map(item).join(',')}}`
62
+ }
63
+
64
+ /**
65
+ * A typed rowset from parallel array parameters, as a source for `.from()` and joins:
66
+ * `rows({ g: 'text', id: 'int' }, { g: ['a', 'b'], id: [1, 2] })` renders
67
+ * `(select * from unnest($1::text[], $2::int[]) as "rows"("g", "id")) "rows"`, one parameter per column
68
+ * whatever the row count, so a 5,000-row key list is two parameters. Each column is read by name, like a
69
+ * table's: `rs.g`. Nulls in an array are NULL cells. Zero rows is valid and returns no rows. Each column
70
+ * is sent as one array-literal text parameter, so any element type Postgres can parse works: Dates as ISO text,
71
+ * objects as JSON (for jsonb). Column names are used as written (not snake-cased); the default alias is `rows`, change it with `.as()`.
72
+ * Throws when the columns are empty, a type is not a plain type name, the data and columns name different keys,
73
+ * or the arrays differ in length.
74
+ */
75
+ export function rows<const TColumns extends RowsColumns>(columns: TColumns, data: RowsData<TColumns>): RowsSource<'rows', TColumns> {
76
+ const names = Object.keys(columns)
77
+ if (names.length === 0) fail('the column spec is empty.', "declare at least one column, e.g. { id: 'uuid' }.")
78
+ for (const name of names) {
79
+ if (!COLUMN_NAME.test(name) || name === 'as' || name === '_') {
80
+ fail(`column name "${name}" is not usable.`, 'use letters, digits and underscores, not starting with a digit, and not "as" or "_".')
81
+ }
82
+ const type = columns[name]
83
+ if (typeof type !== 'string' || type === '') fail(`column "${name}" has no type.`, `give it a type name: { ${name}: 'text' }.`)
84
+ if (!CAST.test(type)) fail(`column "${name}" has type "${type}", which is not a plain type name.`, "pass a type name such as 'uuid' or 'int'.")
85
+ }
86
+ const given = Object.keys(data)
87
+ const unknownKeys = given.filter(k => !names.includes(k))
88
+ if (unknownKeys.length > 0) fail(`values for ${unknownKeys.map(k => `"${k}"`).join(', ')} have no column in the spec.`, 'add the column to the spec or drop its values.')
89
+ const missing = names.filter(k => !given.includes(k))
90
+ if (missing.length > 0) fail(`the spec names ${missing.map(k => `"${k}"`).join(', ')} but the data has no values for it.`, 'pass an array for every column, [] for none.')
91
+ const lengths = new Set<number>()
92
+ for (const name of names) {
93
+ const col = (data as Record<string, unknown>)[name]
94
+ if (!Array.isArray(col)) fail(`values for "${name}" are not an array.`, 'pass one array per column.')
95
+ lengths.add(col.length)
96
+ }
97
+ if (lengths.size > 1) {
98
+ const detail = names.map(n => `${n}: ${((data as Record<string, readonly unknown[]>)[n]!).length}`).join(', ')
99
+ fail(`the column arrays differ in length (${detail}).`, 'pass arrays of one length; row i is the i-th element of each.')
100
+ }
101
+
102
+ const build = (alias: string): RowsSource<string, TColumns> => {
103
+ const arrays = names.map(n => {
104
+ return sql`${sql.param(arrayLiteral((data as Record<string, readonly unknown[]>)[n]!))}::${sql.raw(columns[n]!)}[]`
105
+ })
106
+ const nameList = sql.raw(names.map(quote).join(', '))
107
+ const inner = sql`select * from unnest(${sql.join(arrays, sql`, `)}) as ${sql.raw(quote(alias))}(${nameList})`
108
+ const fields: Record<string, SQL> = {}
109
+ for (const n of names) fields[n] = sql.raw(`${quote(alias)}.${quote(n)}`)
110
+ const subquery = new Subquery(inner, fields, alias)
111
+ const selection = new SelectionProxyHandler<Subquery>({ alias, sqlAliasedBehavior: 'alias', sqlBehavior: 'sql' })
112
+ return new Proxy(subquery, {
113
+ get(target, prop) {
114
+ if (prop === 'as') return (next: string) => build(next)
115
+ return selection.get(target, prop)
116
+ },
117
+ }) as unknown as RowsSource<string, TColumns>
118
+ }
119
+ return build('rows') as RowsSource<'rows', TColumns>
120
+ }