@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.
Files changed (49) hide show
  1. package/README.md +126 -0
  2. package/TODO.md +2 -0
  3. package/db-strategy.md +3 -0
  4. package/driver.js +190 -0
  5. package/index.js +3 -0
  6. package/migrate.js +66 -0
  7. package/migrations.mssql/00000_init_tables.js +268 -0
  8. package/migrations.mysql/00000_init_tables.js +372 -0
  9. package/migrations.mysql/00001_seed_email_templates.js +1 -0
  10. package/migrations.postgres/00000_init_tables.js +358 -0
  11. package/migrations.postgres/00001_seed_email_templates.js +1 -0
  12. package/migrations.shared/00001_seed_email_templates.js +260 -0
  13. package/migrations.sqlite/00000_init_tables.js +357 -0
  14. package/migrations.sqlite/00001_seed_email_templates.js +1 -0
  15. package/package.json +47 -0
  16. package/src/con.auth_users.js +159 -0
  17. package/src/con.collections.js +197 -0
  18. package/src/con.customers.js +202 -0
  19. package/src/con.discounts.js +225 -0
  20. package/src/con.discounts.utils.js +180 -0
  21. package/src/con.helpers.json.js +231 -0
  22. package/src/con.helpers.json.mssql.js +233 -0
  23. package/src/con.helpers.json.mysql.js +239 -0
  24. package/src/con.helpers.json.postgres.js +223 -0
  25. package/src/con.helpers.json.sqlite.js +263 -0
  26. package/src/con.images.js +230 -0
  27. package/src/con.notifications.js +149 -0
  28. package/src/con.orders.js +156 -0
  29. package/src/con.posts.js +147 -0
  30. package/src/con.products.js +497 -0
  31. package/src/con.search.js +148 -0
  32. package/src/con.shared.js +616 -0
  33. package/src/con.shipping.js +147 -0
  34. package/src/con.storefronts.js +301 -0
  35. package/src/con.tags.js +120 -0
  36. package/src/con.templates.js +133 -0
  37. package/src/kysely.sanitize.plugin.js +40 -0
  38. package/src/utils.funcs.js +77 -0
  39. package/src/utils.query.js +195 -0
  40. package/tests/query.cursor.test.js +389 -0
  41. package/tests/query.vql.test.js +71 -0
  42. package/tests/runner.mssql-local.test.js +118 -0
  43. package/tests/runner.mysql-local.test.js +101 -0
  44. package/tests/runner.postgres-local.test.js +99 -0
  45. package/tests/runner.sqlite-local.test.js +99 -0
  46. package/tests/sandbox.test.js +71 -0
  47. package/tsconfig.json +21 -0
  48. package/types.public.d.ts +19 -0
  49. package/types.sql.tables.d.ts +247 -0
