@effect/sql-pg 0.47.0 → 0.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/PgClient.js +145 -100
- package/dist/cjs/PgClient.js.map +1 -1
- package/dist/dts/PgClient.d.ts +11 -62
- package/dist/dts/PgClient.d.ts.map +1 -1
- package/dist/esm/PgClient.js +145 -100
- package/dist/esm/PgClient.js.map +1 -1
- package/package.json +7 -6
- package/src/PgClient.ts +166 -190
package/src/PgClient.ts
CHANGED
|
@@ -5,21 +5,25 @@ import * as Reactivity from "@effect/experimental/Reactivity"
|
|
|
5
5
|
import * as Client from "@effect/sql/SqlClient"
|
|
6
6
|
import type { Connection } from "@effect/sql/SqlConnection"
|
|
7
7
|
import { SqlError } from "@effect/sql/SqlError"
|
|
8
|
-
import type { Custom, Fragment
|
|
8
|
+
import type { Custom, Fragment } from "@effect/sql/Statement"
|
|
9
9
|
import * as Statement from "@effect/sql/Statement"
|
|
10
|
+
import * as Arr from "effect/Array"
|
|
10
11
|
import * as Chunk from "effect/Chunk"
|
|
11
12
|
import * as Config from "effect/Config"
|
|
12
|
-
import type
|
|
13
|
+
import type * as ConfigError from "effect/ConfigError"
|
|
13
14
|
import * as Context from "effect/Context"
|
|
14
15
|
import * as Duration from "effect/Duration"
|
|
15
16
|
import * as Effect from "effect/Effect"
|
|
17
|
+
import * as Fiber from "effect/Fiber"
|
|
16
18
|
import * as Layer from "effect/Layer"
|
|
19
|
+
import * as Option from "effect/Option"
|
|
20
|
+
import * as RcRef from "effect/RcRef"
|
|
17
21
|
import * as Redacted from "effect/Redacted"
|
|
18
|
-
import
|
|
22
|
+
import * as Scope from "effect/Scope"
|
|
19
23
|
import * as Stream from "effect/Stream"
|
|
20
|
-
import type * as NodeStream from "node:stream"
|
|
21
24
|
import type { ConnectionOptions } from "node:tls"
|
|
22
|
-
import
|
|
25
|
+
import * as Pg from "pg"
|
|
26
|
+
import Cursor from "pg-cursor"
|
|
23
27
|
|
|
24
28
|
const ATTR_DB_SYSTEM_NAME = "db.system.name"
|
|
25
29
|
const ATTR_DB_NAMESPACE = "db.namespace"
|
|
@@ -30,13 +34,13 @@ const ATTR_SERVER_PORT = "server.port"
|
|
|
30
34
|
* @category type ids
|
|
31
35
|
* @since 1.0.0
|
|
32
36
|
*/
|
|
33
|
-
export const TypeId:
|
|
37
|
+
export const TypeId: TypeId = "~@effect/sql-pg/PgClient"
|
|
34
38
|
|
|
35
39
|
/**
|
|
36
40
|
* @category type ids
|
|
37
41
|
* @since 1.0.0
|
|
38
42
|
*/
|
|
39
|
-
export type TypeId =
|
|
43
|
+
export type TypeId = "~@effect/sql-pg/PgClient"
|
|
40
44
|
|
|
41
45
|
/**
|
|
42
46
|
* @category models
|
|
@@ -46,7 +50,6 @@ export interface PgClient extends Client.SqlClient {
|
|
|
46
50
|
readonly [TypeId]: TypeId
|
|
47
51
|
readonly config: PgClientConfig
|
|
48
52
|
readonly json: (_: unknown) => Fragment
|
|
49
|
-
readonly array: (_: ReadonlyArray<Primitive>) => Fragment
|
|
50
53
|
readonly listen: (channel: string) => Stream.Stream<string, SqlError>
|
|
51
54
|
readonly notify: (channel: string, payload: string) => Effect.Effect<void, SqlError>
|
|
52
55
|
}
|
|
@@ -72,33 +75,11 @@ export interface PgClientConfig {
|
|
|
72
75
|
readonly username?: string | undefined
|
|
73
76
|
readonly password?: Redacted.Redacted | undefined
|
|
74
77
|
|
|
75
|
-
/**
|
|
76
|
-
* A function returning a custom socket to use. This parameter is not documented
|
|
77
|
-
* in the postgres.js's type signature. See their
|
|
78
|
-
* [readme](https://github.com/porsager/postgres?tab=readme-ov-file#connection-details) instead.
|
|
79
|
-
*
|
|
80
|
-
* @example
|
|
81
|
-
* ```ts
|
|
82
|
-
* import { AuthTypes, Connector } from "@google-cloud/cloud-sql-connector";
|
|
83
|
-
* import { PgClient } from "@effect/sql-pg";
|
|
84
|
-
* import { Config, Effect, Layer } from "effect"
|
|
85
|
-
*
|
|
86
|
-
* const layer = Effect.gen(function*() {
|
|
87
|
-
* const connector = new Connector();
|
|
88
|
-
* const clientOpts = yield* Effect.promise(() => connector.getOptions({
|
|
89
|
-
* instanceConnectionName: "project:region:instance",
|
|
90
|
-
* authType: AuthTypes.IAM,
|
|
91
|
-
* }));
|
|
92
|
-
* return PgClient.layer({ socket: clientOpts.stream, username: "iam-user" });
|
|
93
|
-
* }).pipe(Layer.unwrapEffect)
|
|
94
|
-
* ```
|
|
95
|
-
*/
|
|
96
|
-
readonly socket?: (() => NodeStream.Duplex) | undefined
|
|
97
|
-
|
|
98
78
|
readonly idleTimeout?: Duration.DurationInput | undefined
|
|
99
79
|
readonly connectTimeout?: Duration.DurationInput | undefined
|
|
100
80
|
|
|
101
81
|
readonly maxConnections?: number | undefined
|
|
82
|
+
readonly minConnections?: number | undefined
|
|
102
83
|
readonly connectionTTL?: Duration.DurationInput | undefined
|
|
103
84
|
|
|
104
85
|
readonly applicationName?: string | undefined
|
|
@@ -107,31 +88,7 @@ export interface PgClientConfig {
|
|
|
107
88
|
readonly transformResultNames?: ((str: string) => string) | undefined
|
|
108
89
|
readonly transformQueryNames?: ((str: string) => string) | undefined
|
|
109
90
|
readonly transformJson?: boolean | undefined
|
|
110
|
-
readonly
|
|
111
|
-
readonly prepare?: boolean | undefined
|
|
112
|
-
/**
|
|
113
|
-
* A callback when postgres has a notice, see
|
|
114
|
-
* [readme](https://github.com/porsager/postgres?tab=readme-ov-file#connection-details).
|
|
115
|
-
* By default, postgres.js logs these with console.log.
|
|
116
|
-
* To silence notices, see the following example:
|
|
117
|
-
* @example
|
|
118
|
-
* ```ts
|
|
119
|
-
* import { PgClient } from "@effect/sql-pg";
|
|
120
|
-
* import { Config, Layer } from "effect"
|
|
121
|
-
*
|
|
122
|
-
* const layer = PgClient.layer({ onnotice: Config.succeed(() => {}) })
|
|
123
|
-
* ```
|
|
124
|
-
*/
|
|
125
|
-
readonly onnotice?: (notice: postgres.Notice) => void
|
|
126
|
-
readonly types?: Record<string, postgres.PostgresType> | undefined
|
|
127
|
-
|
|
128
|
-
readonly debug?: postgres.Options<{}>["debug"] | undefined
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
type PartialWithUndefined<T> = { [K in keyof T]?: T[K] | undefined }
|
|
132
|
-
|
|
133
|
-
interface PostgresOptions extends postgres.Options<{}> {
|
|
134
|
-
readonly socket?: (() => NodeStream.Duplex) | undefined
|
|
91
|
+
readonly types?: Pg.CustomTypesConfig | undefined
|
|
135
92
|
}
|
|
136
93
|
|
|
137
94
|
/**
|
|
@@ -153,53 +110,39 @@ export const make = (
|
|
|
153
110
|
).array :
|
|
154
111
|
undefined
|
|
155
112
|
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
? Math.round(
|
|
160
|
-
Duration.toMillis(Duration.decode(options.connectionTTL)) / 1000
|
|
161
|
-
)
|
|
162
|
-
: undefined,
|
|
163
|
-
idle_timeout: options.idleTimeout
|
|
164
|
-
? Math.round(
|
|
165
|
-
Duration.toMillis(Duration.decode(options.idleTimeout)) / 1000
|
|
166
|
-
)
|
|
167
|
-
: undefined,
|
|
168
|
-
connect_timeout: options.connectTimeout
|
|
169
|
-
? Math.round(
|
|
170
|
-
Duration.toMillis(Duration.decode(options.connectTimeout)) / 1000
|
|
171
|
-
)
|
|
172
|
-
: undefined,
|
|
173
|
-
|
|
113
|
+
const pool = new Pg.Pool({
|
|
114
|
+
connectionString: options.url ? Redacted.value(options.url) : undefined,
|
|
115
|
+
user: options.username,
|
|
174
116
|
host: options.host,
|
|
175
|
-
port: options.port,
|
|
176
|
-
ssl: options.ssl,
|
|
177
|
-
path: options.path,
|
|
178
117
|
database: options.database,
|
|
179
|
-
username: options.username,
|
|
180
118
|
password: options.password ? Redacted.value(options.password) : undefined,
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
119
|
+
ssl: options.ssl,
|
|
120
|
+
port: options.port,
|
|
121
|
+
connectionTimeoutMillis: options.connectTimeout
|
|
122
|
+
? Duration.toMillis(options.connectTimeout)
|
|
123
|
+
: undefined,
|
|
124
|
+
idleTimeoutMillis: options.idleTimeout
|
|
125
|
+
? Duration.toMillis(options.idleTimeout)
|
|
126
|
+
: undefined,
|
|
127
|
+
max: options.maxConnections,
|
|
128
|
+
min: options.minConnections,
|
|
129
|
+
maxLifetimeSeconds: options.connectionTTL
|
|
130
|
+
? Duration.toSeconds(options.connectionTTL)
|
|
131
|
+
: undefined,
|
|
132
|
+
application_name: options.applicationName ?? "@effect/sql-pg",
|
|
133
|
+
types: options.types
|
|
134
|
+
})
|
|
191
135
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
: postgres(opts as any)
|
|
136
|
+
pool.on("error", (_err) => {
|
|
137
|
+
})
|
|
195
138
|
|
|
196
139
|
yield* Effect.acquireRelease(
|
|
197
140
|
Effect.tryPromise({
|
|
198
|
-
try: () =>
|
|
141
|
+
try: () => pool.query("SELECT 1"),
|
|
199
142
|
catch: (cause) => new SqlError({ cause, message: "PgClient: Failed to connect" })
|
|
200
143
|
}),
|
|
201
144
|
() =>
|
|
202
|
-
Effect.promise(() =>
|
|
145
|
+
Effect.promise(() => pool.end()).pipe(
|
|
203
146
|
Effect.interruptible,
|
|
204
147
|
Effect.timeoutOption(1000)
|
|
205
148
|
)
|
|
@@ -215,80 +158,133 @@ export const make = (
|
|
|
215
158
|
)
|
|
216
159
|
|
|
217
160
|
class ConnectionImpl implements Connection {
|
|
218
|
-
|
|
161
|
+
readonly pg: Pg.Pool | Pg.PoolClient
|
|
162
|
+
constructor(pg: Pg.Pool | Pg.PoolClient) {
|
|
163
|
+
this.pg = pg
|
|
164
|
+
}
|
|
219
165
|
|
|
220
|
-
private run(query:
|
|
166
|
+
private run(query: string, params: ReadonlyArray<unknown>) {
|
|
221
167
|
return Effect.async<ReadonlyArray<any>, SqlError>((resume) => {
|
|
222
|
-
query
|
|
223
|
-
(
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
168
|
+
this.pg.query(query, params as any, (err, result) => {
|
|
169
|
+
if (err) {
|
|
170
|
+
resume(Effect.fail(new SqlError({ cause: err, message: "Failed to execute statement" })))
|
|
171
|
+
} else {
|
|
172
|
+
// Multi-statement queries return an array of results
|
|
173
|
+
const rows = Array.isArray(result)
|
|
174
|
+
? result.map((r) => r.rows ?? [])
|
|
175
|
+
: result.rows ?? []
|
|
176
|
+
resume(Effect.succeed(rows))
|
|
177
|
+
}
|
|
178
|
+
})
|
|
227
179
|
})
|
|
228
180
|
}
|
|
229
181
|
|
|
230
182
|
execute(
|
|
231
183
|
sql: string,
|
|
232
|
-
params: ReadonlyArray<
|
|
184
|
+
params: ReadonlyArray<unknown>,
|
|
233
185
|
transformRows: (<A extends object>(row: ReadonlyArray<A>) => ReadonlyArray<A>) | undefined
|
|
234
186
|
) {
|
|
235
187
|
return transformRows
|
|
236
|
-
? Effect.map(this.run(
|
|
237
|
-
: this.run(
|
|
188
|
+
? Effect.map(this.run(sql, params), transformRows)
|
|
189
|
+
: this.run(sql, params)
|
|
238
190
|
}
|
|
239
|
-
executeRaw(sql: string, params: ReadonlyArray<
|
|
240
|
-
return
|
|
191
|
+
executeRaw(sql: string, params: ReadonlyArray<unknown>) {
|
|
192
|
+
return Effect.async<Pg.Result, SqlError>((resume) => {
|
|
193
|
+
this.pg.query(sql, params as any, (err, result) => {
|
|
194
|
+
if (err) {
|
|
195
|
+
resume(Effect.fail(new SqlError({ cause: err, message: "Failed to execute statement" })))
|
|
196
|
+
} else {
|
|
197
|
+
resume(Effect.succeed(result))
|
|
198
|
+
}
|
|
199
|
+
})
|
|
200
|
+
})
|
|
241
201
|
}
|
|
242
|
-
executeWithoutTransform(sql: string, params: ReadonlyArray<
|
|
243
|
-
return this.run(
|
|
202
|
+
executeWithoutTransform(sql: string, params: ReadonlyArray<unknown>) {
|
|
203
|
+
return this.run(sql, params)
|
|
244
204
|
}
|
|
245
|
-
executeValues(sql: string, params: ReadonlyArray<
|
|
246
|
-
return
|
|
205
|
+
executeValues(sql: string, params: ReadonlyArray<unknown>) {
|
|
206
|
+
return Effect.async<ReadonlyArray<any>, SqlError>((resume) => {
|
|
207
|
+
this.pg.query(
|
|
208
|
+
{
|
|
209
|
+
text: sql,
|
|
210
|
+
rowMode: "array",
|
|
211
|
+
values: params as Array<string>
|
|
212
|
+
},
|
|
213
|
+
(err, result) => {
|
|
214
|
+
if (err) {
|
|
215
|
+
resume(Effect.fail(new SqlError({ cause: err, message: "Failed to execute statement" })))
|
|
216
|
+
} else {
|
|
217
|
+
resume(Effect.succeed(result.rows))
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
)
|
|
221
|
+
})
|
|
247
222
|
}
|
|
248
223
|
executeUnprepared(
|
|
249
224
|
sql: string,
|
|
250
|
-
params: ReadonlyArray<
|
|
225
|
+
params: ReadonlyArray<unknown>,
|
|
251
226
|
transformRows: (<A extends object>(row: ReadonlyArray<A>) => ReadonlyArray<A>) | undefined
|
|
252
227
|
) {
|
|
253
228
|
return this.execute(sql, params, transformRows)
|
|
254
229
|
}
|
|
255
230
|
executeStream(
|
|
256
231
|
sql: string,
|
|
257
|
-
params: ReadonlyArray<
|
|
232
|
+
params: ReadonlyArray<unknown>,
|
|
258
233
|
transformRows: (<A extends object>(row: ReadonlyArray<A>) => ReadonlyArray<A>) | undefined
|
|
259
234
|
) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
(
|
|
266
|
-
)
|
|
267
|
-
|
|
235
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
236
|
+
const self = this
|
|
237
|
+
return Effect.gen(function*() {
|
|
238
|
+
const cursor = yield* Effect.acquireRelease(
|
|
239
|
+
Effect.sync(() => self.pg.query(new Cursor(sql, params as any))),
|
|
240
|
+
(cursor) => Effect.sync(() => cursor.close())
|
|
241
|
+
)
|
|
242
|
+
const pull = Effect.async<Chunk.Chunk<any>, Option.Option<SqlError>>((resume) => {
|
|
243
|
+
cursor.read(128, (err, rows) => {
|
|
244
|
+
if (err) {
|
|
245
|
+
resume(Effect.fail(Option.some(new SqlError({ cause: err, message: "Failed to execute statement" }))))
|
|
246
|
+
} else if (Arr.isNonEmptyArray(rows)) {
|
|
247
|
+
resume(Effect.succeed(Chunk.unsafeFromArray(transformRows ? transformRows(rows) as any : rows)))
|
|
248
|
+
} else {
|
|
249
|
+
resume(Effect.fail(Option.none()))
|
|
250
|
+
}
|
|
251
|
+
})
|
|
252
|
+
})
|
|
253
|
+
return Stream.repeatEffectChunkOption(pull)
|
|
254
|
+
}).pipe(
|
|
255
|
+
Stream.unwrapScoped
|
|
268
256
|
)
|
|
269
257
|
}
|
|
270
258
|
}
|
|
271
259
|
|
|
260
|
+
const reserveRaw = Effect.async<Pg.PoolClient, SqlError, Scope.Scope>((resume) => {
|
|
261
|
+
const fiber = Option.getOrThrow(Fiber.getCurrentFiber())
|
|
262
|
+
const scope = Context.unsafeGet(fiber.currentContext, Scope.Scope)
|
|
263
|
+
pool.connect((err, client, release) => {
|
|
264
|
+
if (err) {
|
|
265
|
+
resume(Effect.fail(new SqlError({ cause: err, message: "Failed to acquire connection for transaction" })))
|
|
266
|
+
} else {
|
|
267
|
+
resume(Effect.as(Scope.addFinalizer(scope, Effect.sync(release)), client!))
|
|
268
|
+
}
|
|
269
|
+
})
|
|
270
|
+
})
|
|
271
|
+
const reserve = Effect.map(reserveRaw, (client) => new ConnectionImpl(client))
|
|
272
|
+
|
|
273
|
+
const listenClient = yield* RcRef.make({
|
|
274
|
+
acquire: reserveRaw
|
|
275
|
+
})
|
|
276
|
+
|
|
272
277
|
return Object.assign(
|
|
273
278
|
yield* Client.make({
|
|
274
|
-
acquirer: Effect.succeed(new ConnectionImpl(
|
|
275
|
-
transactionAcquirer:
|
|
276
|
-
Effect.acquireRelease(
|
|
277
|
-
Effect.tryPromise({
|
|
278
|
-
try: () => client.reserve(),
|
|
279
|
-
catch: (cause) => new SqlError({ cause, message: "Failed to reserve connection" })
|
|
280
|
-
}),
|
|
281
|
-
(pg) => Effect.sync(() => pg.release())
|
|
282
|
-
),
|
|
283
|
-
(_) => new ConnectionImpl(_)
|
|
284
|
-
),
|
|
279
|
+
acquirer: Effect.succeed(new ConnectionImpl(pool)),
|
|
280
|
+
transactionAcquirer: reserve,
|
|
285
281
|
compiler,
|
|
286
282
|
spanAttributes: [
|
|
287
283
|
...(options.spanAttributes ? Object.entries(options.spanAttributes) : []),
|
|
288
284
|
[ATTR_DB_SYSTEM_NAME, "postgresql"],
|
|
289
|
-
[ATTR_DB_NAMESPACE,
|
|
290
|
-
[ATTR_SERVER_ADDRESS,
|
|
291
|
-
[ATTR_SERVER_PORT,
|
|
285
|
+
[ATTR_DB_NAMESPACE, options.database ?? options.username ?? "postgres"],
|
|
286
|
+
[ATTR_SERVER_ADDRESS, options.host ?? "localhost"],
|
|
287
|
+
[ATTR_SERVER_PORT, options.port ?? 5432]
|
|
292
288
|
],
|
|
293
289
|
transformRows
|
|
294
290
|
}),
|
|
@@ -296,28 +292,42 @@ export const make = (
|
|
|
296
292
|
[TypeId]: TypeId as TypeId,
|
|
297
293
|
config: {
|
|
298
294
|
...options,
|
|
299
|
-
host:
|
|
300
|
-
port:
|
|
301
|
-
username:
|
|
302
|
-
password:
|
|
303
|
-
database:
|
|
295
|
+
host: pool.options.host,
|
|
296
|
+
port: pool.options.port,
|
|
297
|
+
username: pool.options.user,
|
|
298
|
+
password: typeof pool.options.password === "string" ? Redacted.make(pool.options.password) : undefined,
|
|
299
|
+
database: pool.options.database
|
|
304
300
|
},
|
|
305
301
|
json: (_: unknown) => PgJson(_),
|
|
306
|
-
array: (_: ReadonlyArray<Primitive>) => PgArray(_),
|
|
307
302
|
listen: (channel: string) =>
|
|
308
|
-
Stream.asyncPush<string, SqlError>((emit)
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
314
|
-
|
|
303
|
+
Stream.asyncPush<string, SqlError>(Effect.fnUntraced(function*(emit) {
|
|
304
|
+
const client = yield* RcRef.get(listenClient)
|
|
305
|
+
function onNotification(msg: Pg.Notification) {
|
|
306
|
+
if (msg.channel === channel && msg.payload) {
|
|
307
|
+
emit.single(msg.payload)
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
yield* Effect.addFinalizer(() =>
|
|
311
|
+
Effect.promise(() => {
|
|
312
|
+
client.off("notification", onNotification)
|
|
313
|
+
return client.query(`UNLISTEN ${Pg.escapeIdentifier(channel)}`)
|
|
314
|
+
})
|
|
315
315
|
)
|
|
316
|
-
|
|
316
|
+
yield* Effect.tryPromise({
|
|
317
|
+
try: () => client.query(`LISTEN ${Pg.escapeIdentifier(channel)}`),
|
|
318
|
+
catch: (cause) => new SqlError({ cause, message: "Failed to listen" })
|
|
319
|
+
})
|
|
320
|
+
client.on("notification", onNotification)
|
|
321
|
+
})),
|
|
317
322
|
notify: (channel: string, payload: string) =>
|
|
318
|
-
Effect.
|
|
319
|
-
|
|
320
|
-
|
|
323
|
+
Effect.async<void, SqlError>((resume) => {
|
|
324
|
+
pool.query(`NOTIFY ${Pg.escapeIdentifier(channel)}, $1`, [payload], (err) => {
|
|
325
|
+
if (err) {
|
|
326
|
+
resume(Effect.fail(new SqlError({ cause: err, message: "Failed to notify" })))
|
|
327
|
+
} else {
|
|
328
|
+
resume(Effect.void)
|
|
329
|
+
}
|
|
330
|
+
})
|
|
321
331
|
})
|
|
322
332
|
}
|
|
323
333
|
)
|
|
@@ -329,7 +339,7 @@ export const make = (
|
|
|
329
339
|
*/
|
|
330
340
|
export const layerConfig = (
|
|
331
341
|
config: Config.Config.Wrap<PgClientConfig>
|
|
332
|
-
): Layer.Layer<PgClient | Client.SqlClient, ConfigError | SqlError> =>
|
|
342
|
+
): Layer.Layer<PgClient | Client.SqlClient, ConfigError.ConfigError | SqlError> =>
|
|
333
343
|
Layer.scopedContext(
|
|
334
344
|
Config.unwrap(config).pipe(
|
|
335
345
|
Effect.flatMap(make),
|
|
@@ -347,7 +357,7 @@ export const layerConfig = (
|
|
|
347
357
|
*/
|
|
348
358
|
export const layer = (
|
|
349
359
|
config: PgClientConfig
|
|
350
|
-
): Layer.Layer<PgClient | Client.SqlClient,
|
|
360
|
+
): Layer.Layer<PgClient | Client.SqlClient, SqlError> =>
|
|
351
361
|
Layer.scopedContext(
|
|
352
362
|
Effect.map(make(config), (client) =>
|
|
353
363
|
Context.make(PgClient, client).pipe(
|
|
@@ -363,8 +373,6 @@ export const makeCompiler = (
|
|
|
363
373
|
transform?: (_: string) => string,
|
|
364
374
|
transformJson = true
|
|
365
375
|
): Statement.Compiler => {
|
|
366
|
-
const pg = postgres({ max: 0 })
|
|
367
|
-
|
|
368
376
|
const transformValue = transformJson && transform
|
|
369
377
|
? Statement.defaultTransforms(transform).value
|
|
370
378
|
: undefined
|
|
@@ -393,33 +401,12 @@ export const makeCompiler = (
|
|
|
393
401
|
return [
|
|
394
402
|
placeholder(undefined),
|
|
395
403
|
[
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
: transformValue(type.i0)
|
|
400
|
-
) as any
|
|
404
|
+
withoutTransform || transformValue === undefined
|
|
405
|
+
? type.i0
|
|
406
|
+
: transformValue(type.i0)
|
|
401
407
|
]
|
|
402
408
|
]
|
|
403
409
|
}
|
|
404
|
-
case "PgArray": {
|
|
405
|
-
const param = pg.array(type.i0 as any) as any
|
|
406
|
-
const first = type.i0[0]
|
|
407
|
-
switch (typeof first) {
|
|
408
|
-
case "boolean": {
|
|
409
|
-
param.type = 1000
|
|
410
|
-
break
|
|
411
|
-
}
|
|
412
|
-
case "number": {
|
|
413
|
-
param.type = 1022
|
|
414
|
-
break
|
|
415
|
-
}
|
|
416
|
-
default: {
|
|
417
|
-
param.type = 1009
|
|
418
|
-
break
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
return [placeholder(undefined), [param]]
|
|
422
|
-
}
|
|
423
410
|
}
|
|
424
411
|
}
|
|
425
412
|
})
|
|
@@ -431,7 +418,7 @@ const escape = Statement.defaultEscape("\"")
|
|
|
431
418
|
* @category custom types
|
|
432
419
|
* @since 1.0.0
|
|
433
420
|
*/
|
|
434
|
-
export type PgCustom = PgJson
|
|
421
|
+
export type PgCustom = PgJson
|
|
435
422
|
|
|
436
423
|
/**
|
|
437
424
|
* @category custom types
|
|
@@ -443,14 +430,3 @@ interface PgJson extends Custom<"PgJson", unknown> {}
|
|
|
443
430
|
* @since 1.0.0
|
|
444
431
|
*/
|
|
445
432
|
const PgJson = Statement.custom<PgJson>("PgJson")
|
|
446
|
-
|
|
447
|
-
/**
|
|
448
|
-
* @category custom types
|
|
449
|
-
* @since 1.0.0
|
|
450
|
-
*/
|
|
451
|
-
interface PgArray extends Custom<"PgArray", ReadonlyArray<Primitive>> {}
|
|
452
|
-
/**
|
|
453
|
-
* @category custom types
|
|
454
|
-
* @since 1.0.0
|
|
455
|
-
*/
|
|
456
|
-
const PgArray = Statement.custom<PgArray>("PgArray")
|