@storecraft/database-sqlite 1.0.1 → 1.0.2
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 +6 -90
- package/index.js +2 -2
- package/package.json +2 -4
- package/tests/runner.test.js +1 -1
- package/tsconfig.json +1 -1
- package/types.public.d.ts +5 -6
- package/src/con.auth_users.js +0 -160
- package/src/con.collections.js +0 -197
- package/src/con.customers.js +0 -202
- package/src/con.discounts.js +0 -225
- package/src/con.discounts.utils.js +0 -180
- package/src/con.helpers.json.js +0 -231
- package/src/con.helpers.json.mssql.js +0 -233
- package/src/con.helpers.json.mysql.js +0 -239
- package/src/con.helpers.json.postgres.js +0 -223
- package/src/con.helpers.json.sqlite.js +0 -263
- package/src/con.images.js +0 -230
- package/src/con.notifications.js +0 -149
- package/src/con.orders.js +0 -171
- package/src/con.posts.js +0 -147
- package/src/con.products.js +0 -497
- package/src/con.search.js +0 -148
- package/src/con.shared.experiment.js +0 -723
- package/src/con.shared.js +0 -616
- package/src/con.shipping.js +0 -147
- package/src/con.storefronts.js +0 -301
- package/src/con.tags.js +0 -120
- package/src/con.templates.js +0 -133
- package/src/kysely.sanitize.plugin.js +0 -40
- package/src/utils.funcs.js +0 -77
- package/src/utils.query.js +0 -195
- package/tests/query.cursor.test.js +0 -389
- package/tests/query.vql.test.js +0 -71
- package/tests/runner.mssql-local.test.js +0 -118
- package/tests/runner.mysql-local.test.js +0 -103
- package/tests/runner.postgres-local.test.js +0 -103
- package/tests/sandbox.test.js +0 -73
package/src/con.helpers.json.js
DELETED
@@ -1,231 +0,0 @@
|
|
1
|
-
import {
|
2
|
-
AliasNode, ColumnNode, ExpressionWrapper, IdentifierNode,
|
3
|
-
ReferenceNode, SelectQueryNode, TableNode, ValueNode } from 'kysely'
|
4
|
-
import { sqlite_jsonArrayFrom, sqlite_jsonObjectFrom,
|
5
|
-
sqlite_stringArrayFrom } from './con.helpers.json.sqlite.js'
|
6
|
-
import { pg_jsonArrayFrom, pg_jsonObjectFrom,
|
7
|
-
pg_stringArrayFrom } from './con.helpers.json.postgres.js'
|
8
|
-
import { mysql_jsonArrayFrom, mysql_jsonObjectFrom,
|
9
|
-
mysql_stringArrayFrom } from './con.helpers.json.mysql.js'
|
10
|
-
import { mssql_jsonArrayFrom, mssql_jsonObjectFrom,
|
11
|
-
mssql_stringArrayFrom } from './con.helpers.json.mssql.js'
|
12
|
-
|
13
|
-
|
14
|
-
/**
|
15
|
-
* @template O
|
16
|
-
* @typedef {Object} _SelectQueryBuilderExpression
|
17
|
-
* @property {boolean} isSelectQueryBuilder
|
18
|
-
* @property {() => SelectQueryNode} toOperationNode
|
19
|
-
*/
|
20
|
-
|
21
|
-
/**
|
22
|
-
* @template O
|
23
|
-
* @typedef {import('kysely').AliasableExpression<O> & _SelectQueryBuilderExpression<O>} SelectQueryBuilderExpression
|
24
|
-
* @property {boolean} isSelectQueryBuilder
|
25
|
-
* @property {(): SelectQueryNode} toOperationNode
|
26
|
-
*/
|
27
|
-
|
28
|
-
|
29
|
-
/**
|
30
|
-
*
|
31
|
-
* @param {SelectQueryNode} node
|
32
|
-
* @param {string} table
|
33
|
-
* @returns {import('kysely').Expression<unknown>[] }
|
34
|
-
*/
|
35
|
-
export function getJsonObjectArgs(node, table) {
|
36
|
-
/** @type {import('kysely').Expression<unknown>[] } */
|
37
|
-
const args = []
|
38
|
-
|
39
|
-
for (const { selection: s } of node.selections ?? []) {
|
40
|
-
|
41
|
-
if (ReferenceNode.is(s) && ColumnNode.is(s.column)) {
|
42
|
-
args.push(
|
43
|
-
colName(s.column.column.name),
|
44
|
-
colRef(table, s.column.column.name),
|
45
|
-
)
|
46
|
-
} else if (ColumnNode.is(s)) {
|
47
|
-
args.push(colName(s.column.name), colRef(table, s.column.name))
|
48
|
-
} else if (AliasNode.is(s) && IdentifierNode.is(s.alias)) {
|
49
|
-
args.push(colName(s.alias.name), colRef(table, s.alias.name))
|
50
|
-
} else {
|
51
|
-
throw new Error(`can't extract column names from the select query node`)
|
52
|
-
}
|
53
|
-
}
|
54
|
-
|
55
|
-
return args
|
56
|
-
}
|
57
|
-
|
58
|
-
/**
|
59
|
-
*
|
60
|
-
* @param {string} col
|
61
|
-
* @returns {import('kysely').Expression<unknown> }
|
62
|
-
*/
|
63
|
-
function colName(col) {
|
64
|
-
return new ExpressionWrapper(ValueNode.createImmediate(col))
|
65
|
-
}
|
66
|
-
|
67
|
-
/**
|
68
|
-
*
|
69
|
-
* @param {string} table
|
70
|
-
* @param {string} col
|
71
|
-
* @returns {import('kysely').Expression<unknown> }
|
72
|
-
*/
|
73
|
-
function colRef(table, col) {
|
74
|
-
return new ExpressionWrapper(
|
75
|
-
ReferenceNode.create(ColumnNode.create(col), TableNode.create(table)),
|
76
|
-
)
|
77
|
-
}
|
78
|
-
|
79
|
-
/**
|
80
|
-
* @template O
|
81
|
-
* @param {SelectQueryBuilderExpression<O>} expr
|
82
|
-
* @param {string} table
|
83
|
-
* @returns {import('kysely').Expression<unknown>}
|
84
|
-
*/
|
85
|
-
export const extract_first_selection = (expr, table) => {
|
86
|
-
/** @type {any} */
|
87
|
-
let s_ = expr.toOperationNode();
|
88
|
-
/** @type {SelectQueryNode} */
|
89
|
-
const s__ = s_;
|
90
|
-
const s = s__.selections[0].selection;
|
91
|
-
/** @type {import('kysely').Expression<unknown>} */
|
92
|
-
let arg;
|
93
|
-
if (ReferenceNode.is(s) && ColumnNode.is(s.column)) {
|
94
|
-
// console.log('arg ', s)
|
95
|
-
arg = colRef(table, s.column.column.name);
|
96
|
-
} else if (ColumnNode.is(s)) {
|
97
|
-
arg = colRef(table, s.column.name);
|
98
|
-
// console.log('arg ', 2)
|
99
|
-
} else if (AliasNode.is(s) && IdentifierNode.is(s.alias)) {
|
100
|
-
arg = colRef(table, s.alias.name);
|
101
|
-
// console.log('arg ', 3)
|
102
|
-
} else {
|
103
|
-
throw new Error(`can't extract column names from the select query node`)
|
104
|
-
}
|
105
|
-
return arg;
|
106
|
-
}
|
107
|
-
|
108
|
-
/**
|
109
|
-
* ### Examples
|
110
|
-
*
|
111
|
-
* ```ts
|
112
|
-
* const result = await db
|
113
|
-
* .selectFrom('person')
|
114
|
-
* .select((eb) => [
|
115
|
-
* 'id',
|
116
|
-
* jsonArrayFrom(
|
117
|
-
* eb.selectFrom('pet')
|
118
|
-
* .select(['pet.id as pet_id', 'pet.name'])
|
119
|
-
* .whereRef('pet.owner_id', '=', 'person.id')
|
120
|
-
* .orderBy('pet.name')
|
121
|
-
* ).as('pets')
|
122
|
-
* ])
|
123
|
-
* .execute()
|
124
|
-
*
|
125
|
-
* result[0].id
|
126
|
-
* result[0].pets[0].pet_id
|
127
|
-
* result[0].pets[0].name
|
128
|
-
* ```
|
129
|
-
*
|
130
|
-
* @template O
|
131
|
-
* @param {import('./con.helpers.json.js').SelectQueryBuilderExpression<O>} expr
|
132
|
-
* @param {import('../types.public.d.ts').SqlDialectType} sql_type
|
133
|
-
* @returns {import('kysely').RawBuilder<import('kysely').Simplify<O>[]>}
|
134
|
-
*/
|
135
|
-
export function jsonArrayFrom(expr, sql_type) {
|
136
|
-
switch(sql_type) {
|
137
|
-
case 'SQLITE':
|
138
|
-
return sqlite_jsonArrayFrom(expr);
|
139
|
-
case 'POSTGRES':
|
140
|
-
return pg_jsonArrayFrom(expr);
|
141
|
-
case 'MYSQL':
|
142
|
-
return mysql_jsonArrayFrom(expr);
|
143
|
-
case 'MSSQL':
|
144
|
-
return mssql_jsonArrayFrom(expr);
|
145
|
-
default:
|
146
|
-
throw new Error(`sql_type=${sql_type} NOT SUPPORTED !`);
|
147
|
-
}
|
148
|
-
}
|
149
|
-
|
150
|
-
|
151
|
-
/**
|
152
|
-
* A SQLite helper for aggregating a subquery into a JSON array.
|
153
|
-
* ### Examples
|
154
|
-
*
|
155
|
-
* ```ts
|
156
|
-
* const result = await db
|
157
|
-
* .selectFrom('person')
|
158
|
-
* .select((eb) => [
|
159
|
-
* 'id',
|
160
|
-
* stringArrayFrom(
|
161
|
-
* eb.selectFrom('pet')
|
162
|
-
* .select('pet.name')
|
163
|
-
* .whereRef('pet.owner_id', '=', 'person.id')
|
164
|
-
* .orderBy('pet.name')
|
165
|
-
* ).as('pets')
|
166
|
-
* ])
|
167
|
-
* .execute()
|
168
|
-
*
|
169
|
-
* result[0].pets = ['name1', 'name2', ....]
|
170
|
-
* ```
|
171
|
-
* @template O
|
172
|
-
* @param {import('./con.helpers.json.js').SelectQueryBuilderExpression<O>} expr
|
173
|
-
* @param {import('../types.public.d.ts').SqlDialectType} sql_type
|
174
|
-
* @returns {import('kysely').RawBuilder<import('kysely').Simplify<O>[]>}
|
175
|
-
*/
|
176
|
-
export function stringArrayFrom(expr, sql_type) {
|
177
|
-
switch(sql_type) {
|
178
|
-
case 'SQLITE':
|
179
|
-
return sqlite_stringArrayFrom(expr);
|
180
|
-
case 'POSTGRES':
|
181
|
-
return pg_stringArrayFrom(expr);
|
182
|
-
case 'MYSQL':
|
183
|
-
return mysql_stringArrayFrom(expr);
|
184
|
-
case 'MSSQL':
|
185
|
-
return mssql_stringArrayFrom(expr);
|
186
|
-
default:
|
187
|
-
throw new Error(`sql_type=${sql_type} NOT SUPPORTED !`);
|
188
|
-
}
|
189
|
-
}
|
190
|
-
|
191
|
-
/**
|
192
|
-
* ### Examples
|
193
|
-
*
|
194
|
-
* ```ts
|
195
|
-
* const result = await db
|
196
|
-
* .selectFrom('person')
|
197
|
-
* .select((eb) => [
|
198
|
-
* 'id',
|
199
|
-
* jsonObjectFrom(
|
200
|
-
* eb.selectFrom('pet')
|
201
|
-
* .select(['pet.id as pet_id', 'pet.name'])
|
202
|
-
* .whereRef('pet.owner_id', '=', 'person.id')
|
203
|
-
* .where('pet.is_favorite', '=', true)
|
204
|
-
* ).as('favorite_pet')
|
205
|
-
* ])
|
206
|
-
* .execute()
|
207
|
-
*
|
208
|
-
* result[0].id
|
209
|
-
* result[0].favorite_pet.pet_id
|
210
|
-
* result[0].favorite_pet.name
|
211
|
-
* ```
|
212
|
-
*
|
213
|
-
* @template O
|
214
|
-
* @param {import('./con.helpers.json.js').SelectQueryBuilderExpression<O>} expr
|
215
|
-
* @param {import('../types.public.d.ts').SqlDialectType} sql_type
|
216
|
-
* @returns {import('kysely').RawBuilder<import('kysely').Simplify<O> | null>}
|
217
|
-
*/
|
218
|
-
export function jsonObjectFrom(expr, sql_type) {
|
219
|
-
switch(sql_type) {
|
220
|
-
case 'SQLITE':
|
221
|
-
return sqlite_jsonObjectFrom(expr);
|
222
|
-
case 'POSTGRES':
|
223
|
-
return pg_jsonObjectFrom(expr);
|
224
|
-
case 'MYSQL':
|
225
|
-
return mysql_jsonObjectFrom(expr);
|
226
|
-
case 'MSSQL':
|
227
|
-
return mssql_jsonObjectFrom(expr);
|
228
|
-
default:
|
229
|
-
throw new Error(`sql_type=${sql_type} NOT SUPPORTED !`);
|
230
|
-
}
|
231
|
-
}
|
@@ -1,233 +0,0 @@
|
|
1
|
-
import { sql } from "kysely"
|
2
|
-
|
3
|
-
/**
|
4
|
-
* An MS SQL Server helper for aggregating a subquery into a JSON array.
|
5
|
-
*
|
6
|
-
* NOTE: This helper only works correctly if you've installed the `ParseJSONResultsPlugin`.
|
7
|
-
* Otherwise the nested selections will be returned as JSON strings.
|
8
|
-
*
|
9
|
-
* The plugin can be installed like this:
|
10
|
-
*
|
11
|
-
* ```ts
|
12
|
-
* const db = new Kysely({
|
13
|
-
* dialect: new MssqlDialect(config),
|
14
|
-
* plugins: [new ParseJSONResultsPlugin()]
|
15
|
-
* })
|
16
|
-
* ```
|
17
|
-
*
|
18
|
-
* ### Examples
|
19
|
-
*
|
20
|
-
* ```ts
|
21
|
-
* const result = await db
|
22
|
-
* .selectFrom('person')
|
23
|
-
* .select((eb) => [
|
24
|
-
* 'id',
|
25
|
-
* jsonArrayFrom(
|
26
|
-
* eb.selectFrom('pet')
|
27
|
-
* .select(['pet.id as pet_id', 'pet.name'])
|
28
|
-
* .whereRef('pet.owner_id', '=', 'person.id')
|
29
|
-
* .orderBy('pet.name')
|
30
|
-
* .modifyEnd(sql`offset 0 rows`)
|
31
|
-
* ).as('pets')
|
32
|
-
* ])
|
33
|
-
* .execute()
|
34
|
-
*
|
35
|
-
* result[0].id
|
36
|
-
* result[0].pets[0].pet_id
|
37
|
-
* result[0].pets[0].name
|
38
|
-
* ```
|
39
|
-
*
|
40
|
-
* The generated SQL (MS SQL Server):
|
41
|
-
*
|
42
|
-
* ```sql
|
43
|
-
* select "id", (
|
44
|
-
* select coalesce((select * from (
|
45
|
-
* select "pet"."id" as "pet_id", "pet"."name"
|
46
|
-
* from "pet"
|
47
|
-
* where "pet"."owner_id" = "person"."id"
|
48
|
-
* order by "pet"."name"
|
49
|
-
* offset 0 rows
|
50
|
-
* ) as "agg" for json path, include_null_values), '[]')
|
51
|
-
* ) as "pets"
|
52
|
-
* from "person"
|
53
|
-
* ```
|
54
|
-
*
|
55
|
-
* @template O
|
56
|
-
* @param {import("kysely").Expression<O>} expr
|
57
|
-
* @returns {import("kysely").RawBuilder<import("kysely").Simplify<O>[]>}
|
58
|
-
*/
|
59
|
-
export function mssql_jsonArrayFrom(expr) {
|
60
|
-
return sql`coalesce((select * from ${expr} as agg for json path, include_null_values), '[]')`
|
61
|
-
}
|
62
|
-
|
63
|
-
/**
|
64
|
-
* An MS SQL Server helper for aggregating a subquery into a JSON array.
|
65
|
-
*
|
66
|
-
* NOTE: This helper only works correctly if you've installed the `ParseJSONResultsPlugin`.
|
67
|
-
* Otherwise the nested selections will be returned as JSON strings.
|
68
|
-
*
|
69
|
-
* The plugin can be installed like this:
|
70
|
-
*
|
71
|
-
* ```ts
|
72
|
-
* const db = new Kysely({
|
73
|
-
* dialect: new MssqlDialect(config),
|
74
|
-
* plugins: [new ParseJSONResultsPlugin()]
|
75
|
-
* })
|
76
|
-
* ```
|
77
|
-
*
|
78
|
-
* ### Examples
|
79
|
-
*
|
80
|
-
* ```ts
|
81
|
-
* const result = await db
|
82
|
-
* .selectFrom('person')
|
83
|
-
* .select((eb) => [
|
84
|
-
* 'id',
|
85
|
-
* jsonArrayFrom(
|
86
|
-
* eb.selectFrom('pet')
|
87
|
-
* .select(['pet.id as pet_id', 'pet.name'])
|
88
|
-
* .whereRef('pet.owner_id', '=', 'person.id')
|
89
|
-
* .orderBy('pet.name')
|
90
|
-
* .modifyEnd(sql`offset 0 rows`)
|
91
|
-
* ).as('pets')
|
92
|
-
* ])
|
93
|
-
* .execute()
|
94
|
-
*
|
95
|
-
* result[0].id
|
96
|
-
* result[0].pets[0].pet_id
|
97
|
-
* result[0].pets[0].name
|
98
|
-
* ```
|
99
|
-
*
|
100
|
-
* The generated SQL (MS SQL Server):
|
101
|
-
*
|
102
|
-
* ```sql
|
103
|
-
* select "id", (
|
104
|
-
* select coalesce((select * from (
|
105
|
-
* select "pet"."id" as "pet_id", "pet"."name"
|
106
|
-
* from "pet"
|
107
|
-
* where "pet"."owner_id" = "person"."id"
|
108
|
-
* order by "pet"."name"
|
109
|
-
* offset 0 rows
|
110
|
-
* ) as "agg" for json path, include_null_values), '[]')
|
111
|
-
* ) as "pets"
|
112
|
-
* from "person"
|
113
|
-
* ```
|
114
|
-
*
|
115
|
-
* @template O
|
116
|
-
* @param {import("kysely").Expression<O>} expr
|
117
|
-
* @returns {import("kysely").RawBuilder<import("kysely").Simplify<O>[]>}
|
118
|
-
*/
|
119
|
-
export function mssql_stringArrayFrom(expr) {
|
120
|
-
return sql`coalesce((select * from ${expr} as agg for json path, include_null_values), '[]')`
|
121
|
-
}
|
122
|
-
|
123
|
-
|
124
|
-
/**
|
125
|
-
* An MS SQL Server helper for turning a subquery into a JSON object.
|
126
|
-
*
|
127
|
-
* The subquery must only return one row.
|
128
|
-
*
|
129
|
-
* NOTE: This helper only works correctly if you've installed the `ParseJSONResultsPlugin`.
|
130
|
-
* Otherwise the nested selections will be returned as JSON strings.
|
131
|
-
*
|
132
|
-
* The plugin can be installed like this:
|
133
|
-
*
|
134
|
-
* ```ts
|
135
|
-
* const db = new Kysely({
|
136
|
-
* dialect: new MssqlDialect(config),
|
137
|
-
* plugins: [new ParseJSONResultsPlugin()]
|
138
|
-
* })
|
139
|
-
* ```
|
140
|
-
*
|
141
|
-
* ### Examples
|
142
|
-
*
|
143
|
-
* ```ts
|
144
|
-
* const result = await db
|
145
|
-
* .selectFrom('person')
|
146
|
-
* .select((eb) => [
|
147
|
-
* 'id',
|
148
|
-
* jsonObjectFrom(
|
149
|
-
* eb.selectFrom('pet')
|
150
|
-
* .select(['pet.id as pet_id', 'pet.name'])
|
151
|
-
* .whereRef('pet.owner_id', '=', 'person.id')
|
152
|
-
* .where('pet.is_favorite', '=', 1)
|
153
|
-
* ).as('favorite_pet')
|
154
|
-
* ])
|
155
|
-
* .execute()
|
156
|
-
*
|
157
|
-
* result[0].id
|
158
|
-
* result[0].favorite_pet.pet_id
|
159
|
-
* result[0].favorite_pet.name
|
160
|
-
* ```
|
161
|
-
*
|
162
|
-
* The generated SQL (MS SQL Server):
|
163
|
-
*
|
164
|
-
* ```sql
|
165
|
-
* select "id", (
|
166
|
-
* select * from (
|
167
|
-
* select "pet"."id" as "pet_id", "pet"."name"
|
168
|
-
* from "pet"
|
169
|
-
* where "pet"."owner_id" = "person"."id"
|
170
|
-
* and "pet"."is_favorite" = @1
|
171
|
-
* ) as "agg" for json path, include_null_values, without_array_wrapper
|
172
|
-
* ) as "favorite_pet"
|
173
|
-
* from "person"
|
174
|
-
* ```
|
175
|
-
*
|
176
|
-
* @template O
|
177
|
-
* @param {import("kysely").Expression<O>} expr
|
178
|
-
* @returns {import("kysely").RawBuilder<import("kysely").Simplify<O> | null>}
|
179
|
-
*/
|
180
|
-
export function mssql_jsonObjectFrom(expr) {
|
181
|
-
return sql`(select * from ${expr} as agg for json path, include_null_values, without_array_wrapper)`
|
182
|
-
}
|
183
|
-
|
184
|
-
/**
|
185
|
-
* The MS SQL Server `json_query` function, single argument variant.
|
186
|
-
*
|
187
|
-
* NOTE: This helper only works correctly if you've installed the `ParseJSONResultsPlugin`.
|
188
|
-
* Otherwise the nested selections will be returned as JSON strings.
|
189
|
-
*
|
190
|
-
* The plugin can be installed like this:
|
191
|
-
*
|
192
|
-
* ```ts
|
193
|
-
* const db = new Kysely({
|
194
|
-
* dialect: new MssqlDialect(config),
|
195
|
-
* plugins: [new ParseJSONResultsPlugin()]
|
196
|
-
* })
|
197
|
-
* ```
|
198
|
-
*
|
199
|
-
* ### Examples
|
200
|
-
*
|
201
|
-
* ```ts
|
202
|
-
* const result = await db
|
203
|
-
* .selectFrom('person')
|
204
|
-
* .select((eb) => [
|
205
|
-
* 'id',
|
206
|
-
* jsonBuildObject({
|
207
|
-
* first: eb.ref('first_name'),
|
208
|
-
* last: eb.ref('last_name'),
|
209
|
-
* full: eb.fn('concat', ['first_name', eb.val(' '), 'last_name'])
|
210
|
-
* }).as('name')
|
211
|
-
* ])
|
212
|
-
* .execute()
|
213
|
-
* ```
|
214
|
-
*
|
215
|
-
* The generated SQL (MS SQL Server):
|
216
|
-
*
|
217
|
-
* ```sql
|
218
|
-
* select "id", json_query(
|
219
|
-
* '{"first":"'+"first_name"+',"last":"'+"last_name"+',"full":"'+concat("first_name", ' ', "last_name")+'"}'
|
220
|
-
* ) as "name"
|
221
|
-
* from "person"
|
222
|
-
* ```
|
223
|
-
*
|
224
|
-
* @template {Record<string, import("kysely").Expression<unknown>>} O
|
225
|
-
* @param {O} obj
|
226
|
-
* @returns {import("kysely").RawBuilder<import("kysely").Simplify<{[K in keyof O]: O[K] extends Expression<infer V> ? V : never}>>}
|
227
|
-
*/
|
228
|
-
export function mssql_jsonBuildObject(obj) {
|
229
|
-
return sql`json_query('{${sql.join(
|
230
|
-
Object.keys(obj).map((k) => sql`"${sql.raw(k)}":"'+${obj[k]}+'"`),
|
231
|
-
sql`,`,
|
232
|
-
)}}')`
|
233
|
-
}
|
@@ -1,239 +0,0 @@
|
|
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
|
-
}
|