@effect/sql-pg 4.0.0-rc.116 → 4.0.0-rc.118
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/AGENTS.md +4 -4
- package/CLAUDE.md +4 -4
- package/ai-docs/package.json +3 -3
- package/ai-docs/src/01_effect/03_services/20_layer-composition.ts +1 -1
- package/ai-docs/src/01_effect/06_running/20_layer-launch.ts +1 -1
- package/ai-docs/src/03_stream/30_encoding.ts +1 -1
- package/ai-docs/src/08_observability/20_otlp-tracing.ts +2 -2
- package/ai-docs/src/08_observability/index.md +1 -1
- package/ai-docs/src/40_sql/10_basics.ts +2 -2
- package/ai-docs/src/40_sql/index.md +1 -1
- package/ai-docs/src/50_http-client/10_basics.ts +1 -1
- package/ai-docs/src/51_http-server/10_basics.ts +2 -2
- package/ai-docs/src/51_http-server/20_testing.ts +2 -2
- package/ai-docs/src/51_http-server/fixtures/api/Api.ts +1 -1
- package/ai-docs/src/51_http-server/fixtures/api/Authorization.ts +1 -1
- package/ai-docs/src/51_http-server/fixtures/api/System.ts +1 -1
- package/ai-docs/src/51_http-server/fixtures/api/Users.ts +1 -1
- package/ai-docs/src/51_http-server/fixtures/domain/User.ts +1 -1
- package/ai-docs/src/51_http-server/fixtures/server/Users/http.ts +1 -1
- package/ai-docs/src/51_http-server/fixtures/server/Users.ts +1 -1
- package/ai-docs/src/60_child-process/10_working-with-child-processes.ts +1 -1
- package/ai-docs/src/60_child-process/index.md +1 -1
- package/ai-docs/src/70_cli/10_basics.ts +1 -1
- package/ai-docs/src/70_cli/index.md +1 -1
- package/ai-docs/src/71_ai/10_language-model.ts +2 -2
- package/ai-docs/src/71_ai/20_tools.ts +2 -2
- package/ai-docs/src/71_ai/30_chat.ts +2 -2
- package/ai-docs/src/80_cluster/10_entities.ts +3 -3
- package/dist/PgAuth.js +3 -3
- package/dist/PgAuth.js.map +1 -1
- package/dist/PgClient.d.ts +5 -5
- package/dist/PgClient.d.ts.map +1 -1
- package/dist/PgClient.js +14 -3
- package/dist/PgClient.js.map +1 -1
- package/dist/PgConnection.d.ts +20 -6
- package/dist/PgConnection.d.ts.map +1 -1
- package/dist/PgConnection.js +48 -29
- package/dist/PgConnection.js.map +1 -1
- package/dist/PgMigrator.d.ts +5 -5
- package/dist/PgMigrator.d.ts.map +1 -1
- package/dist/PgMigrator.js +4 -4
- package/dist/PgMigrator.js.map +1 -1
- package/dist/PgPool.d.ts +1 -1
- package/dist/PgPool.d.ts.map +1 -1
- package/dist/PgPool.js +4 -7
- package/dist/PgPool.js.map +1 -1
- package/dist/PgTypes.d.ts +2 -0
- package/dist/PgTypes.d.ts.map +1 -1
- package/dist/PgTypes.js +19 -16
- package/dist/PgTypes.js.map +1 -1
- package/dist/internal/sqlError.d.ts +1 -1
- package/dist/internal/sqlError.d.ts.map +1 -1
- package/dist/internal/sqlError.js +1 -1
- package/dist/internal/sqlError.js.map +1 -1
- package/package.json +4 -4
- package/src/PgAuth.ts +3 -3
- package/src/PgClient.ts +26 -6
- package/src/PgConnection.ts +80 -52
- package/src/PgMigrator.ts +6 -6
- package/src/PgPool.ts +5 -8
- package/src/PgTypes.ts +25 -22
- package/src/internal/connection.ts +3 -3
- package/src/internal/sqlError.ts +1 -1
package/src/PgConnection.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Native PostgreSQL sessions built on the `PgProtocol` wire codec.
|
|
3
3
|
*
|
|
4
|
+
* **Details**
|
|
5
|
+
*
|
|
4
6
|
* Sessions support queries, streaming, `LISTEN`/`NOTIFY`, cancellation, and
|
|
5
7
|
* exclusive ownership for transactions.
|
|
6
8
|
*
|
|
@@ -19,14 +21,8 @@ import * as Redacted from "effect/Redacted"
|
|
|
19
21
|
import * as EffectResult from "effect/Result"
|
|
20
22
|
import * as Scope from "effect/Scope"
|
|
21
23
|
import * as Semaphore from "effect/Semaphore"
|
|
24
|
+
import { AuthenticationError, ConnectionError, SqlError, type SqlErrorReason, UnknownError } from "effect/sql/SqlError"
|
|
22
25
|
import * as Stream from "effect/Stream"
|
|
23
|
-
import {
|
|
24
|
-
AuthenticationError,
|
|
25
|
-
ConnectionError,
|
|
26
|
-
SqlError,
|
|
27
|
-
type SqlErrorReason,
|
|
28
|
-
UnknownError
|
|
29
|
-
} from "effect/unstable/sql/SqlError"
|
|
30
26
|
import { Buffer } from "node:buffer"
|
|
31
27
|
import { randomBytes } from "node:crypto"
|
|
32
28
|
import * as Net from "node:net"
|
|
@@ -199,13 +195,28 @@ export interface PgConnection {
|
|
|
199
195
|
* ownership queue, while calls through the original connection wait.
|
|
200
196
|
*/
|
|
201
197
|
readonly pin: Effect.Effect<PgConnection, never, Scope.Scope>
|
|
202
|
-
/**
|
|
198
|
+
/**
|
|
199
|
+
* Runs a query and returns rows keyed by column name. Pass `false` to skip
|
|
200
|
+
* the prepared statement cache.
|
|
201
|
+
*
|
|
202
|
+
* **Details**
|
|
203
|
+
*
|
|
204
|
+
* On interruption, the connection drains to `ReadyForQuery` and sends a
|
|
205
|
+
* `CancelRequest` if needed. Unless the backend confirms cancellation with
|
|
206
|
+
* `57014`, a pool retires the session before its next checkout. A retained
|
|
207
|
+
* checkout and an unpooled session remain exposed to a late cancel.
|
|
208
|
+
* `statement_timeout` also reports `57014` and can be mistaken for
|
|
209
|
+
* confirmation.
|
|
210
|
+
*/
|
|
203
211
|
readonly query: (
|
|
204
212
|
sql: string,
|
|
205
213
|
params?: ReadonlyArray<unknown>,
|
|
206
214
|
prepare?: boolean
|
|
207
215
|
) => Effect.Effect<Result, SqlError>
|
|
208
|
-
/**
|
|
216
|
+
/**
|
|
217
|
+
* Runs a query and returns positional rows. Pass `false` to skip the
|
|
218
|
+
* prepared statement cache. Interruption behaves as for `query`.
|
|
219
|
+
*/
|
|
209
220
|
readonly queryValues: (
|
|
210
221
|
sql: string,
|
|
211
222
|
params?: ReadonlyArray<unknown>,
|
|
@@ -213,9 +224,8 @@ export interface PgConnection {
|
|
|
213
224
|
) => Effect.Effect<ReadonlyArray<ReadonlyArray<unknown>>, SqlError>
|
|
214
225
|
/**
|
|
215
226
|
* Streams rows without collecting the full result. The session is pinned for
|
|
216
|
-
* the lifetime of the stream.
|
|
217
|
-
*
|
|
218
|
-
* and drains the connection back to `ReadyForQuery`.
|
|
227
|
+
* the lifetime of the stream. An early abort behaves like an interrupted
|
|
228
|
+
* `query`.
|
|
219
229
|
*/
|
|
220
230
|
readonly stream: (
|
|
221
231
|
sql: string,
|
|
@@ -317,6 +327,9 @@ interface PipelineEntry {
|
|
|
317
327
|
}
|
|
318
328
|
|
|
319
329
|
const abortDrainTimeoutMillis = 5000
|
|
330
|
+
const abortDrainGraceMillis = 10
|
|
331
|
+
/** PostgreSQL `query_canceled` SQLSTATE. */
|
|
332
|
+
const queryCanceledCode = "57014"
|
|
320
333
|
const cancelRequestTimeoutMillis = 5000
|
|
321
334
|
/** How many statements a multiplexed session keeps on the wire at once. */
|
|
322
335
|
const maxPipelineDepth = 128
|
|
@@ -342,8 +355,9 @@ class PgConnectionImpl implements PgConnection {
|
|
|
342
355
|
consumer: Consumer | undefined
|
|
343
356
|
deadWith: SqlError | undefined
|
|
344
357
|
closed = false
|
|
358
|
+
cancelPending = false
|
|
345
359
|
readonly channels = new Map<string, Set<Queue.Queue<Notification, SqlError>>>()
|
|
346
|
-
readonly
|
|
360
|
+
readonly retireHooks = new Set<() => void>()
|
|
347
361
|
/** Queued but not yet written; drained into `pipelineInFlight` on flush. */
|
|
348
362
|
readonly pipelinePending: Array<PipelineEntry> = []
|
|
349
363
|
/** Written and awaiting their `ReadyForQuery`, oldest first. */
|
|
@@ -367,7 +381,7 @@ class PgConnectionImpl implements PgConnection {
|
|
|
367
381
|
this[internalsKey] = {
|
|
368
382
|
base: this,
|
|
369
383
|
deadError: () => this.deadWith,
|
|
370
|
-
|
|
384
|
+
retireHooks: this.retireHooks
|
|
371
385
|
}
|
|
372
386
|
this.pinnedView = new PinnedPgConnection(this)
|
|
373
387
|
session.socket.on("data", this.onData)
|
|
@@ -399,6 +413,15 @@ class PgConnectionImpl implements PgConnection {
|
|
|
399
413
|
private readonly dispatch = (message: PgProtocol.BackendMessage<unknown>): void => {
|
|
400
414
|
if (this.deadWith !== undefined) return
|
|
401
415
|
switch (message._tag) {
|
|
416
|
+
case "ErrorResponse":
|
|
417
|
+
if (message.fields.code === queryCanceledCode) this.cancelPending = false
|
|
418
|
+
break
|
|
419
|
+
case "ReadyForQuery":
|
|
420
|
+
if (this.cancelPending) {
|
|
421
|
+
this.cancelPending = false
|
|
422
|
+
this.retire()
|
|
423
|
+
}
|
|
424
|
+
break
|
|
402
425
|
case "NotificationResponse": {
|
|
403
426
|
const queues = this.channels.get(message.channel)
|
|
404
427
|
if (queues !== undefined) {
|
|
@@ -440,6 +463,7 @@ class PgConnectionImpl implements PgConnection {
|
|
|
440
463
|
if (destroySocket) this.session.socket.destroy()
|
|
441
464
|
const consumer = this.consumer
|
|
442
465
|
this.consumer = undefined
|
|
466
|
+
this.retire()
|
|
443
467
|
consumer?.onFatal(error)
|
|
444
468
|
const sets = Array.from(this.channels.values())
|
|
445
469
|
this.channels.clear()
|
|
@@ -447,9 +471,11 @@ class PgConnectionImpl implements PgConnection {
|
|
|
447
471
|
for (const set of sets) {
|
|
448
472
|
for (const queue of set) Queue.failCauseUnsafe(queue, cause)
|
|
449
473
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
private retire(): void {
|
|
477
|
+
if (this.closed) return
|
|
478
|
+
for (const hook of this.retireHooks) hook()
|
|
453
479
|
}
|
|
454
480
|
|
|
455
481
|
closeUnsafe(): void {
|
|
@@ -695,6 +721,8 @@ class PgConnectionImpl implements PgConnection {
|
|
|
695
721
|
/** Sends a `CancelRequest` for this session on a side connection. */
|
|
696
722
|
readonly cancel: Effect.Effect<void> = Effect.suspend(() => {
|
|
697
723
|
if (this.deadWith !== undefined) return Effect.void
|
|
724
|
+
this.cancelPending = true
|
|
725
|
+
if (this.consumer === undefined) this.retire()
|
|
698
726
|
return sendCancelRequest(this.resolved, this.session)
|
|
699
727
|
})
|
|
700
728
|
|
|
@@ -1077,6 +1105,7 @@ const encodeQuery = (
|
|
|
1077
1105
|
class PreparedCache {
|
|
1078
1106
|
readonly max: number
|
|
1079
1107
|
private readonly statements = new Map<string, Prepared>()
|
|
1108
|
+
private readonly namespace = randomBytes(8).toString("hex")
|
|
1080
1109
|
private closes: Array<Uint8Array> | undefined
|
|
1081
1110
|
private counter = 0
|
|
1082
1111
|
|
|
@@ -1096,7 +1125,7 @@ class PreparedCache {
|
|
|
1096
1125
|
return found
|
|
1097
1126
|
}
|
|
1098
1127
|
const prepared: Prepared = {
|
|
1099
|
-
name: `
|
|
1128
|
+
name: `effect_${this.namespace}_${++this.counter}`,
|
|
1100
1129
|
key,
|
|
1101
1130
|
ready: false,
|
|
1102
1131
|
parsing: false,
|
|
@@ -1457,6 +1486,32 @@ class QueryMachine implements Consumer {
|
|
|
1457
1486
|
const emptyRows: ReadonlyArray<Row> = []
|
|
1458
1487
|
const emptyValues: ReadonlyArray<ReadonlyArray<unknown>> = []
|
|
1459
1488
|
|
|
1489
|
+
/** Drains an aborted statement, sending a cancel after a short grace period and failing if it stalls. */
|
|
1490
|
+
const drainAborted = (
|
|
1491
|
+
conn: PgConnectionImpl,
|
|
1492
|
+
timeoutMessage: string,
|
|
1493
|
+
abort: (onDrained: () => void) => void
|
|
1494
|
+
): Effect.Effect<void> => {
|
|
1495
|
+
const drained = Deferred.makeUnsafe<void>()
|
|
1496
|
+
const timeout = setTimeout(
|
|
1497
|
+
() => conn.fatal(connectionQueryError(new Error(timeoutMessage), `PgConnection: ${timeoutMessage}`)),
|
|
1498
|
+
abortDrainTimeoutMillis
|
|
1499
|
+
)
|
|
1500
|
+
abort(() => {
|
|
1501
|
+
clearTimeout(timeout)
|
|
1502
|
+
Deferred.doneUnsafe(drained, Effect.void)
|
|
1503
|
+
})
|
|
1504
|
+
const grace = Effect.callback<void>((resume) => {
|
|
1505
|
+
const timer = setTimeout(() => resume(Effect.void), abortDrainGraceMillis)
|
|
1506
|
+
return Effect.sync(() => clearTimeout(timer))
|
|
1507
|
+
})
|
|
1508
|
+
const cancelAndDrain = Effect.andThen(conn.cancel, Deferred.await(drained))
|
|
1509
|
+
return Effect.andThen(
|
|
1510
|
+
Effect.raceFirst(Deferred.await(drained), grace),
|
|
1511
|
+
Effect.suspend(() => Deferred.isDoneUnsafe(drained) ? Effect.void : cancelAndDrain)
|
|
1512
|
+
)
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1460
1515
|
/** One cycle on a connection that carries a single statement at a time. */
|
|
1461
1516
|
const runQuery = (
|
|
1462
1517
|
conn: PgConnectionImpl,
|
|
@@ -1482,26 +1537,13 @@ const runQuery = (
|
|
|
1482
1537
|
conn.fatal(connectionQueryError(cause, "PgConnection: Failed to write query"))
|
|
1483
1538
|
}
|
|
1484
1539
|
|
|
1485
|
-
// On interruption: cancel the statement and drain the connection back to
|
|
1486
|
-
// ReadyForQuery so it stays usable, destroying it when the drain stalls.
|
|
1487
1540
|
return Effect.suspend(() => {
|
|
1488
1541
|
if (machine.isDone()) return Effect.void
|
|
1489
|
-
|
|
1490
|
-
const timer = setTimeout(
|
|
1491
|
-
() =>
|
|
1492
|
-
conn.fatal(connectionQueryError(
|
|
1493
|
-
new Error("Query cancellation timed out"),
|
|
1494
|
-
"PgConnection: Query cancellation timed out"
|
|
1495
|
-
)),
|
|
1496
|
-
abortDrainTimeoutMillis
|
|
1497
|
-
)
|
|
1542
|
+
return drainAborted(conn, "Query cancellation timed out", (onDrained) =>
|
|
1498
1543
|
machine.abort(() => {
|
|
1499
|
-
clearTimeout(timer)
|
|
1500
1544
|
conn.consumer = undefined
|
|
1501
|
-
|
|
1502
|
-
})
|
|
1503
|
-
})
|
|
1504
|
-
return Effect.andThen(conn.cancel, wait)
|
|
1545
|
+
onDrained()
|
|
1546
|
+
}))
|
|
1505
1547
|
})
|
|
1506
1548
|
})
|
|
1507
1549
|
|
|
@@ -1746,30 +1788,16 @@ const streamRows = (
|
|
|
1746
1788
|
else if (buffer.length >= streamPauseThreshold) setPaused(true)
|
|
1747
1789
|
}
|
|
1748
1790
|
|
|
1749
|
-
// On early abort: cancel the statement and drain back to ReadyForQuery so
|
|
1750
|
-
// the pinned connection stays usable, destroying it when the drain stalls.
|
|
1751
1791
|
yield* Scope.addFinalizer(
|
|
1752
1792
|
scope,
|
|
1753
1793
|
Effect.suspend(() => {
|
|
1754
1794
|
if (done) return Effect.void
|
|
1755
1795
|
aborted = true
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
if (done) return resumeWait(Effect.void)
|
|
1759
|
-
const timer = setTimeout(
|
|
1760
|
-
() =>
|
|
1761
|
-
conn.fatal(connectionQueryError(
|
|
1762
|
-
new Error("Stream cancellation timed out"),
|
|
1763
|
-
"PgConnection: Stream cancellation timed out"
|
|
1764
|
-
)),
|
|
1765
|
-
abortDrainTimeoutMillis
|
|
1766
|
-
)
|
|
1767
|
-
drainDone = () => {
|
|
1768
|
-
clearTimeout(timer)
|
|
1769
|
-
resumeWait(Effect.void)
|
|
1770
|
-
}
|
|
1796
|
+
const drain = drainAborted(conn, "Stream cancellation timed out", (onDrained) => {
|
|
1797
|
+
drainDone = onDrained
|
|
1771
1798
|
})
|
|
1772
|
-
|
|
1799
|
+
setPaused(false)
|
|
1800
|
+
return drain
|
|
1773
1801
|
})
|
|
1774
1802
|
)
|
|
1775
1803
|
|
package/src/PgMigrator.ts
CHANGED
|
@@ -13,18 +13,18 @@ import * as Effect from "effect/Effect"
|
|
|
13
13
|
import * as FileSystem from "effect/FileSystem"
|
|
14
14
|
import * as Layer from "effect/Layer"
|
|
15
15
|
import * as Path from "effect/Path"
|
|
16
|
-
import * as ChildProcess from "effect/
|
|
17
|
-
import * as ChildProcessSpawner from "effect/
|
|
18
|
-
import * as Migrator from "effect/
|
|
19
|
-
import type { SqlClient } from "effect/
|
|
20
|
-
import type { SqlError } from "effect/
|
|
16
|
+
import * as ChildProcess from "effect/process/ChildProcess"
|
|
17
|
+
import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner"
|
|
18
|
+
import * as Migrator from "effect/sql/Migrator"
|
|
19
|
+
import type { SqlClient } from "effect/sql/SqlClient"
|
|
20
|
+
import type { SqlError } from "effect/sql/SqlError"
|
|
21
21
|
import * as Password from "./internal/password.ts"
|
|
22
22
|
import { PgClient } from "./PgClient.ts"
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* @since 4.0.0
|
|
26
26
|
*/
|
|
27
|
-
export * from "effect/
|
|
27
|
+
export * from "effect/sql/Migrator"
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* Runs PostgreSQL SQL migrations using the configured clients. Schema dumps use `pg_dump` and require child process, filesystem, and path services.
|
package/src/PgPool.ts
CHANGED
|
@@ -9,7 +9,7 @@ import * as Duration from "effect/Duration"
|
|
|
9
9
|
import * as Effect from "effect/Effect"
|
|
10
10
|
import * as Pool from "effect/Pool"
|
|
11
11
|
import type * as Scope from "effect/Scope"
|
|
12
|
-
import type { SqlError } from "effect/
|
|
12
|
+
import type { SqlError } from "effect/sql/SqlError"
|
|
13
13
|
import { connectionInternals } from "./internal/connection.ts"
|
|
14
14
|
import * as PgConnection from "./PgConnection.ts"
|
|
15
15
|
|
|
@@ -140,7 +140,7 @@ export const make = Effect.fnUntraced(function*(options: Config): Effect.fn.Retu
|
|
|
140
140
|
Effect.sync(() => {
|
|
141
141
|
createdAt.set(connection, clock.currentTimeMillisUnsafe())
|
|
142
142
|
const internals = connectionInternals(connection)
|
|
143
|
-
internals.
|
|
143
|
+
internals.retireHooks.add(() => {
|
|
144
144
|
deadConnections.add(connection)
|
|
145
145
|
// `deadConnections` is only read by the next checkout, and a checkout
|
|
146
146
|
// already waiting for this connection would never get that far. Tell
|
|
@@ -204,12 +204,9 @@ export const make = Effect.fnUntraced(function*(options: Config): Effect.fn.Retu
|
|
|
204
204
|
// `pin` reserves the pool item itself, so this needs no help.
|
|
205
205
|
const reserve = Effect.flatMap(get, (connection) => connection.pin)
|
|
206
206
|
|
|
207
|
-
// `Pool.use` cannot check
|
|
208
|
-
//
|
|
209
|
-
//
|
|
210
|
-
// checkout does its replacement pass first. Checking inside the callback
|
|
211
|
-
// instead would hold one lease while acquiring another, which deadlocks a
|
|
212
|
-
// pool of one.
|
|
207
|
+
// `Pool.use` cannot pre-check a session. Use it only when no TTL applies and
|
|
208
|
+
// no connection awaits retirement. Checking inside its callback can deadlock
|
|
209
|
+
// a size-one pool while acquiring a replacement.
|
|
213
210
|
const use = <A, E, R>(
|
|
214
211
|
f: (connection: PgConnection.PgConnection) => Effect.Effect<A, E, R>
|
|
215
212
|
): Effect.Effect<A, E | SqlError, R> =>
|
package/src/PgTypes.ts
CHANGED
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
* @since 4.0.0
|
|
30
30
|
*/
|
|
31
31
|
import * as Data from "effect/Data"
|
|
32
|
+
import * as IpInterface from "effect/net/IpInterface"
|
|
33
|
+
import * as IpNetwork from "effect/net/IpNetwork"
|
|
34
|
+
import * as NetAddress from "effect/net/NetAddress"
|
|
32
35
|
import * as Result from "effect/Result"
|
|
33
|
-
import * as IpInterface from "effect/unstable/net/IpInterface"
|
|
34
|
-
import * as IpNetwork from "effect/unstable/net/IpNetwork"
|
|
35
|
-
import * as NetAddress from "effect/unstable/net/NetAddress"
|
|
36
36
|
import type * as PgProtocol from "./PgProtocol.ts"
|
|
37
37
|
import type { ValueSink } from "./PgProtocol.ts"
|
|
38
38
|
|
|
@@ -313,6 +313,7 @@ export const OID = {
|
|
|
313
313
|
timestamptz: 1184,
|
|
314
314
|
timetz: 1266,
|
|
315
315
|
numeric: 1700,
|
|
316
|
+
regclass: 2205,
|
|
316
317
|
uuid: 2950,
|
|
317
318
|
jsonb: 3802,
|
|
318
319
|
boolArray: 1000,
|
|
@@ -336,6 +337,7 @@ export const OID = {
|
|
|
336
337
|
timestamptzArray: 1185,
|
|
337
338
|
timetzArray: 1270,
|
|
338
339
|
numericArray: 1231,
|
|
340
|
+
regclassArray: 2210,
|
|
339
341
|
uuidArray: 2951,
|
|
340
342
|
jsonbArray: 3807
|
|
341
343
|
} as const
|
|
@@ -362,6 +364,7 @@ const arrayToElement = new Map<number, number>([
|
|
|
362
364
|
[OID.timestamptzArray, OID.timestamptz],
|
|
363
365
|
[OID.timetzArray, OID.timetz],
|
|
364
366
|
[OID.numericArray, OID.numeric],
|
|
367
|
+
[OID.regclassArray, OID.regclass],
|
|
365
368
|
[OID.uuidArray, OID.uuid],
|
|
366
369
|
[OID.jsonbArray, OID.jsonb]
|
|
367
370
|
])
|
|
@@ -1160,6 +1163,23 @@ const jsonbCodec: UnsafeCodec<any> = codecOf(
|
|
|
1160
1163
|
}
|
|
1161
1164
|
)
|
|
1162
1165
|
|
|
1166
|
+
const oidCodec: UnsafeCodec<any> = codecOf(
|
|
1167
|
+
(bytes, offset, size) => {
|
|
1168
|
+
requireSize(size, 4, "oid")
|
|
1169
|
+
return readUint32(bytes, offset)
|
|
1170
|
+
},
|
|
1171
|
+
(value) => {
|
|
1172
|
+
const num = requireInteger(value, "oid", 0, 4294967295)
|
|
1173
|
+
const bytes = new Uint8Array(4)
|
|
1174
|
+
bytes[0] = num >>> 24
|
|
1175
|
+
bytes[1] = num >>> 16
|
|
1176
|
+
bytes[2] = num >>> 8
|
|
1177
|
+
bytes[3] = num
|
|
1178
|
+
return bytes
|
|
1179
|
+
},
|
|
1180
|
+
(sink, value) => sink.int32(requireInteger(value, "oid", 0, 4294967295))
|
|
1181
|
+
)
|
|
1182
|
+
|
|
1163
1183
|
const builtinScalars = new Map<number, UnsafeCodec<any>>([
|
|
1164
1184
|
[
|
|
1165
1185
|
OID.bool,
|
|
@@ -1224,25 +1244,8 @@ const builtinScalars = new Map<number, UnsafeCodec<any>>([
|
|
|
1224
1244
|
(sink, value) => sink.int32(requireInteger(value, "int4", INT32_MIN, INT32_MAX))
|
|
1225
1245
|
)
|
|
1226
1246
|
],
|
|
1227
|
-
[
|
|
1228
|
-
|
|
1229
|
-
codecOf(
|
|
1230
|
-
(bytes, offset, size) => {
|
|
1231
|
-
requireSize(size, 4, "oid")
|
|
1232
|
-
return readUint32(bytes, offset)
|
|
1233
|
-
},
|
|
1234
|
-
(value) => {
|
|
1235
|
-
const num = requireInteger(value, "oid", 0, 4294967295)
|
|
1236
|
-
const bytes = new Uint8Array(4)
|
|
1237
|
-
bytes[0] = num >>> 24
|
|
1238
|
-
bytes[1] = num >>> 16
|
|
1239
|
-
bytes[2] = num >>> 8
|
|
1240
|
-
bytes[3] = num
|
|
1241
|
-
return bytes
|
|
1242
|
-
},
|
|
1243
|
-
(sink, value) => sink.int32(requireInteger(value, "oid", 0, 4294967295))
|
|
1244
|
-
)
|
|
1245
|
-
],
|
|
1247
|
+
[OID.oid, oidCodec],
|
|
1248
|
+
[OID.regclass, oidCodec],
|
|
1246
1249
|
[
|
|
1247
1250
|
OID.int8,
|
|
1248
1251
|
codecOf(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type * as Effect from "effect/Effect"
|
|
2
2
|
import type * as Scope from "effect/Scope"
|
|
3
|
-
import type { SqlError } from "effect/
|
|
3
|
+
import type { SqlError } from "effect/sql/SqlError"
|
|
4
4
|
|
|
5
5
|
/** @internal */
|
|
6
6
|
export const internalsKey = "~@effect/sql-pg/PgConnection/internals" as const
|
|
@@ -10,8 +10,8 @@ export interface ConnectionInternals {
|
|
|
10
10
|
/** The pool item identity: the unpinned base connection. */
|
|
11
11
|
readonly base: object
|
|
12
12
|
readonly deadError: () => SqlError | undefined
|
|
13
|
-
/** Fired
|
|
14
|
-
readonly
|
|
13
|
+
/** Fired when a pool must stop reusing the connection. */
|
|
14
|
+
readonly retireHooks: Set<() => void>
|
|
15
15
|
/**
|
|
16
16
|
* Installed by a multiplexed pool so that pinning the session also takes it
|
|
17
17
|
* out of shared circulation for as long as the pin lasts. Every route to an
|