@storecraft/database-sql-base 1.0.21 → 1.0.23

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/migrate.js CHANGED
@@ -101,44 +101,12 @@ export async function migrateToLatest(db_driver, release_db_upon_completion=true
101
101
  if (error) {
102
102
  console.error('failed to migrate')
103
103
  console.error(JSON.stringify(error, null, 2))
104
+ console.error(JSON.stringify(results, null, 2))
104
105
  process.exit(1)
105
106
  }
106
107
 
108
+ console.log('Resolving migrations COMPLETE.')
109
+
107
110
  if(release_db_upon_completion)
108
111
  await db.destroy();
109
112
  }
110
-
111
-
112
- /**
113
- * @description Just for education and debugging, do not use !!!
114
- * @param {string} stmt
115
- * @param {any[] | Record<string, any>} params
116
- */
117
- export const prepare_and_bind = (stmt='', params=[]) => {
118
- const params_object = Array.isArray(params) ?
119
- params.reduce((a, v, idx) => ({ ...a, [idx+1]: v}), {}) :
120
- params;
121
-
122
- let current = 0;
123
- let result = ''
124
- let index_run = 1;
125
- for (let m of stmt.matchAll(/\?[0-9]*/g)) {
126
- result += stmt.slice(current, m.index);
127
-
128
- const match_string = m[0];
129
- let index_access = match_string.length > 1 ?
130
- Number(match_string.slice(1)) :
131
- index_run;
132
-
133
- result += "'" + params_object[index_access] + "'";
134
-
135
- current = m.index + m[0].length;
136
- index_run+=1;
137
- }
138
-
139
- result += stmt.slice(current);
140
-
141
- return result;
142
- }
143
-
144
-
@@ -9,6 +9,12 @@ import { Kysely } from 'kysely'
9
9
  */