@@ -0,0 +1,358 @@
1
+ import { CreateTableBuilder, Kysely } from 'kysely'
2
+
3
+ /**
4
+ * @typedef {import('../types.sql.tables.js').Database} Database
5
+ */
6
+
7
+ /**
8
+ * @template {string} TB
9
+ * @template {string} B
10
+ * @param {CreateTableBuilder<TB, B>} tb
11
+ */
12
+ const add_base_columns = tb => {
13
+ return tb
14
+ .addColumn('id', 'text', (col) =>
15
+ col.primaryKey()
16
+ )
17
+ .addColumn('handle', 'text', (col) => col.unique())
18
+ .addColumn('created_at', 'text')
19
+ .addColumn('updated_at', 'text')
20
+ .addColumn('attributes', 'json')
21
+ .addColumn('description', 'text')
22
+ .addColumn('active', 'integer')
23
+ }
24
+
25
+ /**
26
+ * @param {Kysely<Database>} db
27
+ * @param {keyof Database} table_name
28
+ */
29
+ const create_entity_to_value_table = (db, table_name) => {
30
+
31
+ return db.schema
32
+ .createTable(table_name)
33
+ .addColumn('id', 'bigserial',
34
+ (col) => col.primaryKey()
35
+ )
36
+ .addColumn('entity_id', 'text', col => col.notNull())
37
+ .addColumn('entity_handle', 'text')
38
+ .addColumn('value', 'text')
39
+ .addColumn('reporter', 'text')
40
+ .addColumn('context', 'text')
41
+ }
42
+
43
+ /**
44
+ *
45
+ * @param {Kysely<Database>} db
46
+ * @param {keyof Database} table_name
47
+ */
48
+ const create_safe_table = (db, table_name) => {
49
+ return db.schema.createTable(table_name);
50
+ }
51
+
52
+ /**
53
+ *
54
+ * @param {Kysely<Database>} db
55
+ * @param {keyof Database} table_name
56
+ */
57
+ const drop_safe_table = (db, table_name) => {
58
+ return db.schema.dropTable(table_name).execute();
59
+ }
60
+
61
+ /**
62
+ * @param {Kysely<Database>} db
63
+ * @param {keyof Database} table_name
64
+ * @param {boolean} [include_id=true]
65
+ * @param {boolean} [include_handle=true]
66
+ */
67
+ const create_base_indexes = async (db, table_name, include_id=true, include_handle=true) => {
68
+ if(include_id) {
69
+ await db.schema.createIndex(`index_${table_name}_id_updated_at_asc`)
70
+ .on(table_name)
71
+ .columns(['id', 'updated_at asc'])
72
+ .execute();
73
+ await db.schema.createIndex(`index_${table_name}_id_updated_at_desc`)
74
+ .on(table_name)
75
+ .columns(['id', 'updated_at desc'])
76
+ .execute();
77
+ }
78
+
79
+ if(include_handle) {
80
+ await db.schema.createIndex(`index_${table_name}_handle_updated_at_asc`)
81
+ .on(table_name)
82
+ .columns(['handle', 'updated_at asc'])
83
+ .execute();
84
+ await db.schema.createIndex(`index_${table_name}_handle_updated_at_desc`)
85
+ .on(table_name)
86
+ .columns(['handle', 'updated_at desc'])
87
+ .execute();
88
+ }
89
+ }
90
+
91
+
92
+ /**
93
+ * @param {Kysely<Database>} db
94
+ * @param {keyof Pick<Database, 'entity_to_media' |
95
+ * 'entity_to_search_terms' | 'entity_to_tags_projections' |
96
+ * 'products_to_collections' | 'products_to_discounts' |
97
+ * 'products_to_variants' | 'storefronts_to_other'>} table_name
98
+ */
99
+ const create_entity_table_indexes = async (db, table_name) => {
100
+ await db.schema.createIndex(`index_${table_name}_entity_id`)
101
+ .on(table_name)
102
+ .column('entity_id')
103
+ .execute();
104
+ await db.schema.createIndex(`index_${table_name}_entity_handle`)
105
+ .on(table_name)
106
+ .column('entity_handle')
107
+ .execute();
108
+ await db.schema.createIndex(`index_${table_name}_value`)
109
+ .on(table_name)
110
+ .column('value')
111
+ .execute();
112
+ await db.schema.createIndex(`index_${table_name}_reporter`)
113
+ .on(table_name)
114
+ .column('reporter')
115
+ .execute();
116
+ await db.schema.createIndex(`index_${table_name}_context`)
117
+ .on(table_name)
118
+ .column('context')
119
+ .execute();
120
+ }
121
+
122
+ /**
123
+ *
124
+ * @param {Kysely<Database>} db
125
+ */
126
+ export async function up(db) {
127
+ { // auth_users
128
+ let tb = create_safe_table(db, 'auth_users');
129
+ tb = add_base_columns(tb);
130
+ tb = tb
131
+ .addColumn('email', 'text', (col) => col.unique())
132
+ .addColumn('password', 'text')
133
+ .addColumn('roles', 'json')
134
+ .addColumn('confirmed_mail', 'integer');
135
+ await tb.execute();
136
+ await create_base_indexes(db, 'auth_users');
137
+ }
138
+
139
+ { // tags
140
+ let tb = create_safe_table(db, 'tags');
141
+ tb = add_base_columns(tb);
142
+ tb = tb.addColumn('values', 'json');
143
+ await tb.execute();
144
+ await create_base_indexes(db, 'tags');
145
+ }
146
+
147
+ { // templates
148
+ let tb = create_safe_table(db, 'templates');
149
+ tb = add_base_columns(tb);
150
+ tb = tb.addColumn('title', 'text');
151
+ tb = tb.addColumn('template', 'text');
152
+ tb = tb.addColumn('reference_example_input', 'json');
153
+ await tb.execute();
154
+ await create_base_indexes(db, 'templates');
155
+ }
156
+
157
+ { // collections
158
+ let tb = create_safe_table(db, 'collections');
159
+ tb = add_base_columns(tb);
160
+ tb = tb
161
+ .addColumn('title', 'text')
162
+ .addColumn('published', 'text')
163
+ await tb.execute();
164
+ await create_base_indexes(db, 'collections');
165
+ }
166
+
167
+ { // products
168
+ let tb = create_safe_table(db, 'products');
169
+ tb = add_base_columns(tb);
170
+ tb = tb
171
+ .addColumn('title', 'text')
172
+ .addColumn('video', 'text')
173
+ .addColumn('price', 'numeric')
174
+ .addColumn('isbn', 'text', (col) => col.unique())
175
+ .addColumn('compare_at_price', 'numeric')
176
+ .addColumn('qty', 'integer')
177
+ .addColumn('variants_options', 'json')
178
+ .addColumn('parent_handle', 'text')
179
+ .addColumn('parent_id', 'text')
180
+ .addColumn('variant_hint', 'json')
181
+ await tb.execute();
182
+ await create_base_indexes(db, 'products');
183
+ }
184
+
185
+ { // products_to_collections
186
+ await create_entity_to_value_table(db, 'products_to_collections').execute();
187
+ await create_entity_table_indexes(db, 'products_to_collections');
188
+ }
189
+
190
+ { // products_to_discounts
191
+ await create_entity_to_value_table(db, 'products_to_discounts').execute();
192
+ await create_entity_table_indexes(db, 'products_to_discounts');
193
+ }
194
+
195
+ { // products_to_variants
196
+ await create_entity_to_value_table(db, 'products_to_variants').execute();
197
+ await create_entity_table_indexes(db, 'products_to_variants');
198
+ }
199
+
200
+ { // products_to_related_products
201
+ await create_entity_to_value_table(db, 'products_to_related_products').execute();
202
+ await create_entity_table_indexes(db, 'products_to_related_products');
203
+ }
204
+
205
+ { // shipping_methods
206
+ let tb = create_safe_table(db, 'shipping_methods');
207
+ tb = add_base_columns(tb);
208
+ tb = tb
209
+ .addColumn('title', 'text')
210
+ .addColumn('price', 'numeric')
211
+ await tb.execute();
212
+ await create_base_indexes(db, 'shipping_methods');
213
+ }
214
+
215
+ { // posts
216
+ let tb = create_safe_table(db, 'posts');
217
+ tb = add_base_columns(tb);
218
+ tb = tb
219
+ .addColumn('title', 'text')
220
+ .addColumn('text', 'text')
221
+ await tb.execute();
222
+ await create_base_indexes(db, 'posts');
223
+ }
224
+
225
+ { // customers
226
+ let tb = create_safe_table(db, 'customers');
227
+ tb = add_base_columns(tb);
228
+ tb = tb
229
+ .addColumn('email', 'text', (col) => col.unique())
230
+ .addColumn('auth_id', 'text', (col) => col.unique())
231
+ .addColumn('firstname', 'text')
232
+ .addColumn('lastname', 'text')
233
+ .addColumn('phone_number', 'text')
234
+ .addColumn('address', 'json')
235
+ await tb.execute();
236
+ await create_base_indexes(db, 'customers');
237
+ }
238
+
239
+ { // orders
240
+ let tb = create_safe_table(db, 'orders');
241
+ tb = add_base_columns(tb);
242
+ tb = tb
243
+ .addColumn('contact', 'json')
244
+ .addColumn('address', 'json')
245
+ .addColumn('line_items', 'json')
246
+ .addColumn('notes', 'text')
247
+ .addColumn('shipping_method', 'json')
248
+ .addColumn('status', 'json')
249
+ .addColumn('pricing', 'json')
250
+ .addColumn('validation', 'json')
251
+ .addColumn('payment_gateway', 'json')
252
+ .addColumn('coupons', 'json')
253
+ .addColumn('_customer_id', 'text')
254
+ .addColumn('_customer_email', 'text')
255
+ .addColumn('_status_payment_id', 'integer')
256
+ .addColumn('_status_checkout_id', 'integer')
257
+ .addColumn('_status_fulfillment_id', 'integer')
258
+
259
+ await tb.execute();
260
+ await create_base_indexes(db, 'orders');
261
+ }
262
+
263
+ { // storefronts
264
+ let tb = create_safe_table(db, 'storefronts');
265
+ tb = add_base_columns(tb);
266
+ tb = tb
267
+ .addColumn('title', 'text')
268
+ .addColumn('video', 'text')
269
+ .addColumn('published', 'text')
270
+ await tb.execute();
271
+ await create_base_indexes(db, 'storefronts');
272
+ }
273
+
274
+ { // storefronts_to_other
275
+ let tb = create_entity_to_value_table(db, 'storefronts_to_other').execute();
276
+ await create_entity_table_indexes(db, 'storefronts_to_other');
277
+ }
278
+
279
+ { // notifications
280
+ let tb = create_safe_table(db, 'notifications');
281
+ tb = add_base_columns(tb);
282
+ tb = tb
283
+ .addColumn('message', 'text')
284
+ .addColumn('author', 'text')
285
+ .addColumn('actions', 'json')
286
+ await tb.execute();
287
+ await create_base_indexes(db, 'notifications', true, false);
288
+ }
289
+
290
+ { // images
291
+ let tb = create_safe_table(db, 'images');
292
+ tb = add_base_columns(tb);
293
+ tb = tb
294
+ .addColumn('name', 'text')
295
+ .addColumn('url', 'text')
296
+ await tb.execute();
297
+ await create_base_indexes(db, 'images');
298
+ }
299
+
300
+ { // discounts
301
+ let tb = create_safe_table(db, 'discounts');
302
+ tb = add_base_columns(tb);
303
+ tb = tb
304
+ .addColumn('title', 'text')
305
+ .addColumn('published', 'text')
306
+ .addColumn('priority', 'integer')
307
+ .addColumn('info', 'json')
308
+ .addColumn('application', 'json')
309
+ .addColumn('_application_id', 'integer')
310
+ .addColumn('_discount_type_id', 'integer')
311
+ await tb.execute();
312
+ await create_base_indexes(db, 'discounts');
313
+ }
314
+
315
+ { // entity_to_tags_projections
316
+ let tb = create_entity_to_value_table(db, 'entity_to_tags_projections').execute();
317
+ await create_entity_table_indexes(db, 'entity_to_tags_projections');
318
+ }
319
+
320
+ { // entity_to_search_terms
321
+ let tb = create_entity_to_value_table(db, 'entity_to_search_terms').execute();
322
+ await create_entity_table_indexes(db, 'entity_to_search_terms');
323
+ }
324
+
325
+ { // entity_to_media
326
+ let tb = create_entity_to_value_table(db, 'entity_to_media').execute();
327
+ await create_entity_table_indexes(db, 'entity_to_media');
328
+ }
329
+
330
+ }
331
+
332
+ /**
333
+ *
334
+ * @param {Kysely<Database>} db
335
+ */
336
+ export async function down(db) {
337
+ await Promise.all([
338
+ drop_safe_table(db, 'auth_users'),
339
+ drop_safe_table(db, 'tags'),
340
+ drop_safe_table(db, 'collections'),
341
+ drop_safe_table(db, 'customers'),
342
+ drop_safe_table(db, 'discounts'),
343
+ drop_safe_table(db, 'images'),
344
+ drop_safe_table(db, 'notifications'),
345
+ drop_safe_table(db, 'orders'),
346
+ drop_safe_table(db, 'posts'),
347
+ drop_safe_table(db, 'shipping_methods'),
348
+ drop_safe_table(db, 'products'),
349
+ drop_safe_table(db, 'products_to_collections'),
350
+ drop_safe_table(db, 'products_to_discounts'),
351
+ drop_safe_table(db, 'products_to_variants'),
352
+ drop_safe_table(db, 'storefronts'),
353
+ drop_safe_table(db, 'storefronts_to_other'),
354
+ drop_safe_table(db, 'entity_to_media'),
355
+ drop_safe_table(db, 'entity_to_search_terms'),
356
+ drop_safe_table(db, 'entity_to_tags_projections'),
357
+ ]);
358
+ }
@@ -0,0 +1 @@
1
+ export * from '../migrations.shared/00001_seed_email_templates.js'