@effect/sql-pg 0.0.0-snapshot-189d4cae80e186661241002ad9d729628096520f

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.
@@ -0,0 +1,156 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import * as Client from "@effect/sql/Client";
5
+ import { SqlError } from "@effect/sql/Error";
6
+ import * as Statement from "@effect/sql/Statement";
7
+ import * as Chunk from "effect/Chunk";
8
+ import * as Config from "effect/Config";
9
+ import * as Context from "effect/Context";
10
+ import * as Duration from "effect/Duration";
11
+ import * as Effect from "effect/Effect";
12
+ import * as Layer from "effect/Layer";
13
+ import * as Secret from "effect/Secret";
14
+ import * as Stream from "effect/Stream";
15
+ import postgres from "postgres";
16
+ /**
17
+ * @category tags
18
+ * @since 1.0.0
19
+ */
20
+ export const PgClient = /*#__PURE__*/Context.GenericTag("@effect/sql-pg/PgClient");
21
+ const escape = /*#__PURE__*/Statement.defaultEscape("\"");
22
+ /**
23
+ * @category constructors
24
+ * @since 1.0.0
25
+ */
26
+ export const make = options => Effect.gen(function* (_) {
27
+ const compiler = makeCompiler(options.transformQueryNames, options.transformJson);
28
+ const transformRows = Client.defaultTransforms(options.transformResultNames, options.transformJson).array;
29
+ const opts = {
30
+ max: options.maxConnections ?? 10,
31
+ max_lifetime: options.connectionTTL ? Math.round(Duration.toMillis(Duration.decode(options.connectionTTL)) / 1000) : undefined,
32
+ idle_timeout: options.idleTimeout ? Math.round(Duration.toMillis(Duration.decode(options.idleTimeout)) / 1000) : undefined,
33
+ connect_timeout: options.connectTimeout ? Math.round(Duration.toMillis(Duration.decode(options.connectTimeout)) / 1000) : undefined,
34
+ host: options.host,
35
+ port: options.port,
36
+ ssl: options.ssl,
37
+ path: options.path,
38
+ database: options.database,
39
+ username: options.username,
40
+ password: options.password ? Secret.value(options.password) : undefined,
41
+ fetch_types: options.fetchTypes ?? true,
42
+ debug: options.debug
43
+ };
44
+ const client = options.url ? postgres(Secret.value(options.url), opts) : postgres(opts);
45
+ yield* _(Effect.addFinalizer(() => Effect.promise(() => client.end())));
46
+ class ConnectionImpl {
47
+ pg;
48
+ constructor(pg) {
49
+ this.pg = pg;
50
+ }
51
+ run(query) {
52
+ return Effect.async(resume => {
53
+ query.then(_ => resume(Effect.succeed(_)), error => resume(new SqlError({
54
+ error
55
+ })));
56
+ return Effect.sync(() => query.cancel());
57
+ });
58
+ }
59
+ runTransform(query) {
60
+ return options.transformResultNames ? Effect.map(this.run(query), transformRows) : this.run(query);
61
+ }
62
+ execute(sql, params) {
63
+ return this.runTransform(this.pg.unsafe(sql, params));
64
+ }
65
+ executeWithoutTransform(sql, params) {
66
+ return this.run(this.pg.unsafe(sql, params));
67
+ }
68
+ executeValues(sql, params) {
69
+ return this.run(this.pg.unsafe(sql, params).values());
70
+ }
71
+ executeRaw(sql, params) {
72
+ return this.runTransform(this.pg.unsafe(sql, params));
73
+ }
74
+ executeStream(sql, params) {
75
+ return Stream.mapChunks(Stream.fromAsyncIterable(this.pg.unsafe(sql, params).cursor(16), error => new SqlError({
76
+ error
77
+ })), Chunk.flatMap(rows => Chunk.unsafeFromArray(options.transformResultNames ? transformRows(rows) : rows)));
78
+ }
79
+ }
80
+ return Object.assign(Client.make({
81
+ acquirer: Effect.succeed(new ConnectionImpl(client)),
82
+ transactionAcquirer: Effect.map(Effect.acquireRelease(Effect.tryPromise({
83
+ try: () => client.reserve(),
84
+ catch: error => new SqlError({
85
+ error
86
+ })
87
+ }), pg => Effect.sync(() => pg.release())), _ => new ConnectionImpl(_)),
88
+ compiler
89
+ }), {
90
+ config: options,
91
+ json: _ => PgJson(_),
92
+ array: _ => PgArray(_)
93
+ });
94
+ });
95
+ /**
96
+ * @category constructor
97
+ * @since 1.0.0
98
+ */
99
+ export const layer = config => Layer.scoped(PgClient, Effect.flatMap(Config.unwrap(config), make));
100
+ /**
101
+ * @category constructor
102
+ * @since 1.0.0
103
+ */
104
+ export const makeCompiler = (transform, transformJson = true) => {
105
+ const pg = postgres({
106
+ max: 0
107
+ });
108
+ const transformValue = transformJson && transform ? Client.defaultTransforms(transform).value : undefined;
109
+ return Statement.makeCompiler({
110
+ placeholder: _ => `$${_}`,
111
+ onIdentifier: transform ? _ => escape(transform(_)) : escape,
112
+ onRecordUpdate: (placeholders, valueAlias, valueColumns, values) => [`(values ${placeholders}) AS ${valueAlias}${valueColumns}`, values.flat()],
113
+ onCustom: (type, placeholder) => {
114
+ switch (type.kind) {
115
+ case "PgJson":
116
+ {
117
+ return [placeholder(), [pg.json(transformValue !== undefined ? transformValue(type.i0) : type.i0)]];
118
+ }
119
+ case "PgArray":
120
+ {
121
+ const param = pg.array(type.i0);
122
+ const first = type.i0[0];
123
+ switch (typeof first) {
124
+ case "boolean":
125
+ {
126
+ param.type = 1000;
127
+ break;
128
+ }
129
+ case "number":
130
+ {
131
+ param.type = 1022;
132
+ break;
133
+ }
134
+ default:
135
+ {
136
+ param.type = 1009;
137
+ break;
138
+ }
139
+ }
140
+ return [placeholder(), [param]];
141
+ }
142
+ }
143
+ }
144
+ });
145
+ };
146
+ /**
147
+ * @category custom types
148
+ * @since 1.0.0
149
+ */
150
+ const PgJson = /*#__PURE__*/Statement.custom("PgJson");
151
+ /**
152
+ * @category custom types
153
+ * @since 1.0.0
154
+ */
155
+ const PgArray = /*#__PURE__*/Statement.custom("PgArray");
156
+ //# sourceMappingURL=Client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Client.js","names":["Client","SqlError","Statement","Chunk","Config","Context","Duration","Effect","Layer","Secret","Stream","postgres","PgClient","GenericTag","escape","defaultEscape","make","options","gen","_","compiler","makeCompiler","transformQueryNames","transformJson","transformRows","defaultTransforms","transformResultNames","array","opts","max","maxConnections","max_lifetime","connectionTTL","Math","round","toMillis","decode","undefined","idle_timeout","idleTimeout","connect_timeout","connectTimeout","host","port","ssl","path","database","username","password","value","fetch_types","fetchTypes","debug","client","url","addFinalizer","promise","end","ConnectionImpl","pg","constructor","run","query","async","resume","then","succeed","error","sync","cancel","runTransform","map","execute","sql","params","unsafe","executeWithoutTransform","executeValues","values","executeRaw","executeStream","mapChunks","fromAsyncIterable","cursor","flatMap","rows","unsafeFromArray","Object","assign","acquirer","transactionAcquirer","acquireRelease","tryPromise","try","reserve","catch","release","config","json","PgJson","PgArray","layer","scoped","unwrap","transform","transformValue","placeholder","onIdentifier","onRecordUpdate","placeholders","valueAlias","valueColumns","flat","onCustom","type","kind","i0","param","first","custom"],"sources":["../../src/Client.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import * as Command from "@effect/platform/Command";
5
+ import { FileSystem } from "@effect/platform/FileSystem";
6
+ import { Path } from "@effect/platform/Path";
7
+ import * as Migrator from "@effect/sql/Migrator";
8
+ import * as Effect from "effect/Effect";
9
+ import * as Layer from "effect/Layer";
10
+ import * as Secret from "effect/Secret";
11
+ import * as Client from "./Client.js";
12
+ /**
13
+ * @since 1.0.0
14
+ */
15
+ export * from "@effect/sql/Migrator";
16
+ /**
17
+ * @category constructor
18
+ * @since 1.0.0
19
+ */
20
+ export const run = /*#__PURE__*/Migrator.make({
21
+ getClient: Client.PgClient,
22
+ ensureTable(sql, table) {
23
+ return Effect.catchAll(sql`select ${table}::regclass`, () => sql`
24
+ CREATE TABLE ${sql(table)} (
25
+ migration_id integer primary key,
26
+ created_at timestamp with time zone not null default now(),
27
+ name text not null
28
+ )
29
+ `);
30
+ },
31
+ lockTable(sql, table) {
32
+ return sql`
33
+ LOCK TABLE ${sql(table)} IN ACCESS EXCLUSIVE MODE
34
+ `;
35
+ },
36
+ dumpSchema(sql, path, table) {
37
+ const pgDump = args => Effect.gen(function* (_) {
38
+ const dump = yield* _(Command.make("pg_dump", ...args, "--no-owner", "--no-privileges"), Command.env({
39
+ PATH: globalThis.process?.env.PATH,
40
+ PGHOST: sql.config.host,
41
+ PGPORT: sql.config.port?.toString(),
42
+ PGUSER: sql.config.username,
43
+ PGPASSWORD: sql.config.password ? Secret.value(sql.config.password) : undefined,
44
+ PGDATABASE: sql.config.database,
45
+ PGSSLMODE: sql.config.ssl ? "require" : "prefer"
46
+ }), Command.string);
47
+ return dump.replace(/^--.*$/gm, "").replace(/^SET .*$/gm, "").replace(/^SELECT pg_catalog\..*$/gm, "").replace(/\n{2,}/gm, "\n\n").trim();
48
+ }).pipe(Effect.mapError(error => new Migrator.MigrationError({
49
+ reason: "failed",
50
+ message: error.message
51
+ })));
52
+ const pgDumpSchema = pgDump(["--schema-only"]);
53
+ const pgDumpMigrations = pgDump(["--column-inserts", "--data-only", `--table=${table}`]);
54
+ const pgDumpAll = Effect.map(Effect.all([pgDumpSchema, pgDumpMigrations], {
55
+ concurrency: 2
56
+ }), ([schema, migrations]) => schema + "\n\n" + migrations);
57
+ const pgDumpFile = path => Effect.gen(function* (_) {
58
+ const fs = yield* _(FileSystem);
59
+ const path_ = yield* _(Path);
60
+ const dump = yield* _(pgDumpAll);
61
+ yield* _(fs.makeDirectory(path_.dirname(path), {
62
+ recursive: true
63
+ }));
64
+ yield* _(fs.writeFileString(path, dump));
65
+ }).pipe(Effect.mapError(error => new Migrator.MigrationError({
66
+ reason: "failed",
67
+ message: error.message
68
+ })));
69
+ return pgDumpFile(path);
70
+ }
71
+ });
72
+ /**
73
+ * @category layers
74
+ * @since 1.0.0
75
+ */
76
+ export const layer = options => Layer.effectDiscard(run(options));
77
+ //# sourceMappingURL=Migrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Migrator.js","names":["Command","FileSystem","Path","Migrator","Effect","Layer","Secret","Client","run","make","getClient","PgClient","ensureTable","sql","table","catchAll","lockTable","dumpSchema","path","pgDump","args","gen","_","dump","env","PATH","globalThis","process","PGHOST","config","host","PGPORT","port","toString","PGUSER","username","PGPASSWORD","password","value","undefined","PGDATABASE","database","PGSSLMODE","ssl","string","replace","trim","pipe","mapError","error","MigrationError","reason","message","pgDumpSchema","pgDumpMigrations","pgDumpAll","map","all","concurrency","schema","migrations","pgDumpFile","fs","path_","makeDirectory","dirname","recursive","writeFileString","layer","options","effectDiscard"],"sources":["../../src/Migrator.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ /**
5
+ * @since 1.0.0
6
+ */
7
+ export * as client from "./Client.js";
8
+ /**
9
+ * @since 1.0.0
10
+ */
11
+ export * as error from "@effect/sql/Error";
12
+ /**
13
+ * @since 1.0.0
14
+ */
15
+ export * as migrator from "./Migrator.js";
16
+ /**
17
+ * @since 1.0.0
18
+ */
19
+ export * as resolver from "@effect/sql/Resolver";
20
+ /**
21
+ * @since 1.0.0
22
+ */
23
+ export * as schema from "@effect/sql/Schema";
24
+ /**
25
+ * @since 1.0.0
26
+ */
27
+ export * as statement from "@effect/sql/Statement";
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["client","error","migrator","resolver","schema","statement"],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA;;;AAIA;;;AAGA,OAAO,KAAKA,MAAM,MAAM,aAAa;AAErC;;;AAGA,OAAO,KAAKC,KAAK,MAAM,mBAAmB;AAE1C;;;AAGA,OAAO,KAAKC,QAAQ,MAAM,eAAe;AAEzC;;;AAGA,OAAO,KAAKC,QAAQ,MAAM,sBAAsB;AAEhD;;;AAGA,OAAO,KAAKC,MAAM,MAAM,oBAAoB;AAE5C;;;AAGA,OAAO,KAAKC,SAAS,MAAM,uBAAuB","ignoreList":[]}
@@ -0,0 +1,4 @@
1
+ {
2
+ "type": "module",
3
+ "sideEffects": []
4
+ }
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@effect/sql-pg",
3
+ "version": "0.0.0-snapshot-189d4cae80e186661241002ad9d729628096520f",
4
+ "description": "A Postgresql toolkit for Effect",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/effect-ts/effect.git",
9
+ "directory": "packages/sql-pg"
10
+ },
11
+ "sideEffects": [],
12
+ "dependencies": {
13
+ "postgres": "^3.4.4"
14
+ },
15
+ "peerDependencies": {
16
+ "@effect/platform": "^0.0.0-snapshot-189d4cae80e186661241002ad9d729628096520f",
17
+ "@effect/sql": "^0.0.0-snapshot-189d4cae80e186661241002ad9d729628096520f",
18
+ "effect": "^0.0.0-snapshot-189d4cae80e186661241002ad9d729628096520f"
19
+ },
20
+ "main": "./dist/cjs/index.js",
21
+ "module": "./dist/esm/index.js",
22
+ "types": "./dist/dts/index.d.ts",
23
+ "exports": {
24
+ "./package.json": "./package.json",
25
+ ".": {
26
+ "types": "./dist/dts/index.d.ts",
27
+ "import": "./dist/esm/index.js",
28
+ "default": "./dist/cjs/index.js"
29
+ },
30
+ "./Client": {
31
+ "types": "./dist/dts/Client.d.ts",
32
+ "import": "./dist/esm/Client.js",
33
+ "default": "./dist/cjs/Client.js"
34
+ },
35
+ "./Migrator": {
36
+ "types": "./dist/dts/Migrator.d.ts",
37
+ "import": "./dist/esm/Migrator.js",
38
+ "default": "./dist/cjs/Migrator.js"
39
+ }
40
+ },
41
+ "typesVersions": {
42
+ "*": {
43
+ "Client": [
44
+ "./dist/dts/Client.d.ts"
45
+ ],
46
+ "Migrator": [
47
+ "./dist/dts/Migrator.d.ts"
48
+ ]
49
+ }
50
+ }
51
+ }
package/src/Client.ts ADDED
@@ -0,0 +1,290 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import * as Client from "@effect/sql/Client"
5
+ import type { Connection } from "@effect/sql/Connection"
6
+ import { SqlError } from "@effect/sql/Error"
7
+ import type { Custom, Fragment, Primitive } from "@effect/sql/Statement"
8
+ import * as Statement from "@effect/sql/Statement"
9
+ import * as Chunk from "effect/Chunk"
10
+ import * as Config from "effect/Config"
11
+ import type { ConfigError } from "effect/ConfigError"
12
+ import * as Context from "effect/Context"
13
+ import * as Duration from "effect/Duration"
14
+ import * as Effect from "effect/Effect"
15
+ import * as Layer from "effect/Layer"
16
+ import type { Scope } from "effect/Scope"
17
+ import * as Secret from "effect/Secret"
18
+ import * as Stream from "effect/Stream"
19
+ import type { PendingQuery, PendingValuesQuery } from "postgres"
20
+ import postgres from "postgres"
21
+
22
+ /**
23
+ * @category models
24
+ * @since 1.0.0
25
+ */
26
+ export interface PgClient extends Client.Client {
27
+ readonly config: PgClientConfig
28
+ readonly json: (_: unknown) => Fragment
29
+ readonly array: (_: ReadonlyArray<Primitive>) => Fragment
30
+ }
31
+
32
+ /**
33
+ * @category tags
34
+ * @since 1.0.0
35
+ */
36
+ export const PgClient: Context.Tag<PgClient, PgClient> = Context.GenericTag<PgClient>("@effect/sql-pg/PgClient")
37
+
38
+ /**
39
+ * @category constructors
40
+ * @since 1.0.0
41
+ */
42
+ export interface PgClientConfig {
43
+ readonly url?: Secret.Secret | undefined
44
+
45
+ readonly host?: string | undefined
46
+ readonly port?: number | undefined
47
+ readonly path?: string | undefined
48
+ readonly ssl?: boolean | undefined
49
+ readonly database?: string | undefined
50
+ readonly username?: string | undefined
51
+ readonly password?: Secret.Secret | undefined
52
+
53
+ readonly idleTimeout?: Duration.DurationInput | undefined
54
+ readonly connectTimeout?: Duration.DurationInput | undefined
55
+
56
+ readonly maxConnections?: number | undefined
57
+ readonly connectionTTL?: Duration.DurationInput | undefined
58
+
59
+ readonly transformResultNames?: ((str: string) => string) | undefined
60
+ readonly transformQueryNames?: ((str: string) => string) | undefined
61
+ readonly transformJson?: boolean | undefined
62
+ readonly fetchTypes?: boolean | undefined
63
+
64
+ readonly debug?: postgres.Options<{}>["debug"] | undefined
65
+ }
66
+
67
+ const escape = Statement.defaultEscape("\"")
68
+
69
+ type PartialWithUndefined<T> = { [K in keyof T]?: T[K] | undefined }
70
+
71
+ /**
72
+ * @category constructors
73
+ * @since 1.0.0
74
+ */
75
+ export const make = (
76
+ options: PgClientConfig
77
+ ): Effect.Effect<PgClient, never, Scope> =>
78
+ Effect.gen(function*(_) {
79
+ const compiler = makeCompiler(
80
+ options.transformQueryNames,
81
+ options.transformJson
82
+ )
83
+
84
+ const transformRows = Client.defaultTransforms(
85
+ options.transformResultNames!,
86
+ options.transformJson
87
+ ).array
88
+
89
+ const opts: PartialWithUndefined<postgres.Options<{}>> = {
90
+ max: options.maxConnections ?? 10,
91
+ max_lifetime: options.connectionTTL
92
+ ? Math.round(
93
+ Duration.toMillis(Duration.decode(options.connectionTTL)) / 1000
94
+ )
95
+ : undefined,
96
+ idle_timeout: options.idleTimeout
97
+ ? Math.round(
98
+ Duration.toMillis(Duration.decode(options.idleTimeout)) / 1000
99
+ )
100
+ : undefined,
101
+ connect_timeout: options.connectTimeout
102
+ ? Math.round(
103
+ Duration.toMillis(Duration.decode(options.connectTimeout)) / 1000
104
+ )
105
+ : undefined,
106
+
107
+ host: options.host,
108
+ port: options.port,
109
+ ssl: options.ssl,
110
+ path: options.path,
111
+ database: options.database,
112
+ username: options.username,
113
+ password: options.password ? Secret.value(options.password) : undefined,
114
+ fetch_types: options.fetchTypes ?? true,
115
+ debug: options.debug
116
+ }
117
+
118
+ const client = options.url
119
+ ? postgres(Secret.value(options.url), opts as any)
120
+ : postgres(opts as any)
121
+
122
+ yield* _(Effect.addFinalizer(() => Effect.promise(() => client.end())))
123
+
124
+ class ConnectionImpl implements Connection {
125
+ constructor(private readonly pg: postgres.Sql<{}>) {}
126
+
127
+ private run(query: PendingQuery<any> | PendingValuesQuery<any>) {
128
+ return Effect.async<ReadonlyArray<any>, SqlError>((resume) => {
129
+ query.then(
130
+ (_) => resume(Effect.succeed(_)),
131
+ (error) => resume(new SqlError({ error }))
132
+ )
133
+ return Effect.sync(() => query.cancel())
134
+ })
135
+ }
136
+
137
+ private runTransform(query: PendingQuery<any>) {
138
+ return options.transformResultNames
139
+ ? Effect.map(this.run(query), transformRows)
140
+ : this.run(query)
141
+ }
142
+
143
+ execute(sql: string, params: ReadonlyArray<Primitive>) {
144
+ return this.runTransform(this.pg.unsafe(sql, params as any))
145
+ }
146
+ executeWithoutTransform(sql: string, params: ReadonlyArray<Primitive>) {
147
+ return this.run(this.pg.unsafe(sql, params as any))
148
+ }
149
+ executeValues(sql: string, params: ReadonlyArray<Primitive>) {
150
+ return this.run(this.pg.unsafe(sql, params as any).values())
151
+ }
152
+ executeRaw(sql: string, params?: ReadonlyArray<Primitive>) {
153
+ return this.runTransform(this.pg.unsafe(sql, params as any))
154
+ }
155
+ executeStream(sql: string, params: ReadonlyArray<Primitive>) {
156
+ return Stream.mapChunks(
157
+ Stream.fromAsyncIterable(
158
+ this.pg.unsafe(sql, params as any).cursor(16) as AsyncIterable<
159
+ Array<any>
160
+ >,
161
+ (error) => new SqlError({ error })
162
+ ),
163
+ Chunk.flatMap((rows) =>
164
+ Chunk.unsafeFromArray(
165
+ options.transformResultNames ? transformRows(rows) : rows
166
+ )
167
+ )
168
+ )
169
+ }
170
+ }
171
+
172
+ return Object.assign(
173
+ Client.make({
174
+ acquirer: Effect.succeed(new ConnectionImpl(client)),
175
+ transactionAcquirer: Effect.map(
176
+ Effect.acquireRelease(
177
+ Effect.tryPromise({
178
+ try: () => client.reserve(),
179
+ catch: (error) => new SqlError({ error })
180
+ }),
181
+ (pg) => Effect.sync(() => pg.release())
182
+ ),
183
+ (_) => new ConnectionImpl(_)
184
+ ),
185
+ compiler
186
+ }),
187
+ {
188
+ config: options,
189
+ json: (_: unknown) => PgJson(_),
190
+ array: (_: ReadonlyArray<Primitive>) => PgArray(_)
191
+ }
192
+ )
193
+ })
194
+
195
+ /**
196
+ * @category constructor
197
+ * @since 1.0.0
198
+ */
199
+ export const layer: (
200
+ config: Config.Config.Wrap<PgClientConfig>
201
+ ) => Layer.Layer<PgClient, ConfigError> = (
202
+ config: Config.Config.Wrap<PgClientConfig>
203
+ ) => Layer.scoped(PgClient, Effect.flatMap(Config.unwrap(config), make))
204
+
205
+ /**
206
+ * @category constructor
207
+ * @since 1.0.0
208
+ */
209
+ export const makeCompiler = (
210
+ transform?: (_: string) => string,
211
+ transformJson = true
212
+ ): Statement.Compiler => {
213
+ const pg = postgres({ max: 0 })
214
+
215
+ const transformValue = transformJson && transform
216
+ ? Client.defaultTransforms(transform).value
217
+ : undefined
218
+
219
+ return Statement.makeCompiler<PgCustom>({
220
+ placeholder: (_) => `$${_}`,
221
+ onIdentifier: transform ? (_) => escape(transform(_)) : escape,
222
+ onRecordUpdate: (placeholders, valueAlias, valueColumns, values) => [
223
+ `(values ${placeholders}) AS ${valueAlias}${valueColumns}`,
224
+ values.flat()
225
+ ],
226
+ onCustom: (type, placeholder) => {
227
+ switch (type.kind) {
228
+ case "PgJson": {
229
+ return [
230
+ placeholder(),
231
+ [
232
+ pg.json(
233
+ transformValue !== undefined
234
+ ? transformValue(type.i0)
235
+ : type.i0
236
+ ) as any
237
+ ]
238
+ ]
239
+ }
240
+ case "PgArray": {
241
+ const param = pg.array(type.i0 as any) as any
242
+ const first = type.i0[0]
243
+ switch (typeof first) {
244
+ case "boolean": {
245
+ param.type = 1000
246
+ break
247
+ }
248
+ case "number": {
249
+ param.type = 1022
250
+ break
251
+ }
252
+ default: {
253
+ param.type = 1009
254
+ break
255
+ }
256
+ }
257
+ return [placeholder(), [param]]
258
+ }
259
+ }
260
+ }
261
+ })
262
+ }
263
+
264
+ /**
265
+ * @category custom types
266
+ * @since 1.0.0
267
+ */
268
+ export type PgCustom = PgJson | PgArray
269
+
270
+ /**
271
+ * @category custom types
272
+ * @since 1.0.0
273
+ */
274
+ interface PgJson extends Custom<"PgJson", unknown> {}
275
+ /**
276
+ * @category custom types
277
+ * @since 1.0.0
278
+ */
279
+ const PgJson = Statement.custom<PgJson>("PgJson")
280
+
281
+ /**
282
+ * @category custom types
283
+ * @since 1.0.0
284
+ */
285
+ interface PgArray extends Custom<"PgArray", ReadonlyArray<Primitive>> {}
286
+ /**
287
+ * @category custom types
288
+ * @since 1.0.0
289
+ */
290
+ const PgArray = Statement.custom<PgArray>("PgArray")