10
10
  export async function up(db) {
11
11
 
12
+ // console.log(
13
+ // db.schema.alterTable('auth_users')
14
+ // .addColumn('firstname', 'text')
15
+ // .compile()
16
+ // )
17
+
12
18
  await db.schema
13
19
  .alterTable('auth_users')
14
20
  .addColumn('firstname', 'text')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storecraft/database-sql-base",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "Official SQL Database driver for storecraft",
5
5
  "license": "MIT",
6
6
  "author": "Tomer Shalev (https://github.com/store-craft)",
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@storecraft/core": "^1.0.0",
41
- "kysely": "^0.27.2"
41
+ "kysely": "^0.28.1"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/better-sqlite3": "^7.6.9",
@@ -195,7 +195,7 @@ const list_customer_orders = (driver) => {
195
195
  * @returns {db_col["count_customer_orders"]}
196
196
  */
197
197
  const count_customer_orders = (driver) => {
198
- return async (id, query) => {
198
+ return async (customer_id_or_email, query) => {
199
199
 
200
200
  const result = await driver.client
201
201
  .selectFrom('orders')
@@ -208,8 +208,8 @@ const count_customer_orders = (driver) => {
208
208
  query_to_eb(eb, query, table_name),
209
209
  eb.or(
210
210
  [
211
- eb('_customer_id', '=', id),
212
- eb('_customer_email', '=', id),
211
+ eb('_customer_id', '=', customer_id_or_email),
212
+ eb('_customer_email', '=', customer_id_or_email),
213
213
  ]
214
214
  )
215
215
  ].filter(Boolean)
@@ -135,7 +135,7 @@ const upsert = (driver) => {
135
135
  application: JSON.stringify(item.application),
136
136
  info: JSON.stringify(item.info),
137
137
  _application_id: item.application.id,
138
- _discount_type_id: item.info.details.meta.id
138
+ _discount_type_id: item?.info?.details?.meta?.id ?? -1,
139
139
  });
140
140
  }
141
141
  );
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * @import {
3
- * DiscountType, FilterValue_p_in_price_range, FilterValue_p_not_in_collections,
4
- * FilterValue_p_in_collections, FilterValue_p_not_in_tags, FilterValue_p_in_tags,
5
- * FilterValue_p_in_products, FilterValue_p_not_in_products
3
+ * DiscountType, Filter_p_in_price_range, Filter_p_not_in_collections,
4
+ * Filter_p_in_collections, Filter_p_not_in_tags, Filter_p_in_tags,
5
+ * Filter_p_in_products, Filter_p_not_in_products
6
6
  * } from '@storecraft/core/api'
7
7
  * @import { Database } from '../types.sql.tables.js'
8
8
  * @import { ExpressionBuilder, BinaryOperator } from 'kysely'
@@ -11,7 +11,11 @@ import { enums } from "@storecraft/core/api";
11
11
 
12
12
  /** @param {DiscountType} d */
13
13
  const is_order_discount = d => {
14
- return (d.info.details.meta.id===enums.DiscountMetaEnum.order.id);
14
+ return (
15
+ (d.info.details.type===enums.DiscountMetaEnum.order.type) ||
16
+ // @ts-ignore
17
+ (d.info.details.meta?.type===enums.DiscountMetaEnum.order.type)
18
+ );
15
19
  }
16
20
 
17
21
  /** @param {DiscountType} d */
@@ -67,7 +71,7 @@ export const discount_to_conjunctions = (eb, d) => {
67
71
  const filters = d.info.filters;
68
72
 
69
73
  for(const filter of filters) {
70
- const op = filter.meta.op;
74
+ const op = filter.op ?? filter.meta.op;
71
75
 
72
76
  switch (op) {
73
77
  case enums.FilterMetaEnum.p_all.op:
@@ -75,60 +79,60 @@ export const discount_to_conjunctions = (eb, d) => {
75
79
  break;
76
80
  case enums.FilterMetaEnum.p_in_products.op:
77
81
  {
78
-
79
- const cast = /** @type {FilterValue_p_in_products} */ (
80
- Array.isArray(filter?.value) ? filter.value : []
82
+ const cast_filter = /** @type {Filter_p_in_products} */ (
83
+ filter
81
84
  );
82
-
85
+ const value = cast_filter?.value ?? [];
83
86
  conjunctions.push(
84
87
  eb(
85
88
  'products.handle', 'in',
86
- cast.map(item => item.handle).filter(Boolean)
89
+ value.map(item => item.handle).filter(Boolean)
87
90
  )
88
91
  );
89
92
  }
90
93
  break;
91
94
  case enums.FilterMetaEnum.p_not_in_products.op:
92
95
  {
93
-
94
- const cast = /** @type {FilterValue_p_not_in_products} */ (
95
- Array.isArray(filter?.value) ? filter.value : []
96
+ const cast_filter = /** @type {Filter_p_not_in_products} */ (
97
+ filter
96
98
  );
99
+ const value = cast_filter?.value ?? [];
97
100
 
98
101
  conjunctions.push(
99
102
  eb(
100
103
  'products.handle', 'not in',
101
- cast.map(item => item.handle).filter(Boolean)
104
+ value.map(item => item.handle).filter(Boolean)
102
105
  )
103
106
  );
104
107
  }
105
108
  break;
106
109
  case enums.FilterMetaEnum.p_in_tags.op:
107
110
  {
108
-
109
- const cast = /** @type {FilterValue_p_in_tags} */(
110
- Array.isArray(filter?.value) ? filter.value : []
111
+ const cast_filter = /** @type {Filter_p_in_tags} */ (
112
+ filter
111
113
  );
112
-
114
+ const value = cast_filter?.value ?? [];
115
+
113
116
  conjunctions.push(
114
117
  eb_in(
115
118
  eb, 'entity_to_tags_projections',
116
- cast
119
+ value
117
120
  )
118
121
  );
119
122
  }
120
123
  break;
121
124
  case enums.FilterMetaEnum.p_not_in_tags.op:
122
125
  {
123
- const cast = /** @type {FilterValue_p_not_in_tags} */ (
124
- Array.isArray(filter?.value) ? filter.value : []
126
+ const cast_filter = /** @type {Filter_p_not_in_tags} */ (
127
+ filter
125
128
  );
129
+ const value = cast_filter?.value ?? [];
126
130
 
127
131
  conjunctions.push(
128
132
  eb.not(
129
133
  eb_in(
130
134
  eb, 'entity_to_tags_projections',
131
- cast
135
+ value
132
136
  )
133
137
  )
134
138
  );
@@ -136,30 +140,32 @@ export const discount_to_conjunctions = (eb, d) => {
136
140
  break;
137
141
  case enums.FilterMetaEnum.p_in_collections.op:
138
142
  {
139
- const cast = /** @type {FilterValue_p_in_collections} */ (
140
- Array.isArray(filter?.value) ? filter.value : []
143
+ const cast_filter = /** @type {Filter_p_in_collections} */ (
144
+ filter
141
145
  );
146
+ const value = cast_filter?.value ?? [];
142
147
 
143
148
  // PROBLEM: we only have ids, but use handles in the filters
144
149
  conjunctions.push(
145
150
  eb_in(
146
151
  eb, 'products_to_collections',
147
- cast.map(c => c.id)
152
+ value.map(c => c.id)
148
153
  )
149
154
  );
150
155
  }
151
156
  break;
152
157
  case enums.FilterMetaEnum.p_not_in_collections.op:
153
158
  {
154
- const cast = /** @type {FilterValue_p_not_in_collections} */ (
155
- Array.isArray(filter?.value) ? filter.value : []
159
+ const cast_filter = /** @type {Filter_p_not_in_collections} */ (
160
+ filter
156
161
  );
162
+ const value = cast_filter?.value ?? [];
157
163
 
158
164
  conjunctions.push(
159
165
  eb.not(
160
166
  eb_in(
161
167
  eb, 'products_to_collections',
162
- cast.map(c => c.id)
168
+ value.map(c => c.id)
163
169
  )
164
170
  )
165
171
  );
@@ -167,16 +173,17 @@ export const discount_to_conjunctions = (eb, d) => {
167
173
  break;
168
174
  case enums.FilterMetaEnum.p_in_price_range.op:
169
175
  {
170
- const cast = /** @type {FilterValue_p_in_price_range} */ (
171
- {
172
- from: 0,
173
- to: Number.POSITIVE_INFINITY,
174
- ...(filter?.value ?? {}),
175
- }
176
+ const cast_filter = /** @type {Filter_p_in_price_range} */ (
177
+ filter
176
178
  );
177
-
178
- const from = extract_abs_number(cast.from);
179
- const to = extract_abs_number(cast.to);
179
+ const value = /** @type {Filter_p_in_price_range["value"]} */({
180
+ from: 0,
181
+ to: Number.POSITIVE_INFINITY,
182
+ ...(cast_filter?.value ?? {}),
183
+ });
184
+
185
+ const from = extract_abs_number(value.from);
186
+ const to = extract_abs_number(value.to);
180
187
 
181
188
  const conj = { price: { $and: [] } };
182
189
 
@@ -2,9 +2,11 @@
2
2
  * @import { db_notifications 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,
5
+ import {
6
+ count_regular, delete_me, delete_search_of,
6
7
  insert_search_of, regular_upsert_me, where_id_or_handle_table,
7
- with_search } from './con.shared.js'
8
+ with_search
9
+ } from './con.shared.js'
8
10
  import { sanitize_array } from './utils.funcs.js'
9
11
  import { query_to_eb, query_to_sort } from './utils.query.js'
10
12
 
@@ -75,6 +75,8 @@ const upsert = (driver) => {
75
75
  d.info.filters, item
76
76
  )
77
77
  );
78
+
79
+
78
80
 
79
81
  item.tags = union(
80
82
  [
@@ -420,73 +422,6 @@ const list = (driver) => {
420
422
  }
421
423
  }
422
424
 
423
- /**
424
- * @param {SQL} driver
425
- * @returns {db_col["list_all_product_collections"]}
426
- */
427
- const list_product_collections = (driver) => {
428
- return async (product_id_or_handle) => {
429
- // we don't expect many collections per products,
430
- // therefore we use the simple `get` method instead of a query
431
- const item = await get(driver)(
432
- product_id_or_handle, { expand: ['collections'] }
433
- );
434
- return item?.collections ?? []
435
- }
436
- }
437
-
438
- /**
439
- * @param {SQL} driver
440
- * @returns {db_col["list_all_product_discounts"]}
441
- */
442
- const list_product_discounts = (driver) => {
443
- return async (product_id_or_handle) => {
444
- // we don't expect many discounts per products,
445
- // therefore we use the simple `get` method instead of a query
446
- const item = await get(driver)(
447
- product_id_or_handle, { expand: ['discounts'] }
448
- );
449
- return item?.discounts ?? []
450
- }
451
- }
452
-
453
- /**
454
- * @param {SQL} driver
455
- *
456
- * @returns {db_col["list_all_product_variants"]}
457
- */
458
- const list_product_variants = (driver) => {
459
- return async (product_id_or_handle) => {
460
- // we don't expect many discounts per products,
461
- // therefore we use the simple `get` method instead of a query
462
- const item = await get(driver)(
463
- product_id_or_handle, { expand: ['variants'] }
464
- );
465
-
466
- if(item && (`variants` in item))
467
- return item.variants ?? [];
468
-
469
- return [];
470
- }
471
- }
472
-
473
- /**
474
- * @param {SQL} driver
475
- *
476
- * @returns {db_col["list_all_related_products"]}
477
- */
478
- const list_related_products = (driver) => {
479
- return async (product_id_or_handle) => {
480
- // we don't expect many discounts per products,
481
- // therefore we use the simple `get` method instead of a query
482
- const item = await get(driver)(
483
- product_id_or_handle, { expand: ['related_products'] }
484
- );
485
-
486
- return item?.related_products ?? [];
487
- }
488
- }
489
-
490
425
  /**
491
426
  * @param {SQL} driver
492
427
  * @returns {db_col["list_used_products_tags"]}
@@ -520,33 +455,36 @@ const list_used_products_tags = (driver) => {
520
455
  */
521
456
  const changeStockOfBy = (driver) => {
522
457
  return async (product_ids_or_handles, deltas) => {
523
-
524
- await driver.client.transaction().execute(
525
- async (trx) => {
526
- for(let ix=0; ix < product_ids_or_handles.length; ix++ ) {
527
- const id = product_ids_or_handles[ix];
528
- const delta = deltas[ix];
529
-
530
- await trx
531
- .updateTable('products')
532
- .set(
533
- eb => (
534
- {
535
- qty: eb('qty', '+', delta)
536
- }
458
+ try {
459
+ await driver.client.transaction().execute(
460
+ async (trx) => {
461
+ for(let ix=0; ix < product_ids_or_handles.length; ix++ ) {
462
+ const id = product_ids_or_handles[ix];
463
+ const delta = deltas[ix];
464
+
465
+ await trx
466
+ .updateTable('products')
467
+ .set(
468
+ eb => (
469
+ {
470
+ qty: eb('qty', '+', delta)
471
+ }
472
+ )
537
473
  )
538
- )
539
- .where(
540
- where_id_or_handle_table(id)
541
- )
542
- .execute()
543
-
474
+ .where(
475
+ where_id_or_handle_table(id)
476
+ )
477
+ .execute()
478
+ }
544
479
  }
545
- }
546
- );
480
+ );
481
+ } catch(e) {
482
+ console.log(e);
483
+ return false;
484
+ }
547
485
 
486
+ return true;
548
487
  }
549
-
550
488
  }
551
489
 
552
490
 
@@ -564,10 +502,6 @@ export const impl = (driver) => {
564
502
  upsert: upsert(driver),
565
503
  remove: remove(driver),
566
504
  list: list(driver),
567
- list_all_product_collections: list_product_collections(driver),
568
- list_all_product_discounts: list_product_discounts(driver),
569
- list_all_product_variants: list_product_variants(driver),
570
- list_all_related_products: list_related_products(driver),
571
505
  list_used_products_tags: list_used_products_tags(driver),
572
506
  count: count_regular(driver, table_name),
573
507
  }
@@ -3,6 +3,7 @@
3
3
  * @import { VQL } from '@storecraft/core/vql'
4
4
  * @import { Database } from '../types.sql.tables.js'
5
5
  * @import { BinaryOperator, ExpressionBuilder } from 'kysely'
6
+ * @import {DirectedOrderByStringReference, QueryableTables} from './utils.types.js'
6
7
  */
7
8
 
8
9
  import { parse } from "@storecraft/core/vql";
@@ -18,7 +19,8 @@ import { parse } from "@storecraft/core/vql";
18
19
  * @param {ExpressionBuilder<Database>} eb
19
20
  * @param {Cursor} c
20
21
  * @param {'>' | '>=' | '<' | '<='} relation
21
- * @param {(x: [k: string, v: any]) => [k: string, v: any]} transformer Your chance to change key and value
22
+ * @param {(x: [k: string, v: any]) => [k: string, v: any]} transformer
23
+ * Your chance to change key and value
22
24
  */
23
25
  export const query_cursor_to_eb = (eb, c, relation, transformer=(x)=>x) => {
24
26
 
@@ -94,11 +96,20 @@ export const query_vql_node_to_eb = (eb, node, table_name) => {
94
96
  [
95
97
  eb.or(
96
98
  [
97
- eb(`entity_to_search_terms.entity_id`, '=', eb.ref(`${table_name}.id`)),
98
- eb(`entity_to_search_terms.entity_handle`, '=', eb.ref(`${table_name}.handle`)),
99
+ eb(
100
+ `entity_to_search_terms.entity_id`, '=',
101
+ eb.ref(`${table_name}.id`)
102
+ ),
103
+ eb(
104
+ `entity_to_search_terms.entity_handle`, '=',
105
+ eb.ref(`${table_name}.handle`)
106
+ ),
99
107
  ]
100
108
  ),
101
- eb(`entity_to_search_terms.value`, 'like', node.value.toLowerCase())
109
+ eb(
110
+ `entity_to_search_terms.value`, 'like',
111
+ node.value.toLowerCase()
112
+ )
102
113
  ]
103
114
  )
104
115
  )
@@ -129,7 +140,9 @@ export const query_vql_node_to_eb = (eb, node, table_name) => {
129
140
  * @param {QueryableTables} table_name
130
141
  */
131
142
  export const query_vql_to_eb = (eb, root, table_name) => {
132
- return root ? query_vql_node_to_eb(eb, root, table_name) : undefined;
143
+ return root ?
144
+ query_vql_node_to_eb(eb, root, table_name) :
145
+ undefined;
133
146
  }
134
147
 
135
148
 
@@ -169,15 +182,31 @@ export const query_to_eb = (eb, q={}, table_name) => {
169
182
 
170
183
  // compute index clauses
171
184
  if(q.startAt) {
172
- clauses.push(query_cursor_to_eb(eb, q.startAt, asc ? '>=' : '<=', transformer));
185
+ clauses.push(
186
+ query_cursor_to_eb(
187
+ eb, q.startAt, asc ? '>=' : '<=', transformer
188
+ )
189
+ );
173
190
  } else if(q.startAfter) {
174
- clauses.push(query_cursor_to_eb(eb, q.startAfter, asc ? '>' : '<', transformer));
191
+ clauses.push(
192
+ query_cursor_to_eb(
193
+ eb, q.startAfter, asc ? '>' : '<', transformer
194
+ )
195
+ );
175
196
  }
176
197
 
177
198
  if(q.endAt) {
178
- clauses.push(query_cursor_to_eb(eb, q.endAt, asc ? '<=' : '>=', transformer));
199
+ clauses.push(
200
+ query_cursor_to_eb(
201
+ eb, q.endAt, asc ? '<=' : '>=', transformer
202
+ )
203
+ );
179
204
  } else if(q.endBefore) {
180
- clauses.push(query_cursor_to_eb(eb, q.endBefore, asc ? '<' : '>', transformer));
205
+ clauses.push(
206
+ query_cursor_to_eb(
207
+ eb, q.endBefore, asc ? '<' : '>', transformer
208
+ )
209
+ );
181
210
  }
182
211
 
183
212
  // compute VQL clauses
@@ -187,7 +216,10 @@ export const query_to_eb = (eb, q={}, table_name) => {
187
216
  }
188
217
  } catch(e) {}
189
218
 
190
- const vql_clause = query_vql_to_eb(eb, q.vqlParsed, table_name)
219
+ const vql_clause = query_vql_to_eb(
220
+ eb, q.vqlParsed, table_name
221
+ );
222
+
191
223
  vql_clause && clauses.push(vql_clause);
192
224
 
193
225
  return eb.and(clauses);
@@ -198,12 +230,6 @@ const SIGN = {
198
230
  '-1': 'desc'
199
231
  }
200
232
 
201
- // export type DirectedOrderByStringReference<DB, TB extends keyof DB, O> = `${StringReference<DB, TB> | (keyof O & string)} ${OrderByDirection}`;
202
-
203
- /**
204
- * @import {DirectedOrderByStringReference, QueryableTables} from './utils.types.js'
205
- */
206
- // OE extends OrderByExpression<DB, TB, O>
207
233
  /**
208
234
  * Convert an API Query into mongo dialect, also sanitize.
209
235
  * @template {Record<string, any>} [Type=Record<string, any>]
@@ -227,5 +253,9 @@ export const query_to_sort = (q={}, table) => {
227
253
  )
228
254
  // it's too complicated to map each ket to table column.
229
255
  // kysely was designed to do this in place
230
- return (/** @type {DirectedOrderByStringReference<Database, Table, Database[Table]>[]} */ (sort));
256
+ return (
257
+ /** @type {DirectedOrderByStringReference<Database, Table, Database[Table]>[]} */ (
258
+ sort
259
+ )
260
+ );
231
261
  }
package/utils.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @description Just for education and debugging, do not use !!!
3
+ * @param {string} stmt
4
+ * @param {any[] | Record<string, any>} params
5
+ */
6
+ export const prepare_and_bind = (stmt='', params=[]) => {
7
+ const params_object = Array.isArray(params) ?
8
+ params.reduce((a, v, idx) => ({ ...a, [idx+1]: v}), {}) :
9
+ params;
10
+
11
+ let current = 0;
12
+ let result = ''
13
+ let index_run = 1;
14
+ for (let m of stmt.matchAll(/\?[0-9]*/g)) {
15
+ result += stmt.slice(current, m.index);
16
+
17
+ const match_string = m[0];
18
+ let index_access = match_string.length > 1 ?
19
+ Number(match_string.slice(1)) :
20
+ index_run;
21
+
22
+ result += "'" + params_object[index_access] + "'";
23
+
24
+ current = m.index + m[0].length;
25
+ index_run+=1;
26
+ }
27
+
28
+ result += stmt.slice(current);
29
+
30
+ return result;
31
+ }
32
+
33
+