@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,616 @@
|
|
1
|
+
import { ExpressionWrapper, InsertQueryBuilder, Transaction } from 'kysely'
|
2
|
+
import { jsonArrayFrom, stringArrayFrom } from './con.helpers.json.js'
|
3
|
+
import { SQL } from '../index.js';
|
4
|
+
import { query_to_eb } from './utils.query.js';
|
5
|
+
|
6
|
+
|
7
|
+
/**
|
8
|
+
* @param {SQL} driver
|
9
|
+
* @param {keyof Database} table_name
|
10
|
+
*
|
11
|
+
* @returns {import('@storecraft/core/v-database').db_crud["count"]}
|
12
|
+
*/
|
13
|
+
export const count_regular = (driver, table_name) => {
|
14
|
+
return async (query) => {
|
15
|
+
|
16
|
+
const result = await driver.client
|
17
|
+
.selectFrom(table_name)
|
18
|
+
.select(
|
19
|
+
(eb) => eb.fn.countAll().as('count')
|
20
|
+
)
|
21
|
+
.where(
|
22
|
+
(eb) => {
|
23
|
+
return query_to_eb(eb, query, table_name);
|
24
|
+
}
|
25
|
+
)
|
26
|
+
.executeTakeFirst();
|
27
|
+
|
28
|
+
return Number(result.count);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
/**
|
33
|
+
*
|
34
|
+
* @param {string} id_or_handle
|
35
|
+
*/
|
36
|
+
export const where_id_or_handle_entity = (id_or_handle) => {
|
37
|
+
/**
|
38
|
+
* @param {import('kysely').ExpressionBuilder<Database>} eb
|
39
|
+
*/
|
40
|
+
return (eb) => eb.or(
|
41
|
+
[
|
42
|
+
eb('entity_handle', '=', id_or_handle),
|
43
|
+
eb('entity_id', '=', id_or_handle),
|
44
|
+
]
|
45
|
+
);
|
46
|
+
}
|
47
|
+
|
48
|
+
/**
|
49
|
+
*
|
50
|
+
* @param {string} id_or_handle
|
51
|
+
*/
|
52
|
+
export const where_id_or_handle_table = (id_or_handle) => {
|
53
|
+
/**
|
54
|
+
* @param {import('kysely').ExpressionBuilder<Database>} eb
|
55
|
+
*/
|
56
|
+
return (eb) => eb.or(
|
57
|
+
[
|
58
|
+
eb('id', '=', id_or_handle),
|
59
|
+
eb('handle', '=', id_or_handle),
|
60
|
+
]
|
61
|
+
);
|
62
|
+
}
|
63
|
+
|
64
|
+
/**
|
65
|
+
* @typedef { keyof Pick<Database,
|
66
|
+
* 'entity_to_media' | 'entity_to_search_terms'
|
67
|
+
* | 'entity_to_tags_projections' | 'products_to_collections'
|
68
|
+
* | 'products_to_discounts' | 'products_to_variants'
|
69
|
+
* | 'products_to_related_products' | 'storefronts_to_other'>
|
70
|
+
* } EntityTableKeys
|
71
|
+
*/
|
72
|
+
|
73
|
+
/**
|
74
|
+
* helper to generate entity values delete
|
75
|
+
*
|
76
|
+
* @param {EntityTableKeys} entity_table_name
|
77
|
+
*/
|
78
|
+
export const delete_entity_values_by_value_or_reporter = (entity_table_name) => {
|
79
|
+
/**
|
80
|
+
*
|
81
|
+
* @param {Transaction<Database>} trx
|
82
|
+
* @param {string} value delete by entity value
|
83
|
+
* @param {string} [reporter] delete by reporter
|
84
|
+
*/
|
85
|
+
return (trx, value, reporter=undefined) => {
|
86
|
+
|
87
|
+
return trx.deleteFrom(entity_table_name).where(
|
88
|
+
eb => eb.or(
|
89
|
+
[
|
90
|
+
value && eb('value', '=', value),
|
91
|
+
reporter && eb('reporter', '=', reporter),
|
92
|
+
].filter(Boolean)
|
93
|
+
)
|
94
|
+
).executeTakeFirst();
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
/**
|
99
|
+
* helper to generate entity values delete
|
100
|
+
*
|
101
|
+
* @param {EntityTableKeys} entity_table_name
|
102
|
+
*/
|
103
|
+
export const delete_entity_values_of_by_entity_id_or_handle =
|
104
|
+
(entity_table_name) => {
|
105
|
+
/**
|
106
|
+
*
|
107
|
+
* @param {Transaction<import('../index.js').Database>} trx
|
108
|
+
* @param {string} entity_id delete by id
|
109
|
+
* @param {string} [entity_handle=entity_id] delete by handle
|
110
|
+
*/
|
111
|
+
return (trx, entity_id, entity_handle=undefined) => {
|
112
|
+
return trx.deleteFrom(entity_table_name).where(
|
113
|
+
eb => eb.or(
|
114
|
+
[
|
115
|
+
eb('entity_id', '=', entity_id),
|
116
|
+
eb('entity_handle', '=', entity_handle ?? entity_id),
|
117
|
+
]
|
118
|
+
)
|
119
|
+
).executeTakeFirst();
|
120
|
+
}
|
121
|
+
}
|
122
|
+
|
123
|
+
/**
|
124
|
+
* helper to generate entity values for simple tables
|
125
|
+
* @param {EntityTableKeys} entity_table_name
|
126
|
+
*/
|
127
|
+
export const insert_entity_array_values_of = (entity_table_name) => {
|
128
|
+
/**
|
129
|
+
*
|
130
|
+
* @param {Transaction<Database>} trx
|
131
|
+
* @param {string[]} values values of the entity
|
132
|
+
* @param {string} item_id whom the tags belong to
|
133
|
+
* @param {string} [item_handle] whom the tags belong to
|
134
|
+
* @param {boolean} [delete_previous=true] if true and `reporter`,
|
135
|
+
* then will delete by reporter, otherwise by `item_id/item_handle`
|
136
|
+
* @param {string} [reporter=undefined] the reporter of the batch values
|
137
|
+
* (another segment technique)
|
138
|
+
* @param {string} [context=undefined] the context (another segment technique)
|
139
|
+
*/
|
140
|
+
return async (trx, values, item_id, item_handle, delete_previous=true,
|
141
|
+
reporter=undefined, context=undefined) => {
|
142
|
+
|
143
|
+
if(delete_previous) {
|
144
|
+
if(reporter) {
|
145
|
+
await delete_entity_values_by_value_or_reporter(entity_table_name)(
|
146
|
+
trx, undefined, reporter
|
147
|
+
);
|
148
|
+
} else {
|
149
|
+
await delete_entity_values_of_by_entity_id_or_handle(entity_table_name)(
|
150
|
+
trx, item_id, item_handle
|
151
|
+
);
|
152
|
+
}
|
153
|
+
}
|
154
|
+
|
155
|
+
if(!values?.length) return Promise.resolve();
|
156
|
+
|
157
|
+
return await trx.insertInto(entity_table_name).values(
|
158
|
+
values.map(t => ({
|
159
|
+
entity_handle: item_handle,
|
160
|
+
entity_id: item_id,
|
161
|
+
value: t,
|
162
|
+
reporter,
|
163
|
+
context
|
164
|
+
})
|
165
|
+
)
|
166
|
+
).executeTakeFirst();
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
/**
|
171
|
+
* helper to generate entity values delete
|
172
|
+
*
|
173
|
+
* @param {EntityTableKeys} entity_table_name
|
174
|
+
*/
|
175
|
+
export const insert_entity_values_of = (entity_table_name) => {
|
176
|
+
/**
|
177
|
+
*
|
178
|
+
* @param {Transaction<Database>} trx
|
179
|
+
* @param {{value: string, reporter: string}[]} values values of the entity
|
180
|
+
* @param {string} item_id whom the tags belong to
|
181
|
+
* @param {string} [item_handle] whom the tags belong to
|
182
|
+
* @param {string} [context=undefined] the context (another segment technique)
|
183
|
+
*/
|
184
|
+
return async (trx, values, item_id, item_handle, context=undefined) => {
|
185
|
+
|
186
|
+
if(!values?.length) return Promise.resolve();
|
187
|
+
|
188
|
+
return await trx.insertInto(entity_table_name).values(
|
189
|
+
values.map(t => ({
|
190
|
+
entity_id: item_id,
|
191
|
+
entity_handle: item_handle,
|
192
|
+
value: t.value,
|
193
|
+
reporter: t.reporter,
|
194
|
+
context
|
195
|
+
})
|
196
|
+
)
|
197
|
+
).executeTakeFirst();
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
|
202
|
+
/**
|
203
|
+
* Delete previous entities by `id/handle` and insert new ones
|
204
|
+
*
|
205
|
+
* @param {EntityTableKeys} entity_table
|
206
|
+
*/
|
207
|
+
export const insert_entity_array_values_with_delete_of = (entity_table) => {
|
208
|
+
/**
|
209
|
+
* @param {Transaction<Database>} trx
|
210
|
+
* @param {string[]} values values of the entity
|
211
|
+
* @param {string} item_id entity id
|
212
|
+
* @param {string} [item_handle] entity handle
|
213
|
+
* @param {string} [context] context
|
214
|
+
*/
|
215
|
+
return (trx, values, item_id, item_handle, context) => {
|
216
|
+
return insert_entity_array_values_of(entity_table)(
|
217
|
+
trx, values, item_id, item_handle, true, undefined, context
|
218
|
+
)
|
219
|
+
};
|
220
|
+
}
|
221
|
+
|
222
|
+
export const insert_tags_of = insert_entity_array_values_with_delete_of('entity_to_tags_projections');
|
223
|
+
export const insert_search_of = insert_entity_array_values_with_delete_of('entity_to_search_terms');
|
224
|
+
export const insert_media_of = insert_entity_array_values_with_delete_of('entity_to_media');
|
225
|
+
|
226
|
+
export const delete_tags_of = delete_entity_values_of_by_entity_id_or_handle('entity_to_tags_projections');
|
227
|
+
export const delete_search_of = delete_entity_values_of_by_entity_id_or_handle('entity_to_search_terms');
|
228
|
+
export const delete_media_of = delete_entity_values_of_by_entity_id_or_handle('entity_to_media');
|
229
|
+
|
230
|
+
/**
|
231
|
+
* @typedef {import('../index.js').Database} Database
|
232
|
+
*/
|
233
|
+
|
234
|
+
|
235
|
+
/**
|
236
|
+
* @template {keyof Database} T
|
237
|
+
*
|
238
|
+
* @param {Transaction<Database>} trx
|
239
|
+
* @param {T} table_name
|
240
|
+
* @param {import('kysely').InsertObject<Database, T>} item values of the entity
|
241
|
+
*
|
242
|
+
*/
|
243
|
+
export const regular_upsert_me = async (trx, table_name, item) => {
|
244
|
+
|
245
|
+
// TODO: maybe use only `id`
|
246
|
+
await trx.deleteFrom(table_name).where(
|
247
|
+
eb => eb.or(
|
248
|
+
[
|
249
|
+
item.id && eb('id', '=', item.id),
|
250
|
+
item.handle && eb('handle', '=', item.handle),
|
251
|
+
].filter(Boolean)
|
252
|
+
)
|
253
|
+
).execute();
|
254
|
+
|
255
|
+
return await trx.insertInto(table_name).values(item).executeTakeFirst()
|
256
|
+
}
|
257
|
+
|
258
|
+
|
259
|
+
/**
|
260
|
+
*
|
261
|
+
* @param {Transaction<Database>} trx
|
262
|
+
* @param {keyof Database} table_name
|
263
|
+
* @param {string} id_or_handle
|
264
|
+
*/
|
265
|
+
export const delete_me = async (trx, table_name, id_or_handle) => {
|
266
|
+
// console.log('delete ', id_or_handle)
|
267
|
+
return await trx.deleteFrom(table_name).where(
|
268
|
+
where_id_or_handle_table(id_or_handle)
|
269
|
+
).executeTakeFirst();
|
270
|
+
}
|
271
|
+
|
272
|
+
/**
|
273
|
+
*
|
274
|
+
* @param {import('kysely').ExpressionBuilder<Database>} eb
|
275
|
+
* @param {string | ExpressionWrapper<Database>} id_or_handle
|
276
|
+
* @param {import('../types.public.js').SqlDialectType} sql_type
|
277
|
+
*/
|
278
|
+
export const with_tags = (eb, id_or_handle, sql_type) => {
|
279
|
+
return stringArrayFrom(
|
280
|
+
select_values_of_entity_by_entity_id_or_handle(
|
281
|
+
eb, 'entity_to_tags_projections', id_or_handle
|
282
|
+
), sql_type
|
283
|
+
).as('tags');
|
284
|
+
}
|
285
|
+
|
286
|
+
/**
|
287
|
+
*
|
288
|
+
* @param {import('kysely').ExpressionBuilder<Database>} eb
|
289
|
+
* @param {string | ExpressionWrapper<Database>} id_or_handle
|
290
|
+
* @param {import('../types.public.js').SqlDialectType} sql_type
|
291
|
+
*/
|
292
|
+
export const with_search = (eb, id_or_handle, sql_type) => {
|
293
|
+
return stringArrayFrom(
|
294
|
+
select_values_of_entity_by_entity_id_or_handle(
|
295
|
+
eb, 'entity_to_search_terms', id_or_handle
|
296
|
+
), sql_type
|
297
|
+
).as('search');
|
298
|
+
}
|
299
|
+
|
300
|
+
/**
|
301
|
+
*
|
302
|
+
* @param {import('kysely').ExpressionBuilder<Database>} eb
|
303
|
+
* @param {string | ExpressionWrapper<Database>} id_or_handle
|
304
|
+
* @param {import('../types.public.js').SqlDialectType} sql_type
|
305
|
+
*/
|
306
|
+
export const with_media = (eb, id_or_handle, sql_type) => {
|
307
|
+
return stringArrayFrom(
|
308
|
+
select_values_of_entity_by_entity_id_or_handle(
|
309
|
+
eb, 'entity_to_media', id_or_handle
|
310
|
+
), sql_type
|
311
|
+
).as('media');
|
312
|
+
}
|
313
|
+
|
314
|
+
/**
|
315
|
+
* helper to select base attributes
|
316
|
+
* @param {import('kysely').ExpressionBuilder<Database>} eb
|
317
|
+
* @param {keyof Database} table
|
318
|
+
* @return {import('kysely').SelectQueryBuilder<Database, table>}
|
319
|
+
*/
|
320
|
+
const select_base_from = (eb, table) => {
|
321
|
+
return [
|
322
|
+
'active', 'attributes', 'created_at', 'updated_at',
|
323
|
+
'description', 'handle', 'id'
|
324
|
+
].map(k => `${table}.${k}`).reduce(
|
325
|
+
(p, c) => p.select(c), eb.selectFrom(table)
|
326
|
+
);
|
327
|
+
}
|
328
|
+
|
329
|
+
/**
|
330
|
+
* select as json array collections of a product
|
331
|
+
*
|
332
|
+
* @param {import('kysely').ExpressionBuilder<Database, 'products'>} eb
|
333
|
+
* @param {string | ExpressionWrapper<Database>} product_id_or_handle
|
334
|
+
* @param {import('../types.public.js').SqlDialectType} sql_type
|
335
|
+
*/
|
336
|
+
export const products_with_collections = (eb, product_id_or_handle, sql_type) => {
|
337
|
+
return jsonArrayFrom(
|
338
|
+
select_base_from(eb, 'collections')
|
339
|
+
.select('collections.title')
|
340
|
+
.select('collections.published')
|
341
|
+
.select(eb => [
|
342
|
+
with_tags(eb, eb.ref('collections.id'), sql_type),
|
343
|
+
with_media(eb, eb.ref('collections.id'), sql_type),
|
344
|
+
])
|
345
|
+
.where('collections.id', 'in',
|
346
|
+
eb => select_values_of_entity_by_entity_id_or_handle(
|
347
|
+
eb, 'products_to_collections', product_id_or_handle
|
348
|
+
)
|
349
|
+
), sql_type
|
350
|
+
).as('collections');
|
351
|
+
}
|
352
|
+
|
353
|
+
/**
|
354
|
+
* select as json array collections of a product
|
355
|
+
*
|
356
|
+
* @param {import('kysely').ExpressionBuilder<Database, 'products'>} eb
|
357
|
+
* @param {string | ExpressionWrapper<Database>} product_id_or_handle
|
358
|
+
* @param {import('../types.public.js').SqlDialectType} sql_type
|
359
|
+
*/
|
360
|
+
export const products_with_discounts = (eb, product_id_or_handle, sql_type) => {
|
361
|
+
return jsonArrayFrom(
|
362
|
+
select_base_from(eb, 'discounts')
|
363
|
+
.select('discounts.title')
|
364
|
+
.select('discounts.published')
|
365
|
+
.select('discounts.application')
|
366
|
+
.select('discounts.info')
|
367
|
+
.select('discounts.priority')
|
368
|
+
.select(eb => [
|
369
|
+
with_tags(eb, eb.ref('discounts.id'), sql_type),
|
370
|
+
with_media(eb, eb.ref('discounts.id'), sql_type),
|
371
|
+
])
|
372
|
+
.where('discounts.id', 'in',
|
373
|
+
eb => select_values_of_entity_by_entity_id_or_handle(
|
374
|
+
eb, 'products_to_discounts', product_id_or_handle
|
375
|
+
)
|
376
|
+
), sql_type
|
377
|
+
).as('discounts');
|
378
|
+
}
|
379
|
+
|
380
|
+
/**
|
381
|
+
* select as json array collections of a product
|
382
|
+
*
|
383
|
+
* @param {import('kysely').ExpressionBuilder<Database, 'products'>} eb
|
384
|
+
* @param {string | ExpressionWrapper<Database>} product_id_or_handle
|
385
|
+
* @param {import('../types.public.js').SqlDialectType} sql_type
|
386
|
+
*/
|
387
|
+
export const products_with_variants = (eb, product_id_or_handle, sql_type) => {
|
388
|
+
return jsonArrayFrom(
|
389
|
+
select_base_from(eb, 'products')
|
390
|
+
.select('products.compare_at_price')
|
391
|
+
.select('products.parent_handle')
|
392
|
+
.select('products.parent_id')
|
393
|
+
.select('products.price')
|
394
|
+
.select('products.qty')
|
395
|
+
.select('products.title')
|
396
|
+
.select('products.variant_hint')
|
397
|
+
.select('products.variants_options')
|
398
|
+
.select('products.video')
|
399
|
+
.select(eb => [
|
400
|
+
with_tags(eb, eb.ref('products.id'), sql_type),
|
401
|
+
with_media(eb, eb.ref('products.id'), sql_type),
|
402
|
+
])
|
403
|
+
.where('products.id', 'in',
|
404
|
+
eb => select_values_of_entity_by_entity_id_or_handle(
|
405
|
+
eb, 'products_to_variants', product_id_or_handle
|
406
|
+
)
|
407
|
+
), sql_type
|
408
|
+
).as('variants');
|
409
|
+
}
|
410
|
+
|
411
|
+
/**
|
412
|
+
* select as json array collections of a product
|
413
|
+
*
|
414
|
+
* @param {import('kysely').ExpressionBuilder<Database, 'products'>} eb
|
415
|
+
* @param {string | ExpressionWrapper<Database>} product_id_or_handle
|
416
|
+
* @param {import('../types.public.js').SqlDialectType} sql_type
|
417
|
+
*/
|
418
|
+
export const products_with_related_products = (eb, product_id_or_handle, sql_type) => {
|
419
|
+
return jsonArrayFrom(
|
420
|
+
select_base_from(eb, 'products')
|
421
|
+
.select('products.compare_at_price')
|
422
|
+
.select('products.parent_handle')
|
423
|
+
.select('products.parent_id')
|
424
|
+
.select('products.price')
|
425
|
+
.select('products.qty')
|
426
|
+
.select('products.title')
|
427
|
+
.select('products.variant_hint')
|
428
|
+
.select('products.variants_options')
|
429
|
+
.select('products.video')
|
430
|
+
.select(eb => [
|
431
|
+
with_tags(eb, eb.ref('products.id'), sql_type),
|
432
|
+
with_media(eb, eb.ref('products.id'), sql_type),
|
433
|
+
])
|
434
|
+
.where('products.id', 'in',
|
435
|
+
eb => select_values_of_entity_by_entity_id_or_handle(
|
436
|
+
eb, 'products_to_related_products', product_id_or_handle
|
437
|
+
)
|
438
|
+
), sql_type
|
439
|
+
).as('related_products');
|
440
|
+
}
|
441
|
+
|
442
|
+
|
443
|
+
/**
|
444
|
+
* select as json array collections of a product
|
445
|
+
*
|
446
|
+
* @param {import('kysely').ExpressionBuilder<Database, 'storefronts'>} eb
|
447
|
+
* @param {string | ExpressionWrapper<Database>} sf_id_or_handle
|
448
|
+
* @param {import('../types.public.js').SqlDialectType} sql_type
|
449
|
+
*/
|
450
|
+
export const storefront_with_collections = (eb, sf_id_or_handle, sql_type) => {
|
451
|
+
return jsonArrayFrom(
|
452
|
+
select_base_from(eb, 'collections')
|
453
|
+
.select('collections.title')
|
454
|
+
.select('collections.published')
|
455
|
+
.select(eb => [
|
456
|
+
with_tags(eb, eb.ref('collections.id'), sql_type),
|
457
|
+
with_media(eb, eb.ref('collections.id'), sql_type),
|
458
|
+
])
|
459
|
+
.where('collections.id', 'in',
|
460
|
+
eb => select_values_of_entity_by_entity_id_or_handle(
|
461
|
+
eb, 'storefronts_to_other', sf_id_or_handle
|
462
|
+
)
|
463
|
+
), sql_type
|
464
|
+
).as('collections');
|
465
|
+
}
|
466
|
+
|
467
|
+
/**
|
468
|
+
* select as json array collections of a product
|
469
|
+
*
|
470
|
+
* @param {import('kysely').ExpressionBuilder<Database>} eb
|
471
|
+
* @param {string | ExpressionWrapper<Database>} sf_id_or_handle
|
472
|
+
* @param {import('../types.public.js').SqlDialectType} sql_type
|
473
|
+
*/
|
474
|
+
export const storefront_with_products = (eb, sf_id_or_handle, sql_type) => {
|
475
|
+
return jsonArrayFrom(
|
476
|
+
select_base_from(eb, 'products')
|
477
|
+
.select('products.title')
|
478
|
+
.select('products.compare_at_price')
|
479
|
+
.select('products.parent_handle')
|
480
|
+
.select('products.parent_id')
|
481
|
+
.select('products.price')
|
482
|
+
.select('products.qty')
|
483
|
+
.select('products.variant_hint')
|
484
|
+
.select('products.variants_options')
|
485
|
+
.select('products.video')
|
486
|
+
.select(eb => [
|
487
|
+
with_tags(eb, eb.ref('products.id'), sql_type),
|
488
|
+
with_media(eb, eb.ref('products.id'), sql_type),
|
489
|
+
])
|
490
|
+
.where('products.id', 'in',
|
491
|
+
eb => select_values_of_entity_by_entity_id_or_handle(
|
492
|
+
eb, 'storefronts_to_other', sf_id_or_handle
|
493
|
+
)
|
494
|
+
), sql_type
|
495
|
+
).as('products');
|
496
|
+
}
|
497
|
+
|
498
|
+
/**
|
499
|
+
* select as json array collections of a product
|
500
|
+
*
|
501
|
+
* @param {import('kysely').ExpressionBuilder<Database>} eb
|
502
|
+
* @param {string | ExpressionWrapper<Database>} sf_id_or_handle
|
503
|
+
* @param {import('../types.public.js').SqlDialectType} sql_type
|
504
|
+
*/
|
505
|
+
export const storefront_with_discounts = (eb, sf_id_or_handle, sql_type) => {
|
506
|
+
return jsonArrayFrom(
|
507
|
+
select_base_from(eb, 'discounts')
|
508
|
+
.select('discounts.application')
|
509
|
+
.select('discounts.info')
|
510
|
+
.select('discounts.priority')
|
511
|
+
.select('discounts.published')
|
512
|
+
.select('discounts.title')
|
513
|
+
.select(eb => [
|
514
|
+
with_tags(eb, eb.ref('discounts.id'), sql_type),
|
515
|
+
with_media(eb, eb.ref('discounts.id'), sql_type),
|
516
|
+
])
|
517
|
+
.where('discounts.id', 'in',
|
518
|
+
eb => select_values_of_entity_by_entity_id_or_handle(
|
519
|
+
eb, 'storefronts_to_other', sf_id_or_handle
|
520
|
+
)
|
521
|
+
), sql_type
|
522
|
+
).as('discounts');
|
523
|
+
}
|
524
|
+
|
525
|
+
/**
|
526
|
+
* select as json array collections of a product
|
527
|
+
*
|
528
|
+
* @param {import('kysely').ExpressionBuilder<Database>} eb
|
529
|
+
* @param {string | ExpressionWrapper<Database>} sf_id_or_handle
|
530
|
+
* @param {import('../types.public.js').SqlDialectType} sql_type
|
531
|
+
*/
|
532
|
+
export const storefront_with_posts = (eb, sf_id_or_handle, sql_type) => {
|
533
|
+
return jsonArrayFrom(
|
534
|
+
select_base_from(eb, 'posts')
|
535
|
+
.select('posts.text')
|
536
|
+
.select('posts.title')
|
537
|
+
.select(eb => [
|
538
|
+
with_tags(eb, eb.ref('posts.id'), sql_type),
|
539
|
+
with_media(eb, eb.ref('posts.id'), sql_type),
|
540
|
+
])
|
541
|
+
.where('posts.id', 'in',
|
542
|
+
eb => select_values_of_entity_by_entity_id_or_handle(
|
543
|
+
eb, 'storefronts_to_other', sf_id_or_handle
|
544
|
+
)
|
545
|
+
), sql_type
|
546
|
+
).as('posts');
|
547
|
+
}
|
548
|
+
|
549
|
+
/**
|
550
|
+
* select as json array collections of a product
|
551
|
+
*
|
552
|
+
* @param {import('kysely').ExpressionBuilder<Database>} eb
|
553
|
+
* @param {string | ExpressionWrapper<Database>} sf_id_or_handle
|
554
|
+
* @param {import('../types.public.js').SqlDialectType} sql_type
|
555
|
+
*/
|
556
|
+
export const storefront_with_shipping = (eb, sf_id_or_handle, sql_type) => {
|
557
|
+
return jsonArrayFrom(
|
558
|
+
select_base_from(eb, 'shipping_methods')
|
559
|
+
.select('shipping_methods.price')
|
560
|
+
.select('shipping_methods.title')
|
561
|
+
.select(eb => [
|
562
|
+
with_tags(eb, eb.ref('shipping_methods.id'), sql_type),
|
563
|
+
with_media(eb, eb.ref('shipping_methods.id'), sql_type),
|
564
|
+
])
|
565
|
+
.where('shipping_methods.id', 'in',
|
566
|
+
eb => select_values_of_entity_by_entity_id_or_handle(
|
567
|
+
eb, 'storefronts_to_other', sf_id_or_handle
|
568
|
+
)
|
569
|
+
), sql_type
|
570
|
+
).as('shipping_methods');
|
571
|
+
}
|
572
|
+
|
573
|
+
/**
|
574
|
+
* select all the entity values by entity id or handle
|
575
|
+
*
|
576
|
+
* @param {import('kysely').ExpressionBuilder<Database>} eb
|
577
|
+
* @param {EntityTableKeys} entity_junction_table
|
578
|
+
* @param {string | ExpressionWrapper<Database>} entity_id_or_handle
|
579
|
+
*/
|
580
|
+
export const select_values_of_entity_by_entity_id_or_handle =
|
581
|
+
(eb, entity_junction_table, entity_id_or_handle) => {
|
582
|
+
return eb
|
583
|
+
.selectFrom(entity_junction_table)
|
584
|
+
.select(`${entity_junction_table}.value`)
|
585
|
+
.where(eb2 => eb2.or(
|
586
|
+
[
|
587
|
+
eb2(`${entity_junction_table}.entity_id`, '=', entity_id_or_handle),
|
588
|
+
eb2(`${entity_junction_table}.entity_handle`, '=', entity_id_or_handle),
|
589
|
+
]
|
590
|
+
)
|
591
|
+
)
|
592
|
+
.orderBy(`${entity_junction_table}.id`);
|
593
|
+
}
|
594
|
+
|
595
|
+
/**
|
596
|
+
* select the entity ids which are constrained by value or reporter
|
597
|
+
*
|
598
|
+
* @param {import('kysely').ExpressionBuilder<Database>} eb
|
599
|
+
* @param {EntityTableKeys} entity_junction_table
|
600
|
+
* @param {string | ExpressionWrapper<Database>} value
|
601
|
+
* @param {string | ExpressionWrapper<Database>} [reporter]
|
602
|
+
*/
|
603
|
+
export const select_entity_ids_by_value_or_reporter =
|
604
|
+
(eb, entity_junction_table, value, reporter=undefined) => {
|
605
|
+
return eb
|
606
|
+
.selectFrom(entity_junction_table)
|
607
|
+
.select(`${entity_junction_table}.entity_id`)
|
608
|
+
.where(eb2 => eb2.or(
|
609
|
+
[
|
610
|
+
eb2(`${entity_junction_table}.value`, '=', value ?? reporter),
|
611
|
+
eb2(`${entity_junction_table}.reporter`, '=', reporter ?? value),
|
612
|
+
]
|
613
|
+
)
|
614
|
+
)
|
615
|
+
.orderBy(`${entity_junction_table}.entity_id`);
|
616
|
+
}
|