@storecraft/database-sql-base 1.0.12 → 1.0.14
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/index.js +20 -19
- package/migrations.mysql/00003_alter_auth_users.js +1 -0
- package/migrations.postgres/00003_alter_auth_users.js +1 -0
- package/migrations.shared/00003_alter_auth_users.js +37 -0
- package/migrations.sqlite/00003_alter_auth_users.js +1 -0
- package/package.json +1 -1
- package/src/con.auth_users.js +21 -20
- package/src/con.collections.js +123 -22
- package/src/con.customers.js +51 -16
- package/src/con.discounts.js +193 -58
- package/src/con.discounts.utils.js +13 -12
- package/src/con.helpers.json.js +34 -30
- package/src/con.helpers.json.mysql.js +39 -19
- package/src/con.helpers.json.postgres.js +14 -8
- package/src/con.helpers.json.sqlite.js +35 -15
- package/src/con.notifications.js +10 -6
- package/src/con.orders.js +4 -3
- package/src/con.posts.js +6 -6
- package/src/con.products.js +82 -33
- package/src/con.search.js +1 -7
- package/src/con.shared.experiment.js +1 -0
- package/src/con.shared.js +110 -63
- package/src/con.shipping.js +6 -6
- package/src/con.storefronts.js +170 -90
- package/src/con.tags.js +9 -5
- package/src/con.templates.js +3 -1
- package/src/utils.funcs.js +6 -2
- package/src/utils.query.js +24 -20
- package/src/utils.types.d.ts +25 -0
- package/tests/Untitled-1.sqlite3-query +19 -0
- package/tests/sandbox.js +210 -0
- package/types.sql.tables.d.ts +76 -22
- package/src/con.helpers.json.mssql.js +0 -233
- package/tests/sandbox.test.js +0 -73
package/src/con.discounts.js
CHANGED
@@ -2,15 +2,19 @@
|
|
2
2
|
* @import { db_discounts as db_col } from '@storecraft/core/database'
|
3
3
|
*/
|
4
4
|
import { enums } from '@storecraft/core/api'
|
5
|
+
import {
|
6
|
+
helper_compute_product_extra_search_keywords_because_of_discount_side_effect_for_db,
|
7
|
+
helper_compute_product_extra_tags_because_of_discount_side_effect_for_db
|
8
|
+
} from '@storecraft/core/database'
|
5
9
|
import { SQL } from '../index.js'
|
6
10
|
import { discount_to_conjunctions } from './con.discounts.utils.js'
|
7
|
-
import {
|
11
|
+
import {
|
12
|
+
delete_entity_values_by_value_or_reporter_and_context,
|
8
13
|
delete_me, delete_media_of, delete_search_of,
|
9
14
|
delete_tags_of, insert_media_of, insert_search_of,
|
10
|
-
insert_tags_of,
|
11
|
-
with_media, with_tags,
|
12
|
-
|
13
|
-
with_search} from './con.shared.js'
|
15
|
+
insert_tags_of, regular_upsert_me, where_id_or_handle_table,
|
16
|
+
with_media, with_tags, count_regular, with_search,
|
17
|
+
} from './con.shared.js'
|
14
18
|
import { sanitize, sanitize_array } from './utils.funcs.js'
|
15
19
|
import { query_to_eb, query_to_sort } from './utils.query.js'
|
16
20
|
import { report_document_media } from './con.images.js'
|
@@ -36,14 +40,25 @@ const upsert = (driver) => {
|
|
36
40
|
// PRODUCTS => DISCOUNTS
|
37
41
|
//
|
38
42
|
// remove all products relation to this discount
|
39
|
-
await
|
43
|
+
await delete_entity_values_by_value_or_reporter_and_context('products_to_discounts')(
|
40
44
|
trx, item.id, item.handle);
|
45
|
+
|
46
|
+
const extra_search_for_products =
|
47
|
+
helper_compute_product_extra_search_keywords_because_of_discount_side_effect_for_db(item);
|
41
48
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
49
|
+
const extra_tags_for_products =
|
50
|
+
helper_compute_product_extra_tags_because_of_discount_side_effect_for_db(item);
|
51
|
+
|
52
|
+
// maybe i should confine these to `context`=`products`
|
53
|
+
for(const extra_search of extra_search_for_products) {
|
54
|
+
await delete_entity_values_by_value_or_reporter_and_context('entity_to_search_terms')(
|
55
|
+
trx, extra_search);
|
56
|
+
}
|
57
|
+
for(const extra_tag of extra_tags_for_products) {
|
58
|
+
await delete_entity_values_by_value_or_reporter_and_context('entity_to_tags_projections')(
|
59
|
+
trx, extra_tag);
|
60
|
+
}
|
61
|
+
|
47
62
|
if(item.active && item.application.id===enums.DiscountApplicationEnum.Auto.id) {
|
48
63
|
// make connections
|
49
64
|
await trx
|
@@ -63,37 +78,44 @@ const upsert = (driver) => {
|
|
63
78
|
)
|
64
79
|
).execute();
|
65
80
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
.
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
81
|
+
for(const extra_search of extra_search_for_products) {
|
82
|
+
await trx
|
83
|
+
.insertInto('entity_to_search_terms')
|
84
|
+
.columns(['entity_handle', 'entity_id', 'value', 'reporter', 'context'])
|
85
|
+
.expression(eb =>
|
86
|
+
eb.selectFrom('products')
|
87
|
+
.select(eb => [
|
88
|
+
'handle as entity_handle',
|
89
|
+
'id as entity_id',
|
90
|
+
eb.val(extra_search).as('value'),
|
91
|
+
eb.val(item.id).as('reporter'),
|
92
|
+
eb.val('products').as('context'),
|
93
|
+
]
|
94
|
+
)
|
95
|
+
.where(
|
96
|
+
eb => eb.and(discount_to_conjunctions(eb, item))
|
97
|
+
)
|
98
|
+
).execute();
|
99
|
+
}
|
100
|
+
for(const extra_tag of extra_tags_for_products) {
|
101
|
+
await trx
|
102
|
+
.insertInto('entity_to_tags_projections')
|
103
|
+
.columns(['entity_handle', 'entity_id', 'value', 'reporter', 'context'])
|
104
|
+
.expression(eb =>
|
105
|
+
eb.selectFrom('products')
|
106
|
+
.select(eb => [
|
107
|
+
'handle as entity_handle',
|
108
|
+
'id as entity_id',
|
109
|
+
eb.val(extra_tag).as('value'),
|
110
|
+
eb.val(item.id).as('reporter'),
|
111
|
+
eb.val('products').as('context'),
|
112
|
+
]
|
113
|
+
)
|
114
|
+
.where(
|
115
|
+
eb => eb.and(discount_to_conjunctions(eb, item))
|
116
|
+
)
|
117
|
+
).execute();
|
118
|
+
}
|
97
119
|
}
|
98
120
|
|
99
121
|
///
|
@@ -158,17 +180,48 @@ const remove = (driver) => {
|
|
158
180
|
async (trx) => {
|
159
181
|
|
160
182
|
// entities
|
161
|
-
await
|
162
|
-
await
|
163
|
-
await
|
183
|
+
await delete_tags_of(trx, id_or_handle, id_or_handle, table_name);
|
184
|
+
await delete_search_of(trx, id_or_handle, id_or_handle, table_name);
|
185
|
+
await delete_media_of(trx, id_or_handle, id_or_handle, table_name);
|
164
186
|
// delete products -> discounts
|
165
187
|
// PRODUCTS => DISCOUNTS
|
166
|
-
await
|
188
|
+
await delete_entity_values_by_value_or_reporter_and_context('products_to_discounts')(
|
167
189
|
trx, id_or_handle, id_or_handle);
|
168
190
|
// STOREFRONT => DISCOUNTS
|
169
|
-
await
|
170
|
-
trx, id_or_handle, id_or_handle
|
191
|
+
await delete_entity_values_by_value_or_reporter_and_context('storefronts_to_other')(
|
192
|
+
trx, id_or_handle, id_or_handle, table_name
|
171
193
|
);
|
194
|
+
// discount might have published search terms and tags for other products,
|
195
|
+
// so let's remove
|
196
|
+
const discount_handle_and_id = await trx
|
197
|
+
.selectFrom('discounts')
|
198
|
+
.select(['handle', 'id'])
|
199
|
+
.where(
|
200
|
+
(eb) => eb.or([
|
201
|
+
eb('discounts.handle', '=', id_or_handle),
|
202
|
+
eb('discounts.id', '=', id_or_handle)
|
203
|
+
])
|
204
|
+
)
|
205
|
+
.executeTakeFirst();
|
206
|
+
|
207
|
+
const extra_search_for_products =
|
208
|
+
helper_compute_product_extra_search_keywords_because_of_discount_side_effect_for_db(
|
209
|
+
discount_handle_and_id
|
210
|
+
);
|
211
|
+
|
212
|
+
const extra_tags_for_products =
|
213
|
+
helper_compute_product_extra_tags_because_of_discount_side_effect_for_db(
|
214
|
+
discount_handle_and_id
|
215
|
+
);
|
216
|
+
|
217
|
+
for(const extra_search of extra_search_for_products) {
|
218
|
+
await delete_entity_values_by_value_or_reporter_and_context('entity_to_search_terms')(
|
219
|
+
trx, extra_search);
|
220
|
+
}
|
221
|
+
for(const extra_tag of extra_tags_for_products) {
|
222
|
+
await delete_entity_values_by_value_or_reporter_and_context('entity_to_tags_projections')(
|
223
|
+
trx, extra_tag);
|
224
|
+
}
|
172
225
|
|
173
226
|
// delete me
|
174
227
|
await delete_me(trx, table_name, id_or_handle);
|
@@ -220,13 +273,14 @@ const list = (driver) => {
|
|
220
273
|
const list_discount_products = (driver) => {
|
221
274
|
return async (handle_or_id, query={}) => {
|
222
275
|
|
223
|
-
// TODO: try to rewrite this with JOIN to products_to_discounts ON products.id=entity_id
|
224
|
-
// TODO: and then filter by value==handle_or_id_of_discount
|
225
|
-
// TODO: I think it will be better and more memory efficient for the database
|
226
|
-
// TODO: becausee right now it loads all the eligible products ids in advance
|
227
276
|
const items = await driver.client
|
228
277
|
.selectFrom('products')
|
229
|
-
.
|
278
|
+
.innerJoin(
|
279
|
+
'products_to_discounts',
|
280
|
+
'products_to_discounts.entity_id',
|
281
|
+
'products.id'
|
282
|
+
)
|
283
|
+
.selectAll('products')
|
230
284
|
.select(eb => [
|
231
285
|
with_media(eb, eb.ref('products.id'), driver.dialectType),
|
232
286
|
with_tags(eb, eb.ref('products.id'), driver.dialectType),
|
@@ -235,12 +289,13 @@ const list_discount_products = (driver) => {
|
|
235
289
|
(eb) => eb.and(
|
236
290
|
[
|
237
291
|
query_to_eb(eb, query, 'products'),
|
238
|
-
eb(
|
239
|
-
|
240
|
-
eb, '
|
241
|
-
|
292
|
+
eb.or(
|
293
|
+
[
|
294
|
+
eb('products_to_discounts.reporter', '=', handle_or_id),
|
295
|
+
eb('products_to_discounts.value', '=', handle_or_id)
|
296
|
+
]
|
242
297
|
)
|
243
|
-
].filter(Boolean)
|
298
|
+
].filter(Boolean)
|
244
299
|
)
|
245
300
|
)
|
246
301
|
.orderBy(query_to_sort(query, 'products'))
|
@@ -253,6 +308,84 @@ const list_discount_products = (driver) => {
|
|
253
308
|
}
|
254
309
|
}
|
255
310
|
|
311
|
+
|
312
|
+
|
313
|
+
/**
|
314
|
+
* @param {SQL} driver
|
315
|
+
* @returns {db_col["list_all_discount_products_tags"]}
|
316
|
+
*/
|
317
|
+
const list_all_discount_products_tags = (driver) => {
|
318
|
+
return async (handle_or_id) => {
|
319
|
+
|
320
|
+
const items = await driver.client
|
321
|
+
.selectFrom('products')
|
322
|
+
.innerJoin(
|
323
|
+
'products_to_discounts',
|
324
|
+
'products_to_discounts.entity_id',
|
325
|
+
'products.id'
|
326
|
+
)
|
327
|
+
.innerJoin(
|
328
|
+
'entity_to_tags_projections',
|
329
|
+
'entity_to_tags_projections.entity_id',
|
330
|
+
'products.id'
|
331
|
+
)
|
332
|
+
.select('entity_to_tags_projections.value as tag')
|
333
|
+
.where(
|
334
|
+
(eb) => eb.or(
|
335
|
+
[
|
336
|
+
eb('products_to_discounts.reporter', '=', handle_or_id),
|
337
|
+
eb('products_to_discounts.value', '=', handle_or_id)
|
338
|
+
]
|
339
|
+
)
|
340
|
+
)
|
341
|
+
.groupBy('tag')
|
342
|
+
.execute();
|
343
|
+
|
344
|
+
// .compile();
|
345
|
+
// console.log(items[0])
|
346
|
+
|
347
|
+
return items.map(e => e.tag);
|
348
|
+
}
|
349
|
+
}
|
350
|
+
|
351
|
+
|
352
|
+
/**
|
353
|
+
* @param {SQL} driver
|
354
|
+
* @returns {db_col["count_discount_products"]}
|
355
|
+
*/
|
356
|
+
const count_discount_products = (driver) => {
|
357
|
+
return async (handle_or_id, query={}) => {
|
358
|
+
|
359
|
+
const result = await driver.client
|
360
|
+
.selectFrom('products')
|
361
|
+
.innerJoin(
|
362
|
+
'products_to_discounts',
|
363
|
+
'products_to_discounts.entity_id',
|
364
|
+
'products.id'
|
365
|
+
)
|
366
|
+
.select(
|
367
|
+
(eb) => eb.fn.countAll().as('count')
|
368
|
+
)
|
369
|
+
.where(
|
370
|
+
(eb) => eb.and(
|
371
|
+
[
|
372
|
+
query_to_eb(eb, query, 'products'),
|
373
|
+
eb.or(
|
374
|
+
[
|
375
|
+
eb('products_to_discounts.reporter', '=', handle_or_id),
|
376
|
+
eb('products_to_discounts.value', '=', handle_or_id)
|
377
|
+
]
|
378
|
+
)
|
379
|
+
].filter(Boolean)
|
380
|
+
)
|
381
|
+
)
|
382
|
+
.executeTakeFirst();
|
383
|
+
|
384
|
+
return Number(result.count);
|
385
|
+
}
|
386
|
+
}
|
387
|
+
|
388
|
+
|
256
389
|
/**
|
257
390
|
* @param {SQL} driver
|
258
391
|
* @return {db_col}}
|
@@ -265,6 +398,8 @@ export const impl = (driver) => {
|
|
265
398
|
remove: remove(driver),
|
266
399
|
list: list(driver),
|
267
400
|
list_discount_products: list_discount_products(driver),
|
401
|
+
count_discount_products: count_discount_products(driver),
|
402
|
+
list_all_discount_products_tags: list_all_discount_products_tags(driver),
|
268
403
|
count: count_regular(driver, table_name),
|
269
404
|
}
|
270
405
|
}
|
@@ -25,25 +25,26 @@ const extract_abs_number = v => {
|
|
25
25
|
/**
|
26
26
|
* @param {ExpressionBuilder<Database, 'products'>} eb
|
27
27
|
* @param {keyof Pick<Database, 'entity_to_tags_projections' | 'products_to_collections'>} table
|
28
|
-
* @param {BinaryOperator} op
|
29
28
|
* @param {string[]} value
|
30
29
|
*/
|
31
|
-
const eb_in = (eb, table,
|
30
|
+
const eb_in = (eb, table, value) => {
|
32
31
|
return eb.exists(
|
33
32
|
eb => eb
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
.selectFrom(table)
|
34
|
+
.select('id')
|
35
|
+
.where(
|
36
|
+
eb => eb.and(
|
37
|
+
[
|
38
38
|
eb.or(
|
39
39
|
[
|
40
40
|
eb(`${table}.entity_id`, '=', eb.ref('products.id')),
|
41
41
|
eb(`${table}.entity_handle`, '=', eb.ref('products.handle')),
|
42
42
|
]
|
43
43
|
),
|
44
|
-
eb(`${table}.value`,
|
45
|
-
]
|
44
|
+
eb(`${table}.value`, 'in', value)
|
45
|
+
]
|
46
46
|
)
|
47
|
+
)
|
47
48
|
)
|
48
49
|
}
|
49
50
|
|
@@ -111,7 +112,7 @@ export const discount_to_conjunctions = (eb, d) => {
|
|
111
112
|
|
112
113
|
conjunctions.push(
|
113
114
|
eb_in(
|
114
|
-
eb, 'entity_to_tags_projections',
|
115
|
+
eb, 'entity_to_tags_projections',
|
115
116
|
cast
|
116
117
|
)
|
117
118
|
);
|
@@ -126,7 +127,7 @@ export const discount_to_conjunctions = (eb, d) => {
|
|
126
127
|
conjunctions.push(
|
127
128
|
eb.not(
|
128
129
|
eb_in(
|
129
|
-
eb, 'entity_to_tags_projections',
|
130
|
+
eb, 'entity_to_tags_projections',
|
130
131
|
cast
|
131
132
|
)
|
132
133
|
)
|
@@ -142,7 +143,7 @@ export const discount_to_conjunctions = (eb, d) => {
|
|
142
143
|
// PROBLEM: we only have ids, but use handles in the filters
|
143
144
|
conjunctions.push(
|
144
145
|
eb_in(
|
145
|
-
eb, 'products_to_collections',
|
146
|
+
eb, 'products_to_collections',
|
146
147
|
cast.map(c => c.id)
|
147
148
|
)
|
148
149
|
);
|
@@ -157,7 +158,7 @@ export const discount_to_conjunctions = (eb, d) => {
|
|
157
158
|
conjunctions.push(
|
158
159
|
eb.not(
|
159
160
|
eb_in(
|
160
|
-
eb, 'products_to_collections',
|
161
|
+
eb, 'products_to_collections',
|
161
162
|
cast.map(c => c.id)
|
162
163
|
)
|
163
164
|
)
|
package/src/con.helpers.json.js
CHANGED
@@ -1,14 +1,25 @@
|
|
1
|
+
/**
|
2
|
+
* @import { AliasableExpression, Expression} from 'kysely'
|
3
|
+
* @import { SelectQueryBuilderExpression } from './con.helpers.json.js'
|
4
|
+
* @import { SqlDialectType } from '../types.public.js'
|
5
|
+
* @import { RawBuilder, Simplify } from 'kysely'
|
6
|
+
*/
|
7
|
+
|
1
8
|
import {
|
2
9
|
AliasNode, ColumnNode, ExpressionWrapper, IdentifierNode,
|
3
10
|
ReferenceNode, SelectQueryNode, TableNode, ValueNode } from 'kysely'
|
4
|
-
import {
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
import {
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
import {
|
12
|
+
sqlite_jsonArrayFrom, sqlite_jsonObjectFrom,
|
13
|
+
sqlite_stringArrayFrom
|
14
|
+
} from './con.helpers.json.sqlite.js'
|
15
|
+
import {
|
16
|
+
pg_jsonArrayFrom, pg_jsonObjectFrom,
|
17
|
+
pg_stringArrayFrom
|
18
|
+
} from './con.helpers.json.postgres.js'
|
19
|
+
import {
|
20
|
+
mysql_jsonArrayFrom, mysql_jsonObjectFrom,
|
21
|
+
mysql_stringArrayFrom
|
22
|
+
} from './con.helpers.json.mysql.js'
|
12
23
|
|
13
24
|
|
14
25
|
/**
|
@@ -20,7 +31,7 @@ import { mssql_jsonArrayFrom, mssql_jsonObjectFrom,
|
|
20
31
|
|
21
32
|
/**
|
22
33
|
* @template O
|
23
|
-
* @typedef {
|
34
|
+
* @typedef {AliasableExpression<O> & _SelectQueryBuilderExpression<O>} SelectQueryBuilderExpression
|
24
35
|
* @property {boolean} isSelectQueryBuilder
|
25
36
|
* @property {(): SelectQueryNode} toOperationNode
|
26
37
|
*/
|
@@ -30,10 +41,10 @@ import { mssql_jsonArrayFrom, mssql_jsonObjectFrom,
|
|
30
41
|
*
|
31
42
|
* @param {SelectQueryNode} node
|
32
43
|
* @param {string} table
|
33
|
-
* @returns {
|
44
|
+
* @returns {Expression<unknown>[] }
|
34
45
|
*/
|
35
46
|
export function getJsonObjectArgs(node, table) {
|
36
|
-
/** @type {
|
47
|
+
/** @type {Expression<unknown>[] } */
|
37
48
|
const args = []
|
38
49
|
|
39
50
|
for (const { selection: s } of node.selections ?? []) {
|
@@ -58,7 +69,7 @@ export function getJsonObjectArgs(node, table) {
|
|
58
69
|
/**
|
59
70
|
*
|
60
71
|
* @param {string} col
|
61
|
-
* @returns {
|
72
|
+
* @returns {Expression<unknown> }
|
62
73
|
*/
|
63
74
|
function colName(col) {
|
64
75
|
return new ExpressionWrapper(ValueNode.createImmediate(col))
|
@@ -68,7 +79,7 @@ function colName(col) {
|
|
68
79
|
*
|
69
80
|
* @param {string} table
|
70
81
|
* @param {string} col
|
71
|
-
* @returns {
|
82
|
+
* @returns {Expression<unknown> }
|
72
83
|
*/
|
73
84
|
function colRef(table, col) {
|
74
85
|
return new ExpressionWrapper(
|
@@ -80,7 +91,7 @@ function colRef(table, col) {
|
|
80
91
|
* @template O
|
81
92
|
* @param {SelectQueryBuilderExpression<O>} expr
|
82
93
|
* @param {string} table
|
83
|
-
* @returns {
|
94
|
+
* @returns {Expression<unknown>}
|
84
95
|
*/
|
85
96
|
export const extract_first_selection = (expr, table) => {
|
86
97
|
/** @type {any} */
|
@@ -88,7 +99,7 @@ export const extract_first_selection = (expr, table) => {
|
|
88
99
|
/** @type {SelectQueryNode} */
|
89
100
|
const s__ = s_;
|
90
101
|
const s = s__.selections[0].selection;
|
91
|
-
/** @type {
|
102
|
+
/** @type {Expression<unknown>} */
|
92
103
|
let arg;
|
93
104
|
if (ReferenceNode.is(s) && ColumnNode.is(s.column)) {
|
94
105
|
// console.log('arg ', s)
|
@@ -126,11 +137,10 @@ export const extract_first_selection = (expr, table) => {
|
|
126
137
|
* result[0].pets[0].pet_id
|
127
138
|
* result[0].pets[0].name
|
128
139
|
* ```
|
129
|
-
*
|
130
140
|
* @template O
|
131
|
-
* @param {
|
132
|
-
* @param {
|
133
|
-
* @returns {
|
141
|
+
* @param {SelectQueryBuilderExpression<O>} expr
|
142
|
+
* @param {SqlDialectType} sql_type
|
143
|
+
* @returns {RawBuilder<Simplify<O>[]>}
|
134
144
|
*/
|
135
145
|
export function jsonArrayFrom(expr, sql_type) {
|
136
146
|
switch(sql_type) {
|
@@ -140,8 +150,6 @@ export function jsonArrayFrom(expr, sql_type) {
|
|
140
150
|
return pg_jsonArrayFrom(expr);
|
141
151
|
case 'MYSQL':
|
142
152
|
return mysql_jsonArrayFrom(expr);
|
143
|
-
// case 'MSSQL':
|
144
|
-
// return mssql_jsonArrayFrom(expr);
|
145
153
|
default:
|
146
154
|
throw new Error(`sql_type=${sql_type} NOT SUPPORTED !`);
|
147
155
|
}
|
@@ -169,8 +177,8 @@ export function jsonArrayFrom(expr, sql_type) {
|
|
169
177
|
* result[0].pets = ['name1', 'name2', ....]
|
170
178
|
* ```
|
171
179
|
* @template O
|
172
|
-
* @param {
|
173
|
-
* @param {
|
180
|
+
* @param {SelectQueryBuilderExpression<O>} expr
|
181
|
+
* @param {SqlDialectType} sql_type
|
174
182
|
*/
|
175
183
|
export function stringArrayFrom(expr, sql_type) {
|
176
184
|
switch(sql_type) {
|
@@ -180,8 +188,6 @@ export function stringArrayFrom(expr, sql_type) {
|
|
180
188
|
return pg_stringArrayFrom(expr);
|
181
189
|
case 'MYSQL':
|
182
190
|
return mysql_stringArrayFrom(expr);
|
183
|
-
// case 'MSSQL':
|
184
|
-
// return mssql_stringArrayFrom(expr);
|
185
191
|
default:
|
186
192
|
throw new Error(`sql_type=${sql_type} NOT SUPPORTED !`);
|
187
193
|
}
|
@@ -211,9 +217,9 @@ export function stringArrayFrom(expr, sql_type) {
|
|
211
217
|
* ```
|
212
218
|
*
|
213
219
|
* @template O
|
214
|
-
* @param {
|
215
|
-
* @param {
|
216
|
-
* @returns {
|
220
|
+
* @param {SelectQueryBuilderExpression<O>} expr
|
221
|
+
* @param {SqlDialectType} sql_type
|
222
|
+
* @returns {RawBuilder<Simplify<O> | null>}
|
217
223
|
*/
|
218
224
|
export function jsonObjectFrom(expr, sql_type) {
|
219
225
|
switch(sql_type) {
|
@@ -223,8 +229,6 @@ export function jsonObjectFrom(expr, sql_type) {
|
|
223
229
|
return pg_jsonObjectFrom(expr);
|
224
230
|
case 'MYSQL':
|
225
231
|
return mysql_jsonObjectFrom(expr);
|
226
|
-
// case 'MSSQL':
|
227
|
-
// return mssql_jsonObjectFrom(expr);
|
228
232
|
default:
|
229
233
|
throw new Error(`sql_type=${sql_type} NOT SUPPORTED !`);
|
230
234
|
}
|
@@ -1,5 +1,13 @@
|
|
1
|
+
/**
|
2
|
+
* @import { AliasableExpression, Expression} from 'kysely'
|
3
|
+
* @import { SelectQueryBuilderExpression } from './con.helpers.json.js'
|
4
|
+
* @import { SqlDialectType } from '../types.public.js'
|
5
|
+
* @import { RawBuilder, Simplify } from 'kysely'
|
6
|
+
*/
|
1
7
|
import { SelectQueryNode, sql } from "kysely"
|
2
|
-
import {
|
8
|
+
import {
|
9
|
+
extract_first_selection, getJsonObjectArgs
|
10
|
+
} from "./con.helpers.json.js"
|
3
11
|
|
4
12
|
/**
|
5
13
|
* A MySQL helper for aggregating a subquery into a JSON array.
|
@@ -48,13 +56,18 @@ import { extract_first_selection, getJsonObjectArgs } from "./con.helpers.json.j
|
|
48
56
|
* ```
|
49
57
|
*
|
50
58
|
* @template O
|
51
|
-
* @param {
|
52
|
-
* @returns {
|
59
|
+
* @param {SelectQueryBuilderExpression<O>} expr
|
60
|
+
* @returns {RawBuilder<Simplify<O>[]>}
|
53
61
|
*/
|
54
62
|
export function mysql_jsonArrayFrom(expr) {
|
55
|
-
return sql`(select cast(coalesce(json_arrayagg(json_object(${
|
56
|
-
|
57
|
-
|
63
|
+
return sql`(select cast(coalesce(json_arrayagg(json_object(${
|
64
|
+
sql.join(
|
65
|
+
getMysqlJsonObjectArgs(
|
66
|
+
/** @type {SelectQueryNode} */(expr.toOperationNode()),
|
67
|
+
'agg'
|
68
|
+
),
|
69
|
+
)
|
70
|
+
})), '[]') as json) from ${expr} as agg)`
|
58
71
|
}
|
59
72
|
|
60
73
|
/**
|
@@ -105,8 +118,8 @@ export function mysql_jsonArrayFrom(expr) {
|
|
105
118
|
* from "person"
|
106
119
|
* ```
|
107
120
|
* @template O
|
108
|
-
* @param {
|
109
|
-
* @returns {
|
121
|
+
* @param {SelectQueryBuilderExpression<O>} expr
|
122
|
+
* @returns {RawBuilder<string[]>}
|
110
123
|
*/
|
111
124
|
export function mysql_stringArrayFrom(expr) {
|
112
125
|
const arg = extract_first_selection(expr, 'agg');
|
@@ -163,13 +176,18 @@ export function mysql_stringArrayFrom(expr) {
|
|
163
176
|
* ```
|
164
177
|
*
|
165
178
|
* @template O
|
166
|
-
* @param {
|
167
|
-
* @returns {
|
179
|
+
* @param {SelectQueryBuilderExpression<O>} expr
|
180
|
+
* @returns {RawBuilder<Simplify<O> | null>}
|
168
181
|
*/
|
169
182
|
export function mysql_jsonObjectFrom(expr) {
|
170
|
-
return sql`(select json_object(${
|
171
|
-
|
172
|
-
|
183
|
+
return sql`(select json_object(${
|
184
|
+
sql.join(
|
185
|
+
getMysqlJsonObjectArgs(
|
186
|
+
/** @type {SelectQueryNode} */(expr.toOperationNode()),
|
187
|
+
'obj'
|
188
|
+
),
|
189
|
+
)
|
190
|
+
}) from ${expr} as obj)`
|
173
191
|
}
|
174
192
|
|
175
193
|
/**
|
@@ -212,21 +230,23 @@ export function mysql_jsonObjectFrom(expr) {
|
|
212
230
|
* from "person"
|
213
231
|
* ```
|
214
232
|
*
|
215
|
-
* @template {Record<string,
|
233
|
+
* @template {Record<string, Expression<unknown>>} O
|
216
234
|
* @param {O} obj
|
217
|
-
* @returns {
|
235
|
+
* @returns {RawBuilder<Simplify<{[K in keyof O]: O[K] extends Expression<infer V> ? V : never}>>}
|
218
236
|
*/
|
219
237
|
export function mysql_jsonBuildObject(obj) {
|
220
|
-
return sql`json_object(${
|
221
|
-
|
222
|
-
|
238
|
+
return sql`json_object(${
|
239
|
+
sql.join(
|
240
|
+
Object.keys(obj).flatMap((k) => [sql.lit(k), obj[k]]),
|
241
|
+
)
|
242
|
+
})`
|
223
243
|
}
|
224
244
|
|
225
245
|
/**
|
226
246
|
*
|
227
247
|
* @param {SelectQueryNode} node
|
228
248
|
* @param {string} table
|
229
|
-
* @returns {
|
249
|
+
* @returns {Expression<unknown>[]}
|
230
250
|
*/
|
231
251
|
function getMysqlJsonObjectArgs(node, table) {
|
232
252
|
try {
|