@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/src/con.shared.js CHANGED
@@ -3,6 +3,7 @@
3
3
  * @import { Database } from '../types.sql.tables.js'
4
4
  * @import { ExpressionBuilder, InsertObject } from 'kysely'
5
5
  * @import { SqlDialectType } from '../types.public.js'
6
+ * @import { QueryableTables } from './utils.types.js'
6
7
  */
7
8
  import { ExpressionWrapper, InsertQueryBuilder, Kysely, Transaction } from 'kysely'
8
9
  import { jsonArrayFrom, stringArrayFrom } from './con.helpers.json.js'
@@ -46,7 +47,7 @@ export const safe_trx = (k) => {
46
47
 
47
48
  /**
48
49
  * @param {SQL} driver
49
- * @param {keyof Database} table_name
50
+ * @param {QueryableTables} table_name
50
51
  *
51
52
  * @returns {db_crud["count"]}
52
53
  */
@@ -54,16 +55,16 @@ export const count_regular = (driver, table_name) => {
54
55
  return async (query) => {
55
56
 
56
57
  const result = await driver.client
57
- .selectFrom(table_name)
58
- .select(
59
- (eb) => eb.fn.countAll().as('count')
60
- )
61
- .where(
62
- (eb) => {
63
- return query_to_eb(eb, query, table_name);
64
- }
65
- )
66
- .executeTakeFirst();
58
+ .selectFrom(table_name)
59
+ .select(
60
+ (eb) => eb.fn.countAll().as('count')
61
+ )
62
+ .where(
63
+ (eb) => {
64
+ return query_to_eb(eb, query, table_name);
65
+ }
66
+ )
67
+ .executeTakeFirst();
67
68
 
68
69
  return Number(result.count);
69
70
  }
@@ -111,50 +112,102 @@ export const where_id_or_handle_table = (id_or_handle) => {
111
112
  */
112
113
 
113
114
  /**
114
- * helper to generate entity values delete
115
+ * helper to delete entity values from conjunction table.
116
+ *
117
+ * Usually in entity tables, the (`value`, `reporter`) pair maps to
118
+ * (`secondary_entity_id`, `secondary_entity_handle`).
119
+ *
120
+ * 1. This is true for all entity tables except of `entity_to_tags_projections`,
121
+ * `entity_to_search_terms`, `entity_to_media`.
122
+ * 2. In those other entity tables, usually:
123
+ * - `value` identifies an entity
124
+ * - `reporter` handle identifies an entity in tables `products_to_collections`,
125
+ * `products_to_discounts`, `products_to_variants`, `products_to_related_products`
126
+ * - `reporter` does not identify an entity in `storefronts_to_other` because it
127
+ * hosts many resource types (for example, a post has the same handle as a product)
128
+ * - `reporter` + `context` identifies a secondary identity in `storefronts_to_other`
129
+ *
130
+ * Please consult the full documentation about interpretation of the entity
131
+ * tables in `../types.sql.tables.jd.ts`.
132
+ *
133
+ * Consult {@link '../types.sql.tables.jd.ts'} for the list of meaningful entity tables
134
+ * and their interpretations. and take a look at the database, it is actually
135
+ * quite simple
115
136
  *
116
137
  * @param {EntityTableKeys} entity_table_name
117
138
  */
118
- export const delete_entity_values_by_value_or_reporter = (entity_table_name) => {
139
+ export const delete_entity_values_by_value_or_reporter_and_context = (
140
+ entity_table_name
141
+ ) => {
119
142
  /**
120
143
  *
121
144
  * @param {Kysely<Database>} trx
122
145
  * @param {string} value delete by entity value
123
146
  * @param {string} [reporter] delete by reporter
147
+ * @param {string} [context] delete by reporter + context
124
148
  */
125
- return (trx, value, reporter=undefined) => {
149
+ return (trx, value, reporter, context) => {
126
150
 
127
151
  return trx.deleteFrom(entity_table_name).where(
128
152
  eb => eb.or(
129
153
  [
130
154
  value && eb('value', '=', value),
131
- reporter && eb('reporter', '=', reporter),
155
+ reporter && context && eb.and(
156
+ [
157
+ eb('reporter', '=', reporter),
158
+ eb('context', '=', context),
159
+ ]
160
+ ),
161
+ reporter && !(context) && eb('reporter', '=', reporter),
132
162
  ].filter(Boolean)
133
163
  )
134
164
  ).executeTakeFirst();
135
165
  }
136
166
  }
137
167
 
168
+
138
169
  /**
139
- * helper to generate entity values delete
170
+ * helper to delete entity values
171
+ *
172
+ * 1. either by `entity_id` which always identifies an entity.
173
+ * 2. or by `entity_handle` which identifies an entity for some entity tables
174
+ * such as `products_to_collections`, `products_to_discounts`, `products_to_variants`,
175
+ * `products_to_related_products`, `storefronts_to_other`
176
+ * 3. or by `entity_handle` + `context` which identifies an entity for some entity tables
177
+ * such as `entity_to_tags_projections`, `entity_to_search_terms`, `entity_to_media`
178
+ *
179
+ * - `entity_handle` by itself does not always identify an entity,
180
+ * but `entity_handle` + `context` does.
181
+ *
182
+ * for example, we may have a product and a collection with the same `entity_handle`
183
+ * in the `entity_to_tags_projections` table, but they are different entities.
184
+ * Therefore, if we naively delete by `entity_handle`, we may delete more entities than intended.
140
185
  *
141
186
  * @param {EntityTableKeys} entity_table_name
142
187
  */
143
- export const delete_entity_values_of_by_entity_id_or_handle =
144
- (entity_table_name) => {
188
+ export const delete_entity_values_of_by_entity_id_or_handle_and_context = (
189
+ entity_table_name
190
+ ) => {
145
191
  /**
146
192
  *
147
193
  * @param {Kysely<Database>} trx
148
194
  * @param {string} entity_id delete by id
149
- * @param {string} [entity_handle=entity_id] delete by handle
195
+ * @param {string} [entity_handle] delete by handle
196
+ * @param {string} [context=undefined] the context (another segment technique)
150
197
  */
151
- return (trx, entity_id, entity_handle=undefined) => {
198
+ return (trx, entity_id, entity_handle=undefined, context=undefined) => {
152
199
  return trx.deleteFrom(entity_table_name).where(
153
200
  eb => eb.or(
154
201
  [
155
- eb('entity_id', '=', entity_id),
156
- eb('entity_handle', '=', entity_handle ?? entity_id),
157
- ]
202
+ entity_id && eb('entity_id', '=', entity_id),
203
+ entity_handle && context && eb.and(
204
+ [
205
+ eb('entity_handle', '=', entity_handle),
206
+ eb('context', '=', context)
207
+ ]
208
+ ),
209
+ entity_handle && !(context) && eb('entity_handle', '=', entity_handle),
210
+ ].filter(Boolean)
158
211
  )
159
212
  ).executeTakeFirst();
160
213
  }
@@ -173,23 +226,18 @@ export const insert_entity_array_values_of = (entity_table_name) => {
173
226
  * @param {string} [item_handle] whom the tags belong to
174
227
  * @param {boolean} [delete_previous=true] if true and `reporter`,
175
228
  * then will delete by reporter, otherwise by `item_id/item_handle`
176
- * @param {string} [reporter=undefined] the reporter of the batch values
177
- * (another segment technique)
178
229
  * @param {string} [context=undefined] the context (another segment technique)
179
230
  */
180
- return async (trx, values, item_id, item_handle, delete_previous=true,
181
- reporter=undefined, context=undefined) => {
231
+ return async (
232
+ trx, values, item_id, item_handle,
233
+ delete_previous=true,
234
+ context=undefined
235
+ ) => {
182
236
 
183
237
  if(delete_previous) {
184
- if(reporter) {
185
- await delete_entity_values_by_value_or_reporter(entity_table_name)(
186
- trx, undefined, reporter
187
- );
188
- } else {
189
- await delete_entity_values_of_by_entity_id_or_handle(entity_table_name)(
190
- trx, item_id, item_handle
191
- );
192
- }
238
+ await delete_entity_values_of_by_entity_id_or_handle_and_context(entity_table_name)(
239
+ trx, item_id, item_handle, context
240
+ );
193
241
  }
194
242
 
195
243
  if(!values?.length) return Promise.resolve();
@@ -199,7 +247,6 @@ export const insert_entity_array_values_of = (entity_table_name) => {
199
247
  entity_handle: item_handle,
200
248
  entity_id: item_id,
201
249
  value: t,
202
- reporter,
203
250
  context
204
251
  })
205
252
  )
@@ -254,7 +301,7 @@ export const insert_entity_array_values_with_delete_of = (entity_table) => {
254
301
  */
255
302
  return (trx, values, item_id, item_handle, context) => {
256
303
  return insert_entity_array_values_of(entity_table)(
257
- trx, values, item_id, item_handle, true, undefined, context
304
+ trx, values, item_id, item_handle, true, context
258
305
  )
259
306
  };
260
307
  }
@@ -263,9 +310,9 @@ export const insert_tags_of = insert_entity_array_values_with_delete_of('entity_
263
310
  export const insert_search_of = insert_entity_array_values_with_delete_of('entity_to_search_terms');
264
311
  export const insert_media_of = insert_entity_array_values_with_delete_of('entity_to_media');
265
312
 
266
- export const delete_tags_of = delete_entity_values_of_by_entity_id_or_handle('entity_to_tags_projections');
267
- export const delete_search_of = delete_entity_values_of_by_entity_id_or_handle('entity_to_search_terms');
268
- export const delete_media_of = delete_entity_values_of_by_entity_id_or_handle('entity_to_media');
313
+ export const delete_tags_of = delete_entity_values_of_by_entity_id_or_handle_and_context('entity_to_tags_projections');
314
+ export const delete_search_of = delete_entity_values_of_by_entity_id_or_handle_and_context('entity_to_search_terms');
315
+ export const delete_media_of = delete_entity_values_of_by_entity_id_or_handle_and_context('entity_to_media');
269
316
 
270
317
 
271
318
  /**
@@ -679,25 +726,25 @@ export const select_values_of_entity_by_entity_id_or_handle =
679
726
  .orderBy(`${entity_junction_table}.id`);
680
727
  }
681
728
 
682
- /**
683
- * select the entity ids which are constrained by value or reporter
684
- *
685
- * @param {ExpressionBuilder<Database>} eb
686
- * @param {EntityTableKeys} entity_junction_table
687
- * @param {string | ExpressionWrapper<Database>} value
688
- * @param {string | ExpressionWrapper<Database>} [reporter]
689
- */
690
- export const select_entity_ids_by_value_or_reporter =
691
- (eb, entity_junction_table, value, reporter=undefined) => {
692
- return eb
693
- .selectFrom(entity_junction_table)
694
- .select(`${entity_junction_table}.entity_id`)
695
- .where(eb2 => eb2.or(
696
- [
697
- eb2(`${entity_junction_table}.value`, '=', value ?? reporter),
698
- eb2(`${entity_junction_table}.reporter`, '=', reporter ?? value),
699
- ]
700
- )
701
- )
702
- .orderBy(`${entity_junction_table}.entity_id`);
703
- }
729
+ // /**
730
+ // * select the entity ids which are constrained by value or reporter
731
+ // *
732
+ // * @param {ExpressionBuilder<Database>} eb
733
+ // * @param {EntityTableKeys} entity_junction_table
734
+ // * @param {string | ExpressionWrapper<Database>} value
735
+ // * @param {string | ExpressionWrapper<Database>} [reporter]
736
+ // */
737
+ // export const select_entity_ids_by_value_or_reporter =
738
+ // (eb, entity_junction_table, value, reporter=undefined) => {
739
+ // return eb
740
+ // .selectFrom(entity_junction_table)
741
+ // .select(`${entity_junction_table}.entity_id`)
742
+ // .where(eb2 => eb2.or(
743
+ // [
744
+ // eb2(`${entity_junction_table}.value`, '=', value ?? reporter),
745
+ // eb2(`${entity_junction_table}.reporter`, '=', reporter ?? value),
746
+ // ]
747
+ // )
748
+ // )
749
+ // .orderBy(`${entity_junction_table}.entity_id`);
750
+ // }
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { SQL } from '../index.js'
5
5
  import { report_document_media } from './con.images.js'
6
- import { count_regular, delete_entity_values_by_value_or_reporter,
6
+ import { count_regular, delete_entity_values_by_value_or_reporter_and_context,
7
7
  delete_me, delete_media_of, delete_search_of,
8
8
  delete_tags_of, insert_media_of, insert_search_of,
9
9
  insert_tags_of, regular_upsert_me, where_id_or_handle_table,
@@ -83,12 +83,12 @@ const remove = (driver) => {
83
83
  async (trx) => {
84
84
 
85
85
  // entities
86
- await delete_search_of(trx, id_or_handle);
87
- await delete_media_of(trx, id_or_handle);
88
- await delete_tags_of(trx, id_or_handle);
86
+ await delete_tags_of(trx, id_or_handle, id_or_handle, table_name);
87
+ await delete_search_of(trx, id_or_handle, id_or_handle, table_name);
88
+ await delete_media_of(trx, id_or_handle, id_or_handle, table_name);
89
89
  // STOREFRONT => SHIPPING
90
- await delete_entity_values_by_value_or_reporter('storefronts_to_other')(
91
- trx, id_or_handle, id_or_handle
90
+ await delete_entity_values_by_value_or_reporter_and_context('storefronts_to_other')(
91
+ trx, id_or_handle, id_or_handle, table_name
92
92
  );
93
93
  // delete me
94
94
  await delete_me(trx, table_name, id_or_handle);
@@ -1,9 +1,11 @@
1
1
  /**
2
2
  * @import { db_storefronts as db_col } from '@storecraft/core/database'
3
+ * @import { Database } from '../types.sql.tables.js';
3
4
  */
4
5
  import { SQL } from '../index.js'
6
+ import { jsonArrayFrom, stringArrayFrom } from './con.helpers.json.js'
5
7
  import { report_document_media } from './con.images.js'
6
- import { delete_entity_values_of_by_entity_id_or_handle,
8
+ import { delete_entity_values_of_by_entity_id_or_handle_and_context,
7
9
  delete_me, delete_media_of, delete_search_of,
8
10
  delete_tags_of, insert_entity_values_of, insert_media_of,
9
11
  insert_search_of, insert_tags_of, storefront_with_collections,
@@ -12,7 +14,11 @@ import { delete_entity_values_of_by_entity_id_or_handle,
12
14
  regular_upsert_me, where_id_or_handle_table,
13
15
  with_media, with_tags,
14
16
  count_regular,
15
- with_search} from './con.shared.js'
17
+ with_search,
18
+ products_with_collections,
19
+ products_with_discounts,
20
+ products_with_variants,
21
+ products_with_related_products} from './con.shared.js'
16
22
  import { sanitize, sanitize_array } from './utils.funcs.js'
17
23
  import { query_to_eb, query_to_sort } from './utils.query.js'
18
24
 
@@ -35,8 +41,8 @@ const upsert = (driver) => {
35
41
  await report_document_media(driver)(item, trx);
36
42
  // Explicit STOREFRONTS => PRODUCTS / COLLECTIONS / DISCOUNTS / SHIPPING / POSTS
37
43
  // remove all the past connections of this storefront at once
38
- await delete_entity_values_of_by_entity_id_or_handle('storefronts_to_other')(
39
- trx, item.id, item.handle
44
+ await delete_entity_values_of_by_entity_id_or_handle_and_context('storefronts_to_other')(
45
+ trx, item.id
40
46
  );
41
47
  if(item.collections) { // add this storefront's new collections connections
42
48
  await insert_entity_values_of('storefronts_to_other')(
@@ -115,11 +121,21 @@ const get = (driver) => {
115
121
  with_media(eb, id_or_handle, driver.dialectType),
116
122
  with_tags(eb, id_or_handle, driver.dialectType),
117
123
  with_search(eb, id_or_handle, driver.dialectType),
118
- expand_collections && storefront_with_collections(eb, id_or_handle, driver.dialectType),
119
- expand_products && storefront_with_products(eb, id_or_handle, driver.dialectType),
120
- expand_discounts && storefront_with_discounts(eb, id_or_handle, driver.dialectType),
121
- expand_shipping && storefront_with_shipping(eb, id_or_handle, driver.dialectType),
122
- expand_posts && storefront_with_posts(eb, id_or_handle, driver.dialectType),
124
+ expand_collections && storefront_with_collections(
125
+ eb, id_or_handle, driver.dialectType
126
+ ),
127
+ expand_products && storefront_with_products(
128
+ eb, id_or_handle, driver.dialectType
129
+ ),
130
+ expand_discounts && storefront_with_discounts(
131
+ eb, id_or_handle, driver.dialectType
132
+ ),
133
+ expand_shipping && storefront_with_shipping(
134
+ eb, id_or_handle, driver.dialectType
135
+ ),
136
+ expand_posts && storefront_with_posts(
137
+ eb, id_or_handle, driver.dialectType
138
+ ),
123
139
  ]
124
140
  .filter(Boolean))
125
141
  .where(where_id_or_handle_table(id_or_handle))
@@ -140,11 +156,12 @@ const remove = (driver) => {
140
156
  async (trx) => {
141
157
 
142
158
  // entities
143
- await delete_search_of(trx, id_or_handle);
144
- await delete_tags_of(trx, id_or_handle);
145
- await delete_media_of(trx, id_or_handle);
159
+ await delete_tags_of(trx, id_or_handle, id_or_handle, table_name);
160
+ await delete_search_of(trx, id_or_handle, id_or_handle, table_name);
161
+ await delete_media_of(trx, id_or_handle, id_or_handle, table_name);
146
162
  // delete storefront => other
147
- await delete_entity_values_of_by_entity_id_or_handle('storefronts_to_other')(
163
+ // this is correct, since `id` or `handle` are both unique for this table
164
+ await delete_entity_values_of_by_entity_id_or_handle_and_context('storefronts_to_other')(
148
165
  trx, id_or_handle, id_or_handle
149
166
  );
150
167
  // delete me
@@ -183,11 +200,21 @@ const list = (driver) => {
183
200
  with_media(eb, eb.ref('storefronts.id'), driver.dialectType),
184
201
  with_tags(eb, eb.ref('storefronts.id'), driver.dialectType),
185
202
  with_search(eb, eb.ref('storefronts.id'), driver.dialectType),
186
- expand_collections && storefront_with_collections(eb, eb.ref('storefronts.id'), driver.dialectType),
187
- expand_products && storefront_with_products(eb, eb.ref('storefronts.id'), driver.dialectType),
188
- expand_discounts && storefront_with_discounts(eb, eb.ref('storefronts.id'), driver.dialectType),
189
- expand_shipping && storefront_with_shipping(eb, eb.ref('storefronts.id'), driver.dialectType),
190
- expand_posts && storefront_with_posts(eb, eb.ref('storefronts.id'), driver.dialectType),
203
+ expand_collections && storefront_with_collections(
204
+ eb, eb.ref('storefronts.id'), driver.dialectType
205
+ ),
206
+ expand_products && storefront_with_products(
207
+ eb, eb.ref('storefronts.id'), driver.dialectType
208
+ ),
209
+ expand_discounts && storefront_with_discounts(
210
+ eb, eb.ref('storefronts.id'), driver.dialectType
211
+ ),
212
+ expand_shipping && storefront_with_shipping(
213
+ eb, eb.ref('storefronts.id'), driver.dialectType
214
+ ),
215
+ expand_posts && storefront_with_posts(
216
+ eb, eb.ref('storefronts.id'), driver.dialectType
217
+ ),
191
218
  ].filter(Boolean)
192
219
  )
193
220
  .where(
@@ -206,82 +233,139 @@ const list = (driver) => {
206
233
  }
207
234
 
208
235
  /**
209
- * @param {SQL} driver
210
- * @returns {db_col["list_storefront_products"]}
236
+ * @type {{[K in keyof Database]?: (keyof Database[K])[]}}
211
237
  */
212
- const list_storefront_products = (driver) => {
213
- return async (product_id_or_handle) => {
214
- // because we load everything (we don't expect storefronts to
215
- // promote so many products), therefore we use the simple `get`
216
- // method instead of a query
217
- const item = await get(driver)(
218
- product_id_or_handle, { expand: ['products'] }
219
- );
220
- return item?.products ?? []
238
+ const resource_to_props = (
239
+ {
240
+ 'collections': ['active', 'attributes', 'created_at', 'description', 'handle', 'id', 'published', 'title', 'updated_at'],
241
+ 'discounts': ['active', 'application', 'attributes', 'created_at', 'description', 'handle', 'id', 'info', 'priority', 'published', 'title', 'updated_at'],
242
+ 'products': ['active', 'attributes', 'compare_at_price', 'created_at', 'description', 'handle', 'id', 'isbn', 'parent_handle', 'parent_id', 'price', 'qty', 'title', 'updated_at', 'variant_hint', 'variants_options', 'video'],
243
+ 'shipping_methods': ['active', 'attributes', 'created_at', 'description', 'handle', 'id', 'price', 'title', 'updated_at'],
244
+ 'posts': ['active', 'attributes', 'created_at', 'description', 'handle', 'id', 'text', 'title', 'updated_at'],
221
245
  }
222
- }
246
+ );
223
247
 
224
- /**
225
- * @param {SQL} driver
226
- * @returns {db_col["list_storefront_collections"]}
227
- */
228
- const list_storefront_collections = (driver) => {
229
- return async (product_id_or_handle) => {
230
- // because we load everything (we don't expect storefronts to
231
- // promote so many products), therefore we use the simple `get`
232
- // method instead of a query
233
- const item = await get(driver)(
234
- product_id_or_handle, { expand: ['collections'] }
235
- );
236
- return item?.collections ?? []
237
- }
238
- }
239
-
240
- /**
241
- * @param {SQL} driver
242
- * @returns {db_col["list_storefront_discounts"]}
243
- */
244
- const list_storefront_discounts = (driver) => {
245
- return async (product_id_or_handle) => {
246
- // because we load everything (we don't expect storefronts to
247
- // promote so many products), therefore we use the simple `get`
248
- // method instead of a query
249
- const item = await get(driver)(
250
- product_id_or_handle, { expand: ['discounts'] }
251
- );
252
- return item?.discounts ?? []
253
- }
254
- }
255
248
 
256
249
  /**
257
250
  * @param {SQL} driver
258
- * @returns {db_col["list_storefront_posts"]}
251
+ * @returns {db_col["get_default_auto_generated_storefront"]}
259
252
  */
260
- const list_storefront_posts = (driver) => {
261
- return async (product_id_or_handle) => {
262
- // because we load everything (we don't expect storefronts to
263
- // promote so many products), therefore we use the simple `get`
264
- // method instead of a query
265
- const item = await get(driver)(
266
- product_id_or_handle, { expand: ['posts'] }
253
+ const get_default_auto_generated_storefront = (driver) => {
254
+ return async () => {
255
+ const client = driver.client;
256
+ const dialectType = driver.dialectType;
257
+ const limit = -1;
258
+ const sf = await client.selectNoFrom(
259
+ eb => [
260
+ jsonArrayFrom(
261
+ eb
262
+ .selectFrom('collections')
263
+ .select(resource_to_props.collections)
264
+ .select(
265
+ eb => [
266
+ with_tags(eb, eb.ref('collections.id'), dialectType),
267
+ with_media(eb, eb.ref('collections.id'), dialectType),
268
+ ]
269
+ )
270
+ .where('active', '=', 1)
271
+ .orderBy(['updated_at desc']),
272
+ driver.dialectType
273
+ ).as('collections'),
274
+
275
+ jsonArrayFrom(
276
+ eb
277
+ .selectFrom('products')
278
+ .select(resource_to_props.products)
279
+ .select(
280
+ eb => [
281
+ with_tags(eb, eb.ref('products.id'), dialectType),
282
+ with_media(eb, eb.ref('products.id'), dialectType),
283
+ products_with_collections(eb, eb.ref('products.id'), dialectType),
284
+ products_with_discounts(eb, eb.ref('products.id'), dialectType),
285
+ products_with_variants(eb, eb.ref('products.id'), dialectType),
286
+ products_with_related_products(eb, eb.ref('products.id'), dialectType),
287
+ ]
288
+ )
289
+ .where('active', '=', 1)
290
+ .orderBy(['updated_at desc'])
291
+ .limit(10),
292
+ dialectType
293
+ ).as('products'),
294
+
295
+ jsonArrayFrom(
296
+ eb
297
+ .selectFrom('discounts')
298
+ .select(resource_to_props.discounts)
299
+ .select(
300
+ eb => [
301
+ with_tags(eb, eb.ref('discounts.id'), dialectType),
302
+ with_media(eb, eb.ref('discounts.id'), dialectType),
303
+ ]
304
+ )
305
+ .where('active', '=', 1)
306
+ .orderBy(['updated_at desc']),
307
+ dialectType
308
+ ).as('discounts'),
309
+
310
+ jsonArrayFrom(
311
+ eb
312
+ .selectFrom('shipping_methods')
313
+ .select(resource_to_props.shipping_methods)
314
+ .select(
315
+ eb => [
316
+ with_tags(eb, eb.ref('shipping_methods.id'), dialectType),
317
+ with_media(eb, eb.ref('shipping_methods.id'), dialectType),
318
+ ]
319
+ )
320
+ .where('active', '=', 1)
321
+ .orderBy(['updated_at desc']),
322
+ dialectType
323
+ ).as('shipping_methods'),
324
+
325
+ jsonArrayFrom(
326
+ eb
327
+ .selectFrom('posts')
328
+ .select(resource_to_props.posts)
329
+ .select(
330
+ eb => [
331
+ with_tags(eb, eb.ref('posts.id'), dialectType),
332
+ with_media(eb, eb.ref('posts.id'), dialectType),
333
+ ]
334
+ )
335
+ .where('active', '=', 1)
336
+ .orderBy(['updated_at desc'])
337
+ .limit(3),
338
+ dialectType
339
+ ).as('posts'),
340
+
341
+ stringArrayFrom(
342
+ eb.selectFrom('products')
343
+ .innerJoin(
344
+ 'entity_to_tags_projections',
345
+ 'entity_to_tags_projections.entity_id',
346
+ 'products.id'
347
+ )
348
+ .select('entity_to_tags_projections.value as tag')
349
+ .groupBy('tag'),
350
+ dialectType
351
+ ).as('all_used_products_tags')
352
+ ]
353
+ )
354
+ .executeTakeFirst();
355
+
356
+ const sanitized = sanitize(
357
+ {
358
+ active: true,
359
+ created_at: new Date().toISOString(),
360
+ handle: 'default-auto-generated-storefront',
361
+ id: 'default',
362
+ title: 'Default Auto Generated Storefront',
363
+ description: 'Default Auto Generated Storefront',
364
+ ...sf
365
+ }
267
366
  );
268
- return item?.posts ?? []
269
- }
270
- }
271
367
 
272
- /**
273
- * @param {SQL} driver
274
- * @returns {db_col["list_storefront_shipping_methods"]}
275
- */
276
- const list_storefront_shipping_methods = (driver) => {
277
- return async (product_id_or_handle) => {
278
- // because we load everything (we don't expect storefronts to
279
- // promote so many products), therefore we use the simple `get`
280
- // method instead of a query
281
- const item = await get(driver)(
282
- product_id_or_handle, { expand: ['shipping_methods'] }
283
- );
284
- return item?.shipping_methods ?? []
368
+ return sanitized;
285
369
  }
286
370
  }
287
371
 
@@ -296,12 +380,8 @@ export const impl = (driver) => {
296
380
  upsert: upsert(driver),
297
381
  remove: remove(driver),
298
382
  list: list(driver),
299
- list_storefront_products: list_storefront_products(driver),
300
- list_storefront_collections: list_storefront_collections(driver),
301
- list_storefront_discounts: list_storefront_discounts(driver),
302
- list_storefront_posts: list_storefront_posts(driver),
303
- list_storefront_shipping_methods: list_storefront_shipping_methods(driver),
304
383
  count: count_regular(driver, table_name),
384
+ get_default_auto_generated_storefront: get_default_auto_generated_storefront(driver),
305
385
  }
306
386
  }
307
387
 
package/src/con.tags.js CHANGED
@@ -2,10 +2,11 @@
2
2
  * @import { db_tags as db_col } from '@storecraft/core/database'
3
3
  */
4
4
  import { SQL } from '../index.js'
5
- import { count_regular, delete_me, delete_search_of, insert_search_of,
5
+ import {
6
+ count_regular, delete_me, delete_search_of, insert_search_of,
6
7
  regular_upsert_me, where_id_or_handle_table,
7
- with_media,
8
- with_search} from './con.shared.js'
8
+ with_media, with_search
9
+ } from './con.shared.js'
9
10
  import { sanitize, sanitize_array } from './utils.funcs.js'
10
11
  import { query_to_eb, query_to_sort } from './utils.query.js'
11
12
 
@@ -23,11 +24,14 @@ const upsert = (driver) => {
23
24
  async (trx) => {
24
25
  await insert_search_of(trx, search_terms, item.id, item.handle, table_name);
25
26
  await regular_upsert_me(trx, table_name, {
27
+ active: item.active ? 1 : 0,
28
+ description: item.description,
26
29
  created_at: item.created_at,
27
30
  updated_at: item.updated_at,
28
31
  id: item.id,
29
32
  handle: item.handle,
30
- values: JSON.stringify(item.values)
33
+ attributes: JSON.stringify(item.attributes),
34
+ values: JSON.stringify(item.values),
31
35
  });
32
36
  }
33
37
  );
@@ -71,7 +75,7 @@ const remove = (driver) => {
71
75
  async (trx) => {
72
76
 
73
77
  // entities
74
- await delete_search_of(trx, id_or_handle);
78
+ await delete_search_of(trx, id_or_handle, id_or_handle, table_name);
75
79
  // delete me
76
80
  await delete_me(trx, table_name, id_or_handle);
77
81
  }