@storecraft/database-sql-base 1.0.17 → 1.0.19

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.
@@ -16,7 +16,17 @@ import {
16
16
  */
17
17
 
18
18
  /**
19
- * @description Official Storecraft Cloudflare D1 adapter on Worker
19
+ * @description A special dialect that aggregates / records queries.
20
+ * This is useful for
21
+ * - testing / debugging
22
+ * - generating migration files for cloud based databases
23
+ * such as `libsql` / `turso` / `d1`
24
+ *
25
+ * NOTE:
26
+ * - This dialect does not support transactions
27
+ * - This is only useful for non-interactive queries, which are
28
+ * basically transactions, that do not depend on results of previous queries.
29
+ * Which is the philosophy of `storecraft` and is quite common in migrations.
20
30
  *
21
31
  * @implements {Dialect}
22
32
  */
package/migrate.js CHANGED
@@ -46,17 +46,17 @@ export const get_migrations = async (dialect_type='SQLITE') => {
46
46
  return migrations;
47
47
  }
48
48
 
49
- console.log(
50
- await get_migrations()
51
- )
49
+ // console.log(
50
+ // await get_migrations()
51
+ // )
52
52
 
53
53
 
54
54
  /**
55
55
  *
56
56
  * @param {SQL} db_driver
57
- * @param {boolean} [destroy_db_upon_completion=true]
57
+ * @param {boolean} [release_db_upon_completion=true]
58
58
  */
59
- export async function migrateToLatest(db_driver, destroy_db_upon_completion=true) {
59
+ export async function migrateToLatest(db_driver, release_db_upon_completion=true) {
60
60
  if(!db_driver?.client)
61
61
  throw new Error('No Kysely client found !!!');
62
62
 
@@ -104,6 +104,41 @@ export async function migrateToLatest(db_driver, destroy_db_upon_completion=true
104
104
  process.exit(1)
105
105
  }
106
106
 
107
- if(destroy_db_upon_completion)
107
+ if(release_db_upon_completion)
108
108
  await db.destroy();
109
109
  }
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
+
@@ -1,8 +1,7 @@
1
- import { CreateTableBuilder, Kysely } from 'kysely'
2
-
3
1
  /**
4
- * @typedef {import('../types.sql.tables.js').Database} Database
2
+ * @import { Database } from '../types.sql.tables.js'
5
3
  */
4
+ import { CreateTableBuilder, Kysely } from 'kysely'
6
5
 
7
6
  /**
8
7
  * @template {string} TB
@@ -0,0 +1 @@
1
+ export * from '../migrations.shared/00004_update_previous_templates_with_subject.js'
@@ -1,8 +1,7 @@
1
- import { CreateTableBuilder, Kysely } from 'kysely'
2
-
3
1
  /**
4
- * @typedef {import('../types.sql.tables.js').Database} Database
2
+ * @import { Database } from '../types.sql.tables.js'
5
3
  */
4
+ import { CreateTableBuilder, Kysely } from 'kysely'
6
5
 
7
6
  /**
8
7
  * @template {string} TB
@@ -0,0 +1 @@
1
+ export * from '../migrations.shared/00004_update_previous_templates_with_subject.js'
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { Kysely } from 'kysely'
5
5
  import { upsert } from '../src/con.templates.js'
6
- import { templates } from '@storecraft/core/assets/seed-templates.js';
6
+ import { templates } from '@storecraft/core/assets/seed-templates-v1.js';
7
7
 
8
8
 
9
9
  /**
@@ -12,6 +12,33 @@ import { templates } from '@storecraft/core/assets/seed-templates.js';
12
12
  */
13
13
  export async function up(db) {
14
14
 
15
+ //
16
+ // NOTE: seeding templates this way might be problematic. Basically,
17
+ // seeds should not be in the migration folder. But, because we have
18
+ // direct access to the database, we can seed the templates directly.
19
+ // But this may result with problems, because right now we use the
20
+ // an `api` layer to seed the templates, which always assumes that we
21
+ // have the latest schema. So, if we change the schema, we need to change
22
+ // the seed templates as well. This is not a problem for now, but it may be.
23
+ // So, we need to be careful with this. If any issue arises, please just
24
+ // use kysely directly to seed the tempaltes according to the schema at
25
+ // that time.
26
+ //
27
+ // Example:
28
+ // - later on, we add a new column to the template table.
29
+ // - The `upsert` function always assumes that the schema is up to date.
30
+ // - So, if the upsert method assigns a value like a default value to the new column,
31
+ // it will fail, because the column does not exist yet.
32
+ // - So, the solution for that, is to write our version of the upsert here.
33
+ //
34
+ // NOTE 2:
35
+ // - It is always better to seperate the seed data from the migration files.
36
+ // - seeding always assumes that the schema is up to date.
37
+ // - It is more hustle for users to run seeds, which might evolve.
38
+ // - I can afford to run seeds in migration files, because i have direct access to the database,
39
+ // as oppposed to ORM users etc.
40
+ //
41
+ //
15
42
  for (const template of templates.slice(0)) {
16
43
  const result = await upsert(db)(template, template.search);
17
44
  if(!result)
@@ -1,17 +1,42 @@
1
+ /**
2
+ * @import { Database } from '../types.sql.tables.js'
3
+ */
1
4
  import { Kysely } from 'kysely'
2
5
  import { upsert } from '../src/con.templates.js'
3
6
  import { templates } from '@storecraft/core/assets/seed-templates-v2.js';
4
7
 
5
- /**
6
- * @typedef {import('../types.sql.tables.js').Database} Database
7
- */
8
-
9
8
  /**
10
9
  *
11
10
  * @param {Kysely<Database>} db
12
11
  */
13
12
  export async function up(db) {
14
-
13
+ //
14
+ // NOTE: seeding templates this way might be problematic. Basically,
15
+ // seeds should not be in the migration folder. But, because we have
16
+ // direct access to the database, we can seed the templates directly.
17
+ // But this may result with problems, because right now we use the
18
+ // an `api` layer to seed the templates, which always assumes that we
19
+ // have the latest schema. So, if we change the schema, we need to change
20
+ // the seed templates as well. This is not a problem for now, but it may be.
21
+ // So, we need to be careful with this. If any issue arises, please just
22
+ // use kysely directly to seed the tempaltes according to the schema at
23
+ // that time.
24
+ //
25
+ // Example:
26
+ // - later on, we add a new column to the template table.
27
+ // - The `upsert` function always assumes that the schema is up to date.
28
+ // - So, if the upsert method assigns a value like a default value to the new column,
29
+ // it will fail, because the column does not exist yet.
30
+ // - So, the solution for that, is to write our version of the upsert here.
31
+ //
32
+ // NOTE 2:
33
+ // - It is always better to seperate the seed data from the migration files.
34
+ // - seeding always assumes that the schema is up to date.
35
+ // - It is more hustle for users to run seeds, which might evolve.
36
+ // - I can afford to run seeds in migration files, because i have direct access to the database,
37
+ // as oppposed to ORM users etc.
38
+ //
39
+ //
15
40
  for (const template of templates.slice(0)) {
16
41
  const result = await upsert(db)(template, template.search);
17
42
  if(!result)
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @import { Database } from '../types.sql.tables.js'
3
+ */
4
+ import { Kysely } from 'kysely'
5
+ import {
6
+ templates as templates_corrections
7
+ } from '@storecraft/core/assets/seed-templates-v3-update-previous-templates-with-subject.js';
8
+
9
+ /**
10
+ * update templates with subject template
11
+ * @param {Kysely<Database>} db
12
+ */
13
+ export async function up(db) {
14
+ await db.schema
15
+ .alterTable('templates')
16
+ .addColumn('template_subject', 'text')
17
+ .execute();
18
+
19
+ for (const template of templates_corrections) {
20
+ await db
21
+ .updateTable('templates')
22
+ .set({
23
+ template_subject: template.template_subject,
24
+ })
25
+ .where('id', '=', template.id)
26
+ .executeTakeFirst();
27
+ }
28
+ }
29
+
30
+ /**
31
+ *
32
+ * @param {Kysely<Database>} db
33
+ */
34
+ export async function down(db) {
35
+ await db.schema
36
+ .alterTable('templates')
37
+ .dropColumn('template_subject')
38
+ .execute();
39
+ }
@@ -1,8 +1,7 @@
1
- import { CreateTableBuilder, Kysely } from 'kysely'
2
-
3
1
  /**
4
- * @typedef {import('../types.sql.tables.js').Database} Database
2
+ * @import { Database } from '../types.sql.tables.js'
5
3
  */
4
+ import { CreateTableBuilder, Kysely } from 'kysely'
6
5
 
7
6
  /**
8
7
  * @template {string} TB
@@ -0,0 +1 @@
1
+ export * from '../migrations.shared/00004_update_previous_templates_with_subject.js'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storecraft/database-sql-base",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "description": "Official SQL Database driver for storecraft",
5
5
  "license": "MIT",
6
6
  "author": "Tomer Shalev (https://github.com/store-craft)",
@@ -19,7 +19,7 @@ export const table_name = 'templates'
19
19
  * @param {string} val
20
20
  */
21
21
  const encode_base64_if_needed = val => {
22
- if(val.startsWith('base64_'))
22
+ if(val?.startsWith('base64_'))
23
23
  return val;
24
24
 
25
25
  return 'base64_' + base64.encode(val);
@@ -31,7 +31,7 @@ const encode_base64_if_needed = val => {
31
31
  * @param {string} val
32
32
  */
33
33
  const decode_base64_if_needed = val => {
34
- if(!val.startsWith('base64_'))
34
+ if(!val?.startsWith('base64_'))
35
35
  return val;
36
36
 
37
37
  return base64.decode(val.split('base64_').at(-1) ?? '');
@@ -39,7 +39,6 @@ const decode_base64_if_needed = val => {
39
39
 
40
40
  /**
41
41
  * @param {Kysely<Database>} client
42
- *
43
42
  * @returns {db_col["upsert"]}
44
43
  */
45
44
  export const upsert = (client) => {
@@ -56,8 +55,9 @@ export const upsert = (client) => {
56
55
  active: item.active ? 1 : 0,
57
56
  title: item.title,
58
57
  handle: item.handle,
59
- template_html: encode_base64_if_needed(item.template_html),
60
- template_text: encode_base64_if_needed(item.template_text),
58
+ template_html: item.template_html && encode_base64_if_needed(item.template_html),
59
+ template_text: item.template_text && encode_base64_if_needed(item.template_text),
60
+ template_subject: item.template_subject && encode_base64_if_needed(item.template_subject),
61
61
  reference_example_input: JSON.stringify(item.reference_example_input ?? {})
62
62
  });
63
63
  }
@@ -74,11 +74,9 @@ export const upsert = (client) => {
74
74
 
75
75
  /**
76
76
  * @param {SQL} driver
77
- *
78
- *
79
77
  * @returns {db_col["get"]}
80
78
  */
81
- const get = (driver) => {
79
+ export const get = (driver) => {
82
80
  return (id_or_handle, options) => {
83
81
  return driver.client
84
82
  .selectFrom(table_name)
@@ -96,6 +94,7 @@ const get = (driver) => {
96
94
 
97
95
  item.template_html = decode_base64_if_needed(item.template_html);
98
96
  item.template_text = decode_base64_if_needed(item.template_text);
97
+ item.template_subject = decode_base64_if_needed(item.template_subject);
99
98
 
100
99
  return item;
101
100
  }
@@ -106,8 +105,6 @@ const get = (driver) => {
106
105
 
107
106
  /**
108
107
  * @param {SQL} driver
109
- *
110
- *
111
108
  * @returns {db_col["remove"]}
112
109
  */
113
110
  const remove = (driver) => {
@@ -162,6 +159,7 @@ const list = (driver) => {
162
159
  (item) => {
163
160
  item.template_html = decode_base64_if_needed(item.template_html);
164
161
  item.template_text = decode_base64_if_needed(item.template_text);
162
+ item.template_subject = decode_base64_if_needed(item.template_subject);
165
163
  return item;
166
164
  }
167
165
  )
@@ -10,7 +10,7 @@ import { homedir } from 'node:os';
10
10
  import { join } from 'node:path';
11
11
 
12
12
  export const sqlite_dialect = new SqliteDialect({
13
- database: async () => new SQLite(join(homedir(), 'db.sqlite')),
13
+ database: async () => new SQLite(':memory:'),
14
14
  });
15
15
 
16
16
  export const create_app = async () => {
@@ -190,6 +190,7 @@ export interface CollectionsTable extends Base {
190
190
  }
191
191
 
192
192
  export interface TemplatesTable extends Base {
193
+ template_subject?: string;
193
194
  template_html?: string;
194
195
  template_text?: string;
195
196
  reference_example_input?: JSONColumnType<object>;
@@ -1,38 +0,0 @@
1
- import 'dotenv/config';
2
- import { App } from '@storecraft/core';
3
- import { SQL } from '@storecraft/database-sql-base';
4
- import { migrateToLatest } from '@storecraft/database-sql-base/migrate.js';
5
- import { NodePlatform } from '@storecraft/core/platform/node';
6
- import { api } from '@storecraft/core/test-runner'
7
- import SQLite from 'better-sqlite3'
8
- import { SqliteDialect } from 'kysely';
9
- import { homedir } from 'node:os';
10
- import { join } from 'node:path';
11
- import { up } from '../migrations.sqlite/00000_init_tables.js'
12
- import { AggregateDialect } from '../kysely.aggregate.dialect.js'
13
-
14
- export const sqlite_dialect = new SqliteDialect(
15
- {
16
- database: async () => new SQLite(join(homedir(), 'db.sqlite')),
17
- }
18
- );
19
-
20
- export const test = async () => {
21
- const aggregate_dialect = new AggregateDialect(
22
- {
23
- dialect: sqlite_dialect,
24
- }
25
- );
26
-
27
- const db = new SQL({
28
- dialect: aggregate_dialect,
29
- dialect_type: 'SQLITE'
30
- });
31
-
32
- await up(db.client);
33
-
34
- const queries = aggregate_dialect.queries;
35
- console.log({queries})
36
-
37
- }
38
- test();