@storecraft/database-sql-base 1.0.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/README.md +126 -0
- package/TODO.md +2 -0
- package/db-strategy.md +3 -0
- package/driver.js +190 -0
- package/index.js +3 -0
- package/migrate.js +66 -0
- package/migrations.mssql/00000_init_tables.js +268 -0
- package/migrations.mysql/00000_init_tables.js +372 -0
- package/migrations.mysql/00001_seed_email_templates.js +1 -0
- package/migrations.postgres/00000_init_tables.js +358 -0
- package/migrations.postgres/00001_seed_email_templates.js +1 -0
- package/migrations.shared/00001_seed_email_templates.js +260 -0
- package/migrations.sqlite/00000_init_tables.js +357 -0
- package/migrations.sqlite/00001_seed_email_templates.js +1 -0
- package/package.json +47 -0
- package/src/con.auth_users.js +159 -0
- package/src/con.collections.js +197 -0
- package/src/con.customers.js +202 -0
- package/src/con.discounts.js +225 -0
- package/src/con.discounts.utils.js +180 -0
- package/src/con.helpers.json.js +231 -0
- package/src/con.helpers.json.mssql.js +233 -0
- package/src/con.helpers.json.mysql.js +239 -0
- package/src/con.helpers.json.postgres.js +223 -0
- package/src/con.helpers.json.sqlite.js +263 -0
- package/src/con.images.js +230 -0
- package/src/con.notifications.js +149 -0
- package/src/con.orders.js +156 -0
- package/src/con.posts.js +147 -0
- package/src/con.products.js +497 -0
- package/src/con.search.js +148 -0
- package/src/con.shared.js +616 -0
- package/src/con.shipping.js +147 -0
- package/src/con.storefronts.js +301 -0
- package/src/con.tags.js +120 -0
- package/src/con.templates.js +133 -0
- package/src/kysely.sanitize.plugin.js +40 -0
- package/src/utils.funcs.js +77 -0
- package/src/utils.query.js +195 -0
- package/tests/query.cursor.test.js +389 -0
- package/tests/query.vql.test.js +71 -0
- package/tests/runner.mssql-local.test.js +118 -0
- package/tests/runner.mysql-local.test.js +101 -0
- package/tests/runner.postgres-local.test.js +99 -0
- package/tests/runner.sqlite-local.test.js +99 -0
- package/tests/sandbox.test.js +71 -0
- package/tsconfig.json +21 -0
- package/types.public.d.ts +19 -0
- package/types.sql.tables.d.ts +247 -0
@@ -0,0 +1,239 @@
|
|
1
|
+
import { SelectQueryNode, sql } from "kysely"
|
2
|
+
import { extract_first_selection, getJsonObjectArgs } from "./con.helpers.json.js"
|
3
|
+
|
4
|
+
/**
|
5
|
+
* A MySQL helper for aggregating a subquery into a JSON array.
|
6
|
+
*
|
7
|
+
* NOTE: This helper is only guaranteed to fully work with the built-in `MysqlDialect`.
|
8
|
+
* While the produced SQL is compatible with all MySQL databases, some 3rd party dialects
|
9
|
+
* may not parse the nested JSON into arrays. In these cases you can use the built in
|
10
|
+
* `ParseJSONResultsPlugin` to parse the results.
|
11
|
+
*
|
12
|
+
* ### Examples
|
13
|
+
*
|
14
|
+
* ```ts
|
15
|
+
* const result = await db
|
16
|
+
* .selectFrom('person')
|
17
|
+
* .select((eb) => [
|
18
|
+
* 'id',
|
19
|
+
* jsonArrayFrom(
|
20
|
+
* eb.selectFrom('pet')
|
21
|
+
* .select(['pet.id as pet_id', 'pet.name'])
|
22
|
+
* .whereRef('pet.owner_id', '=', 'person.id')
|
23
|
+
* .orderBy('pet.name')
|
24
|
+
* ).as('pets')
|
25
|
+
* ])
|
26
|
+
* .execute()
|
27
|
+
*
|
28
|
+
* result[0].id
|
29
|
+
* result[0].pets[0].pet_id
|
30
|
+
* result[0].pets[0].name
|
31
|
+
* ```
|
32
|
+
*
|
33
|
+
* The generated SQL (MySQL):
|
34
|
+
*
|
35
|
+
* ```sql
|
36
|
+
* select `id`, (
|
37
|
+
* select cast(coalesce(json_arrayagg(json_object(
|
38
|
+
* 'pet_id', `agg`.`pet_id`,
|
39
|
+
* 'name', `agg`.`name`
|
40
|
+
* )), '[]') as json) from (
|
41
|
+
* select `pet`.`id` as `pet_id`, `pet`.`name`
|
42
|
+
* from `pet`
|
43
|
+
* where `pet`.`owner_id` = `person`.`id`
|
44
|
+
* order by `pet`.`name`
|
45
|
+
* ) as `agg`
|
46
|
+
* ) as `pets`
|
47
|
+
* from `person`
|
48
|
+
* ```
|
49
|
+
*
|
50
|
+
* @template O
|
51
|
+
* @param {import("./con.helpers.json.js").SelectQueryBuilderExpression<O>} expr
|
52
|
+
* @returns {import("kysely").RawBuilder<import("kysely").Simplify<O>[]>}
|
53
|
+
*/
|
54
|
+
export function mysql_jsonArrayFrom(expr) {
|
55
|
+
return sql`(select cast(coalesce(json_arrayagg(json_object(${sql.join(
|
56
|
+
getMysqlJsonObjectArgs(expr.toOperationNode(), 'agg'),
|
57
|
+
)})), '[]') as json) from ${expr} as agg)`
|
58
|
+
}
|
59
|
+
|
60
|
+
/**
|
61
|
+
* A SQLite helper for aggregating a subquery into a JSON array.
|
62
|
+
*
|
63
|
+
* NOTE: This helper only works correctly if you've installed the `ParseJSONResultsPlugin`.
|
64
|
+
* Otherwise the nested selections will be returned as JSON strings.
|
65
|
+
*
|
66
|
+
* The plugin can be installed like this:
|
67
|
+
*
|
68
|
+
* ```ts
|
69
|
+
* const db = new Kysely({
|
70
|
+
* dialect: new SqliteDialect(config),
|
71
|
+
* plugins: [new ParseJSONResultsPlugin()]
|
72
|
+
* })
|
73
|
+
* ```
|
74
|
+
*
|
75
|
+
* ### Examples
|
76
|
+
*
|
77
|
+
* ```ts
|
78
|
+
* const result = await db
|
79
|
+
* .selectFrom('person')
|
80
|
+
* .select((eb) => [
|
81
|
+
* 'id',
|
82
|
+
* stringArrayFrom(
|
83
|
+
* eb.selectFrom('pet')
|
84
|
+
* .select('pet.name')
|
85
|
+
* .whereRef('pet.owner_id', '=', 'person.id')
|
86
|
+
* .orderBy('pet.name')
|
87
|
+
* ).as('pets')
|
88
|
+
* ])
|
89
|
+
* .execute()
|
90
|
+
*
|
91
|
+
* result[0].pets = ['name1', 'name2', ....]
|
92
|
+
* ```
|
93
|
+
*
|
94
|
+
* The generated SQL (SQLite):
|
95
|
+
*
|
96
|
+
* ```sql
|
97
|
+
* select "id", (
|
98
|
+
* select coalesce(json_group_array("agg"."name"), '[]') from (
|
99
|
+
* select "pet"."name"
|
100
|
+
* from "pet"
|
101
|
+
* where "pet"."owner_id" = "person"."id"
|
102
|
+
* order by "pet"."name"
|
103
|
+
* ) as "agg"
|
104
|
+
* ) as "pets"
|
105
|
+
* from "person"
|
106
|
+
* ```
|
107
|
+
* @template O
|
108
|
+
* @param {import('./con.helpers.json.js').SelectQueryBuilderExpression<O>} expr
|
109
|
+
* @returns {import('kysely').RawBuilder<import('kysely').Simplify<O>[]>}
|
110
|
+
*/
|
111
|
+
export function mysql_stringArrayFrom(expr) {
|
112
|
+
const arg = extract_first_selection(expr, 'agg');
|
113
|
+
return sql`(select cast(coalesce(json_arrayagg(${sql.join([arg])}), '[]') as json) from ${expr} as agg)`
|
114
|
+
}
|
115
|
+
|
116
|
+
|
117
|
+
/**
|
118
|
+
* A MySQL helper for turning a subquery into a JSON object.
|
119
|
+
*
|
120
|
+
* The subquery must only return one row.
|
121
|
+
*
|
122
|
+
* NOTE: This helper is only guaranteed to fully work with the built-in `MysqlDialect`.
|
123
|
+
* While the produced SQL is compatible with all MySQL databases, some 3rd party dialects
|
124
|
+
* may not parse the nested JSON into objects. In these cases you can use the built in
|
125
|
+
* `ParseJSONResultsPlugin` to parse the results.
|
126
|
+
*
|
127
|
+
* ### Examples
|
128
|
+
*
|
129
|
+
* ```ts
|
130
|
+
* const result = await db
|
131
|
+
* .selectFrom('person')
|
132
|
+
* .select((eb) => [
|
133
|
+
* 'id',
|
134
|
+
* jsonObjectFrom(
|
135
|
+
* eb.selectFrom('pet')
|
136
|
+
* .select(['pet.id as pet_id', 'pet.name'])
|
137
|
+
* .whereRef('pet.owner_id', '=', 'person.id')
|
138
|
+
* .where('pet.is_favorite', '=', true)
|
139
|
+
* ).as('favorite_pet')
|
140
|
+
* ])
|
141
|
+
* .execute()
|
142
|
+
*
|
143
|
+
* result[0].id
|
144
|
+
* result[0].favorite_pet.pet_id
|
145
|
+
* result[0].favorite_pet.name
|
146
|
+
* ```
|
147
|
+
*
|
148
|
+
* The generated SQL (MySQL):
|
149
|
+
*
|
150
|
+
* ```sql
|
151
|
+
* select `id`, (
|
152
|
+
* select json_object(
|
153
|
+
* 'pet_id', `obj`.`pet_id`,
|
154
|
+
* 'name', `obj`.`name`
|
155
|
+
* ) from (
|
156
|
+
* select `pet`.`id` as `pet_id`, `pet`.`name`
|
157
|
+
* from `pet`
|
158
|
+
* where `pet`.`owner_id` = `person`.`id`
|
159
|
+
* and `pet`.`is_favorite` = ?
|
160
|
+
* ) as obj
|
161
|
+
* ) as `favorite_pet`
|
162
|
+
* from `person`
|
163
|
+
* ```
|
164
|
+
*
|
165
|
+
* @template O
|
166
|
+
* @param {import("./con.helpers.json.js").SelectQueryBuilderExpression<O>} expr
|
167
|
+
* @returns {import("kysely").RawBuilder<import("kysely").Simplify<O> | null>}
|
168
|
+
*/
|
169
|
+
export function mysql_jsonObjectFrom(expr) {
|
170
|
+
return sql`(select json_object(${sql.join(
|
171
|
+
getMysqlJsonObjectArgs(expr.toOperationNode(), 'obj'),
|
172
|
+
)}) from ${expr} as obj)`
|
173
|
+
}
|
174
|
+
|
175
|
+
/**
|
176
|
+
* The MySQL `json_object` function.
|
177
|
+
*
|
178
|
+
* NOTE: This helper is only guaranteed to fully work with the built-in `MysqlDialect`.
|
179
|
+
* While the produced SQL is compatible with all MySQL databases, some 3rd party dialects
|
180
|
+
* may not parse the nested JSON into objects. In these cases you can use the built in
|
181
|
+
* `ParseJSONResultsPlugin` to parse the results.
|
182
|
+
*
|
183
|
+
* ### Examples
|
184
|
+
*
|
185
|
+
* ```ts
|
186
|
+
* const result = await db
|
187
|
+
* .selectFrom('person')
|
188
|
+
* .select((eb) => [
|
189
|
+
* 'id',
|
190
|
+
* jsonBuildObject({
|
191
|
+
* first: eb.ref('first_name'),
|
192
|
+
* last: eb.ref('last_name'),
|
193
|
+
* full: eb.fn('concat', ['first_name', eb.val(' '), 'last_name'])
|
194
|
+
* }).as('name')
|
195
|
+
* ])
|
196
|
+
* .execute()
|
197
|
+
*
|
198
|
+
* result[0].id
|
199
|
+
* result[0].name.first
|
200
|
+
* result[0].name.last
|
201
|
+
* result[0].name.full
|
202
|
+
* ```
|
203
|
+
*
|
204
|
+
* The generated SQL (MySQL):
|
205
|
+
*
|
206
|
+
* ```sql
|
207
|
+
* select "id", json_object(
|
208
|
+
* 'first', first_name,
|
209
|
+
* 'last', last_name,
|
210
|
+
* 'full', concat(`first_name`, ?, `last_name`)
|
211
|
+
* ) as "name"
|
212
|
+
* from "person"
|
213
|
+
* ```
|
214
|
+
*
|
215
|
+
* @template {Record<string, import("kysely").Expression<unknown>>} O
|
216
|
+
* @param {O} obj
|
217
|
+
* @returns {import("kysely").RawBuilder<import("kysely").Simplify<{[K in keyof O]: O[K] extends Expression<infer V> ? V : never}>>}
|
218
|
+
*/
|
219
|
+
export function mysql_jsonBuildObject(obj) {
|
220
|
+
return sql`json_object(${sql.join(
|
221
|
+
Object.keys(obj).flatMap((k) => [sql.lit(k), obj[k]]),
|
222
|
+
)})`
|
223
|
+
}
|
224
|
+
|
225
|
+
/**
|
226
|
+
*
|
227
|
+
* @param {SelectQueryNode} node
|
228
|
+
* @param {string} table
|
229
|
+
* @returns {import("kysely").Expression<unknown>[]}
|
230
|
+
*/
|
231
|
+
function getMysqlJsonObjectArgs(node, table) {
|
232
|
+
try {
|
233
|
+
return getJsonObjectArgs(node, table)
|
234
|
+
} catch {
|
235
|
+
throw new Error(
|
236
|
+
'MySQL jsonArrayFrom and jsonObjectFrom functions can only handle explicit selections due to limitations of the json_object function. selectAll() is not allowed in the subquery.',
|
237
|
+
)
|
238
|
+
}
|
239
|
+
}
|
@@ -0,0 +1,223 @@
|
|
1
|
+
import { sql} from 'kysely'
|
2
|
+
import { extract_first_selection } from './con.helpers.json.js';
|
3
|
+
|
4
|
+
|
5
|
+
/**
|
6
|
+
* A SQLite helper for aggregating a subquery into a JSON array.
|
7
|
+
*
|
8
|
+
* NOTE: This helper only works correctly if you've installed the `ParseJSONResultsPlugin`.
|
9
|
+
* Otherwise the nested selections will be returned as JSON strings.
|
10
|
+
*
|
11
|
+
* The plugin can be installed like this:
|
12
|
+
*
|
13
|
+
* ```ts
|
14
|
+
* const db = new Kysely({
|
15
|
+
* dialect: new SqliteDialect(config),
|
16
|
+
* plugins: [new ParseJSONResultsPlugin()]
|
17
|
+
* })
|
18
|
+
* ```
|
19
|
+
*
|
20
|
+
* ### Examples
|
21
|
+
*
|
22
|
+
* ```ts
|
23
|
+
* const result = await db
|
24
|
+
* .selectFrom('person')
|
25
|
+
* .select((eb) => [
|
26
|
+
* 'id',
|
27
|
+
* stringArrayFrom(
|
28
|
+
* eb.selectFrom('pet')
|
29
|
+
* .select('pet.name')
|
30
|
+
* .whereRef('pet.owner_id', '=', 'person.id')
|
31
|
+
* .orderBy('pet.name')
|
32
|
+
* ).as('pets')
|
33
|
+
* ])
|
34
|
+
* .execute()
|
35
|
+
*
|
36
|
+
* result[0].pets = ['name1', 'name2', ....]
|
37
|
+
* ```
|
38
|
+
*
|
39
|
+
* The generated SQL (SQLite):
|
40
|
+
*
|
41
|
+
* ```sql
|
42
|
+
* select "id", (
|
43
|
+
* select coalesce(json_group_array("agg"."name"), '[]') from (
|
44
|
+
* select "pet"."name"
|
45
|
+
* from "pet"
|
46
|
+
* where "pet"."owner_id" = "person"."id"
|
47
|
+
* order by "pet"."name"
|
48
|
+
* ) as "agg"
|
49
|
+
* ) as "pets"
|
50
|
+
* from "person"
|
51
|
+
* ```
|
52
|
+
* @template O
|
53
|
+
* @param {import('./con.helpers.json.js').SelectQueryBuilderExpression<O>} expr
|
54
|
+
* @returns {import('kysely').RawBuilder<import('kysely').Simplify<O>[]>}
|
55
|
+
*/
|
56
|
+
export function pg_stringArrayFrom(expr) {
|
57
|
+
const arg = extract_first_selection(expr, 'agg');
|
58
|
+
return sql`(select coalesce(json_agg(${sql.join([arg])}), '[]') from ${expr} as agg)`
|
59
|
+
}
|
60
|
+
|
61
|
+
/**
|
62
|
+
* A postgres helper for aggregating a subquery (or other expression) into a JSONB array.
|
63
|
+
*
|
64
|
+
* ### Examples
|
65
|
+
*
|
66
|
+
* <!-- siteExample("select", "Nested array", 110) -->
|
67
|
+
*
|
68
|
+
* While kysely is not an ORM and it doesn't have the concept of relations, we do provide
|
69
|
+
* helpers for fetching nested objects and arrays in a single query. In this example we
|
70
|
+
* use the `jsonArrayFrom` helper to fetch person's pets along with the person's id.
|
71
|
+
*
|
72
|
+
* Please keep in mind that the helpers under the `kysely/helpers` folder, including
|
73
|
+
* `jsonArrayFrom`, are not guaranteed to work with third party dialects. In order for
|
74
|
+
* them to work, the dialect must automatically parse the `json` data type into
|
75
|
+
* javascript JSON values like objects and arrays. Some dialects might simply return
|
76
|
+
* the data as a JSON string. In these cases you can use the built in `ParseJSONResultsPlugin`
|
77
|
+
* to parse the results.
|
78
|
+
*
|
79
|
+
* ```ts
|
80
|
+
* import { jsonArrayFrom } from 'kysely/helpers/postgres'
|
81
|
+
*
|
82
|
+
* const result = await db
|
83
|
+
* .selectFrom('person')
|
84
|
+
* .select((eb) => [
|
85
|
+
* 'id',
|
86
|
+
* jsonArrayFrom(
|
87
|
+
* eb.selectFrom('pet')
|
88
|
+
* .select(['pet.id as pet_id', 'pet.name'])
|
89
|
+
* .whereRef('pet.owner_id', '=', 'person.id')
|
90
|
+
* .orderBy('pet.name')
|
91
|
+
* ).as('pets')
|
92
|
+
* ])
|
93
|
+
* .execute()
|
94
|
+
* ```
|
95
|
+
*
|
96
|
+
* The generated SQL (PostgreSQL):
|
97
|
+
*
|
98
|
+
* ```sql
|
99
|
+
* select "id", (
|
100
|
+
* select coalesce(json_agg(agg), '[]') from (
|
101
|
+
* select "pet"."id" as "pet_id", "pet"."name"
|
102
|
+
* from "pet"
|
103
|
+
* where "pet"."owner_id" = "person"."id"
|
104
|
+
* order by "pet"."name"
|
105
|
+
* ) as agg
|
106
|
+
* ) as "pets"
|
107
|
+
* from "person"
|
108
|
+
* ```
|
109
|
+
* @template O
|
110
|
+
* @param {import('kysely').Expression<O>} expr
|
111
|
+
* @returns {import('kysely').RawBuilder<import('kysely').Simplify<O>[]>}
|
112
|
+
*/
|
113
|
+
export function pg_jsonArrayFrom(expr) {
|
114
|
+
return sql`(select coalesce(json_agg(agg), '[]') from ${expr} as agg)`
|
115
|
+
}
|
116
|
+
|
117
|
+
/**
|
118
|
+
* A postgres helper for turning a subquery (or other expression) into a JSON object.
|
119
|
+
*
|
120
|
+
* The subquery must only return one row.
|
121
|
+
*
|
122
|
+
* ### Examples
|
123
|
+
*
|
124
|
+
* <!-- siteExample("select", "Nested object", 120) -->
|
125
|
+
*
|
126
|
+
* While kysely is not an ORM and it doesn't have the concept of relations, we do provide
|
127
|
+
* helpers for fetching nested objects and arrays in a single query. In this example we
|
128
|
+
* use the `jsonObjectFrom` helper to fetch person's favorite pet along with the person's id.
|
129
|
+
*
|
130
|
+
* Please keep in mind that the helpers under the `kysely/helpers` folder, including
|
131
|
+
* `jsonObjectFrom`, are not guaranteed to work with 3rd party dialects. In order for
|
132
|
+
* them to work, the dialect must automatically parse the `json` data type into
|
133
|
+
* javascript JSON values like objects and arrays. Some dialects might simply return
|
134
|
+
* the data as a JSON string. In these cases you can use the built in `ParseJSONResultsPlugin`
|
135
|
+
* to parse the results.
|
136
|
+
*
|
137
|
+
* ```ts
|
138
|
+
* import { jsonObjectFrom } from 'kysely/helpers/postgres'
|
139
|
+
*
|
140
|
+
* const result = await db
|
141
|
+
* .selectFrom('person')
|
142
|
+
* .select((eb) => [
|
143
|
+
* 'id',
|
144
|
+
* jsonObjectFrom(
|
145
|
+
* eb.selectFrom('pet')
|
146
|
+
* .select(['pet.id as pet_id', 'pet.name'])
|
147
|
+
* .whereRef('pet.owner_id', '=', 'person.id')
|
148
|
+
* .where('pet.is_favorite', '=', true)
|
149
|
+
* ).as('favorite_pet')
|
150
|
+
* ])
|
151
|
+
* .execute()
|
152
|
+
* ```
|
153
|
+
*
|
154
|
+
* The generated SQL (PostgreSQL):
|
155
|
+
*
|
156
|
+
* ```sql
|
157
|
+
* select "id", (
|
158
|
+
* select to_json(obj) from (
|
159
|
+
* select "pet"."id" as "pet_id", "pet"."name"
|
160
|
+
* from "pet"
|
161
|
+
* where "pet"."owner_id" = "person"."id"
|
162
|
+
* and "pet"."is_favorite" = $1
|
163
|
+
* ) as obj
|
164
|
+
* ) as "favorite_pet"
|
165
|
+
* from "person"
|
166
|
+
* ```
|
167
|
+
* @template O
|
168
|
+
* @param {import('kysely').Expression<O>} expr
|
169
|
+
* @returns {import('kysely').RawBuilder<import('kysely').Simplify<O> | null>}
|
170
|
+
*/
|
171
|
+
export function pg_jsonObjectFrom(expr) {
|
172
|
+
return sql`(select to_json(obj) from ${expr} as obj)`
|
173
|
+
}
|
174
|
+
|
175
|
+
/**
|
176
|
+
* The PostgreSQL `json_build_object` function.
|
177
|
+
*
|
178
|
+
* NOTE: This helper is only guaranteed to fully work with the built-in `PostgresDialect`.
|
179
|
+
* While the produced SQL is compatible with all PostgreSQL databases, some 3rd party dialects
|
180
|
+
* may not parse the nested JSON into objects. In these cases you can use the built in
|
181
|
+
* `ParseJSONResultsPlugin` to parse the results.
|
182
|
+
*
|
183
|
+
* ### Examples
|
184
|
+
*
|
185
|
+
* ```ts
|
186
|
+
* const result = await db
|
187
|
+
* .selectFrom('person')
|
188
|
+
* .select((eb) => [
|
189
|
+
* 'id',
|
190
|
+
* jsonBuildObject({
|
191
|
+
* first: eb.ref('first_name'),
|
192
|
+
* last: eb.ref('last_name'),
|
193
|
+
* full: sql<string>`first_name || ' ' || last_name`
|
194
|
+
* }).as('name')
|
195
|
+
* ])
|
196
|
+
* .execute()
|
197
|
+
*
|
198
|
+
* result[0].id
|
199
|
+
* result[0].name.first
|
200
|
+
* result[0].name.last
|
201
|
+
* result[0].name.full
|
202
|
+
* ```
|
203
|
+
*
|
204
|
+
* The generated SQL (PostgreSQL):
|
205
|
+
*
|
206
|
+
* ```sql
|
207
|
+
* select "id", json_build_object(
|
208
|
+
* 'first', first_name,
|
209
|
+
* 'last', last_name,
|
210
|
+
* 'full', first_name || ' ' || last_name
|
211
|
+
* ) as "name"
|
212
|
+
* from "person"
|
213
|
+
* ```
|
214
|
+
* @template {Record<string, import('kysely').Expression<unknown>>} O
|
215
|
+
* @param {O} obj
|
216
|
+
* @returns { import('kysely').RawBuilder<import('kysely').Simplify<{[K in keyof O]: O[K] extends Expression<infer V> ? V : never}>>}
|
217
|
+
>}
|
218
|
+
*/
|
219
|
+
export function pg_jsonBuildObject(obj) {
|
220
|
+
return sql`json_build_object(${sql.join(
|
221
|
+
Object.keys(obj).flatMap((k) => [sql.lit(k), obj[k]]),
|
222
|
+
)})`
|
223
|
+
}
|