@enbox/dwn-sql-store 0.0.1

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 (75) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +178 -0
  3. package/dist/cjs/main.js +3784 -0
  4. package/dist/cjs/package.json +1 -0
  5. package/dist/esm/src/data-store-sql.js +103 -0
  6. package/dist/esm/src/data-store-sql.js.map +1 -0
  7. package/dist/esm/src/dialect/dialect.js +2 -0
  8. package/dist/esm/src/dialect/dialect.js.map +1 -0
  9. package/dist/esm/src/dialect/mysql-dialect.js +40 -0
  10. package/dist/esm/src/dialect/mysql-dialect.js.map +1 -0
  11. package/dist/esm/src/dialect/postgres-dialect.js +26 -0
  12. package/dist/esm/src/dialect/postgres-dialect.js.map +1 -0
  13. package/dist/esm/src/dialect/sqlite-dialect.js +33 -0
  14. package/dist/esm/src/dialect/sqlite-dialect.js.map +1 -0
  15. package/dist/esm/src/event-log-sql.js +169 -0
  16. package/dist/esm/src/event-log-sql.js.map +1 -0
  17. package/dist/esm/src/main.js +9 -0
  18. package/dist/esm/src/main.js.map +1 -0
  19. package/dist/esm/src/message-store-sql.js +317 -0
  20. package/dist/esm/src/message-store-sql.js.map +1 -0
  21. package/dist/esm/src/resumable-task-store-sql.js +141 -0
  22. package/dist/esm/src/resumable-task-store-sql.js.map +1 -0
  23. package/dist/esm/src/types.js +2 -0
  24. package/dist/esm/src/types.js.map +1 -0
  25. package/dist/esm/src/utils/filter.js +125 -0
  26. package/dist/esm/src/utils/filter.js.map +1 -0
  27. package/dist/esm/src/utils/sanitize.js +92 -0
  28. package/dist/esm/src/utils/sanitize.js.map +1 -0
  29. package/dist/esm/src/utils/tags.js +38 -0
  30. package/dist/esm/src/utils/tags.js.map +1 -0
  31. package/dist/esm/src/utils/transaction.js +25 -0
  32. package/dist/esm/src/utils/transaction.js.map +1 -0
  33. package/dist/types/src/data-store-sql.d.ts +14 -0
  34. package/dist/types/src/data-store-sql.d.ts.map +1 -0
  35. package/dist/types/src/dialect/dialect.d.ts +40 -0
  36. package/dist/types/src/dialect/dialect.d.ts.map +1 -0
  37. package/dist/types/src/dialect/mysql-dialect.d.ts +18 -0
  38. package/dist/types/src/dialect/mysql-dialect.d.ts.map +1 -0
  39. package/dist/types/src/dialect/postgres-dialect.d.ts +12 -0
  40. package/dist/types/src/dialect/postgres-dialect.d.ts.map +1 -0
  41. package/dist/types/src/dialect/sqlite-dialect.d.ts +12 -0
  42. package/dist/types/src/dialect/sqlite-dialect.d.ts.map +1 -0
  43. package/dist/types/src/event-log-sql.d.ts +24 -0
  44. package/dist/types/src/event-log-sql.d.ts.map +1 -0
  45. package/dist/types/src/main.d.ts +9 -0
  46. package/dist/types/src/main.d.ts.map +1 -0
  47. package/dist/types/src/message-store-sql.d.ts +46 -0
  48. package/dist/types/src/message-store-sql.d.ts.map +1 -0
  49. package/dist/types/src/resumable-task-store-sql.d.ts +16 -0
  50. package/dist/types/src/resumable-task-store-sql.d.ts.map +1 -0
  51. package/dist/types/src/types.d.ts +100 -0
  52. package/dist/types/src/types.d.ts.map +1 -0
  53. package/dist/types/src/utils/filter.d.ts +13 -0
  54. package/dist/types/src/utils/filter.d.ts.map +1 -0
  55. package/dist/types/src/utils/sanitize.d.ts +28 -0
  56. package/dist/types/src/utils/sanitize.d.ts.map +1 -0
  57. package/dist/types/src/utils/tags.d.ts +20 -0
  58. package/dist/types/src/utils/tags.d.ts.map +1 -0
  59. package/dist/types/src/utils/transaction.d.ts +7 -0
  60. package/dist/types/src/utils/transaction.d.ts.map +1 -0
  61. package/package.json +91 -0
  62. package/src/data-store-sql.ts +148 -0
  63. package/src/dialect/dialect.ts +77 -0
  64. package/src/dialect/mysql-dialect.ts +86 -0
  65. package/src/dialect/postgres-dialect.ts +66 -0
  66. package/src/dialect/sqlite-dialect.ts +72 -0
  67. package/src/event-log-sql.ts +227 -0
  68. package/src/main.ts +8 -0
  69. package/src/message-store-sql.ts +440 -0
  70. package/src/resumable-task-store-sql.ts +174 -0
  71. package/src/types.ts +109 -0
  72. package/src/utils/filter.ts +136 -0
  73. package/src/utils/sanitize.ts +117 -0
  74. package/src/utils/tags.ts +46 -0
  75. package/src/utils/transaction.ts +28 -0
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "@enbox/dwn-sql-store",
3
+ "version": "0.0.1",
4
+ "description": "SQL backed implementations of DWN MessageStore, DataStore, and EventLog",
5
+ "type": "module",
6
+ "license": "Apache-2.0",
7
+ "homepage": "https://github.com/enboxorg/enbox/tree/main/packages/dwn-sql-store#readme",
8
+ "bugs": "https://github.com/enboxorg/enbox/issues",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/enboxorg/enbox.git",
12
+ "directory": "packages/dwn-sql-store"
13
+ },
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "main": "./dist/cjs/main.js",
18
+ "module": "./dist/esm/src/main.js",
19
+ "types": "./dist/types/src/main.d.ts",
20
+ "exports": {
21
+ "import": "./dist/esm/src/main.js",
22
+ "require": "./dist/cjs/main.js",
23
+ "types": "./dist/types/src/main.d.ts"
24
+ },
25
+ "react-native": "./dist/esm/src/main.js",
26
+ "dependencies": {
27
+ "@enbox/dwn-sdk-js": "workspace:*",
28
+ "@ipld/dag-cbor": "9.0.5",
29
+ "kysely": "0.26.3",
30
+ "multiformats": "12.0.1",
31
+ "readable-stream": "4.4.2"
32
+ },
33
+ "devDependencies": {
34
+ "@types/better-sqlite3": "7.6.4",
35
+ "@types/chai": "4.3.4",
36
+ "@types/chai-as-promised": "7.1.5",
37
+ "@types/express": "4.17.17",
38
+ "@types/mocha": "10.0.1",
39
+ "@types/node": "20.3.1",
40
+ "@types/pg": "8.10.2",
41
+ "@types/pg-cursor": "2.7.0",
42
+ "@types/readable-stream": "4.0.6",
43
+ "@types/supertest": "2.0.12",
44
+ "@typescript-eslint/eslint-plugin": "5.59.11",
45
+ "@typescript-eslint/parser": "5.59.11",
46
+ "better-sqlite3": "8.4.0",
47
+ "c8": "8.0.0",
48
+ "chai": "4.3.6",
49
+ "chai-as-promised": "7.1.1",
50
+ "esbuild": "^0.19.3",
51
+ "eslint": "8.42.0",
52
+ "mocha": "10.2.0",
53
+ "mysql2": "3.9.8",
54
+ "pg": "8.11.1",
55
+ "pg-cursor": "2.10.1",
56
+ "rimraf": "5.0.1",
57
+ "sinon": "^18.0.1",
58
+ "typescript": "5.0.4"
59
+ },
60
+ "scripts": {
61
+ "build:esm": "pnpm clean & tsc",
62
+ "build:cjs": "pnpm build:esm && node build/create-cjs-bundle.cjs && echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json",
63
+ "build": "pnpm clean && pnpm build:esm && pnpm build:cjs",
64
+ "clean": "rimraf dist compiled",
65
+ "lint": "eslint . --ext .ts --max-warnings 0",
66
+ "lint:fix": "eslint . --ext .ts --fix",
67
+ "test": "rimraf compiled && tsc -p tests/tsconfig.json && mocha",
68
+ "test-coverage": "rimraf compiled && tsc -p tests/tsconfig.json && c8 mocha"
69
+ },
70
+ "files": [
71
+ "dist",
72
+ "src"
73
+ ],
74
+ "engines": {
75
+ "node": ">=18"
76
+ },
77
+ "contributors": [
78
+ {
79
+ "name": "Adam Mika",
80
+ "url": "https://github.com/amika-sq"
81
+ },
82
+ {
83
+ "name": "Moe Jangda",
84
+ "url": "https://github.com/mistermoe"
85
+ },
86
+ {
87
+ "name": "Liran Cohen",
88
+ "url": "https://github.com/lirancohen"
89
+ }
90
+ ]
91
+ }
@@ -0,0 +1,148 @@
1
+ import { DataStore, DataStream, DataStoreGetResult, DataStorePutResult } from '@enbox/dwn-sdk-js';
2
+ import { Kysely } from 'kysely';
3
+ import { Readable } from 'readable-stream';
4
+ import { DwnDatabaseType } from './types.js';
5
+ import { Dialect } from './dialect/dialect.js';
6
+
7
+ export class DataStoreSql implements DataStore {
8
+ #dialect: Dialect;
9
+ #db: Kysely<DwnDatabaseType> | null = null;
10
+
11
+ constructor(dialect: Dialect) {
12
+ this.#dialect = dialect;
13
+ }
14
+
15
+ async open(): Promise<void> {
16
+ if (this.#db) {
17
+ return;
18
+ }
19
+
20
+ this.#db = new Kysely<DwnDatabaseType>({ dialect: this.#dialect });
21
+
22
+ // if table already exists, there is no more things todo
23
+ const tableName = 'dataStore';
24
+ const tableExists = await this.#dialect.hasTable(this.#db, tableName);
25
+ if (tableExists) {
26
+ return;
27
+ }
28
+
29
+ // else create the table and corresponding indexes
30
+
31
+ let table = this.#db.schema
32
+ .createTable(tableName)
33
+ .ifNotExists()// kept to show supported by all dialects in contrast to ifNotExists() below, though not needed due to hasTable() check above
34
+ .addColumn('tenant', 'varchar(255)', (col) => col.notNull())
35
+ .addColumn('recordId', 'varchar(60)', (col) => col.notNull())
36
+ .addColumn('dataCid', 'varchar(60)', (col) => col.notNull());
37
+
38
+ // Add columns that have dialect-specific constraints
39
+ table = this.#dialect.addAutoIncrementingColumn(table, 'id', (col) => col.primaryKey());
40
+ table = this.#dialect.addBlobColumn(table, 'data', (col) => col.notNull());
41
+ await table.execute();
42
+
43
+ // Add index for efficient lookups.
44
+ await this.#db.schema
45
+ .createIndex('tenant_recordId_dataCid')
46
+ // .ifNotExists() // intentionally kept commented out code to show that it is not supported by all dialects (ie. MySQL)
47
+ .on(tableName)
48
+ .columns(['tenant', 'recordId', 'dataCid'])
49
+ .unique()
50
+ .execute();
51
+ }
52
+
53
+ async close(): Promise<void> {
54
+ await this.#db?.destroy();
55
+ this.#db = null;
56
+ }
57
+
58
+ async get(
59
+ tenant: string,
60
+ recordId: string,
61
+ dataCid: string
62
+ ): Promise<DataStoreGetResult | undefined> {
63
+ if (!this.#db) {
64
+ throw new Error(
65
+ 'Connection to database not open. Call `open` before using `get`.'
66
+ );
67
+ }
68
+
69
+ const result = await this.#db
70
+ .selectFrom('dataStore')
71
+ .selectAll()
72
+ .where('tenant', '=', tenant)
73
+ .where('recordId', '=', recordId)
74
+ .where('dataCid', '=', dataCid)
75
+ .executeTakeFirst();
76
+
77
+ if (!result) {
78
+ return undefined;
79
+ }
80
+
81
+ return {
82
+ dataSize : result.data.length,
83
+ dataStream : new Readable({
84
+ read() {
85
+ this.push(Buffer.from(result.data));
86
+ this.push(null);
87
+ }
88
+ }),
89
+ };
90
+ }
91
+
92
+ async put(
93
+ tenant: string,
94
+ recordId: string,
95
+ dataCid: string,
96
+ dataStream: Readable
97
+ ): Promise<DataStorePutResult> {
98
+ if (!this.#db) {
99
+ throw new Error(
100
+ 'Connection to database not open. Call `open` before using `put`.'
101
+ );
102
+ }
103
+
104
+ const bytes = await DataStream.toBytes(dataStream);
105
+ const data = Buffer.from(bytes);
106
+
107
+ await this.#db
108
+ .insertInto('dataStore')
109
+ .values({ tenant, recordId, dataCid, data })
110
+ .executeTakeFirstOrThrow();
111
+
112
+ return {
113
+ dataSize: bytes.length
114
+ };
115
+ }
116
+
117
+ async delete(
118
+ tenant: string,
119
+ recordId: string,
120
+ dataCid: string
121
+ ): Promise<void> {
122
+ if (!this.#db) {
123
+ throw new Error(
124
+ 'Connection to database not open. Call `open` before using `delete`.'
125
+ );
126
+ }
127
+
128
+ await this.#db
129
+ .deleteFrom('dataStore')
130
+ .where('tenant', '=', tenant)
131
+ .where('recordId', '=', recordId)
132
+ .where('dataCid', '=', dataCid)
133
+ .execute();
134
+ }
135
+
136
+ async clear(): Promise<void> {
137
+ if (!this.#db) {
138
+ throw new Error(
139
+ 'Connection to database not open. Call `open` before using `clear`.'
140
+ );
141
+ }
142
+
143
+ await this.#db
144
+ .deleteFrom('dataStore')
145
+ .execute();
146
+ }
147
+
148
+ }
@@ -0,0 +1,77 @@
1
+ import {
2
+ ColumnBuilderCallback,
3
+ ColumnDataType,
4
+ CreateTableBuilder,
5
+ Dialect as KyselyDialect,
6
+ Kysely,
7
+ InsertObject,
8
+ InsertQueryBuilder,
9
+ Selection,
10
+ SelectExpression,
11
+ Transaction,
12
+ } from 'kysely';
13
+
14
+ export interface Dialect extends KyselyDialect {
15
+ readonly name: string;
16
+ readonly isStreamingSupported: boolean;
17
+
18
+ hasTable(db: Kysely<any>, tableName: string): Promise<boolean>;
19
+
20
+ addAutoIncrementingColumn<TB extends string>(
21
+ builder: CreateTableBuilder<TB>,
22
+ columnName: string,
23
+ callback?: ColumnBuilderCallback
24
+ ): CreateTableBuilder<TB>;
25
+
26
+ addBlobColumn<TB extends string>(
27
+ builder: CreateTableBuilder<TB>,
28
+ columnName: string,
29
+ callback?: ColumnBuilderCallback
30
+ ): CreateTableBuilder<TB>;
31
+
32
+ /**
33
+ * This is a helper method to add a column with foreign key constraints.
34
+ * This is primarily useful because the `mySQL` dialect adds the constraints in a different way than `sqlite` and `postgres`.
35
+ *
36
+ * @param builder the CreateTableBuilder to add the column to.
37
+ * @param tableName the name of the table to add the column to.
38
+ * @param columnName the name of the column to add.
39
+ * @param columnType the type of the column to add.
40
+ * @param referenceTable the foreign table to reference.
41
+ * @param referenceColumnName the foreign column to reference.
42
+ * @param onDeleteAction the action to take when the referenced row is deleted.
43
+ *
44
+ * @returns {CreateTableBuilder} the CreateTableBuilder with the added column.
45
+ */
46
+ addReferencedColumn<TB extends string>(
47
+ builder: CreateTableBuilder<TB & string>,
48
+ tableName: TB,
49
+ columnName: string,
50
+ columnType: ColumnDataType,
51
+ referenceTable: string,
52
+ referenceColumnName: string,
53
+ onDeleteAction: 'cascade' | 'no action' | 'restrict' | 'set null' | 'set default',
54
+ ): CreateTableBuilder<TB & string>;
55
+
56
+ /**
57
+ * This is a helper method to return an `insertId` across all dialects after inserting values.
58
+ * `postgres` and `sqlite` both support the `returning` clause, however `mysql` does not and instead returns the last inserted id.
59
+ *
60
+ * @param db the Kysely DB object or a DB Transaction.
61
+ * @param table the table to insert into.
62
+ * @param values the values to insert.
63
+ * @param returning a string representing the generated key you'd like returned as an insertId.
64
+ *
65
+ * NOTE: the `returning` value must be formatted to return an insertId value.
66
+ * ex. if the generated key is `id` the string should be `id as insertId`.
67
+ * if the generated key is `watermark` the string should be `watermark as insertId`.
68
+ *
69
+ * @returns {InsertQueryBuilder} object to further modify the query or execute it.
70
+ */
71
+ insertThenReturnId<DB, TB extends keyof DB = keyof DB, SE extends SelectExpression<DB, TB & string> = any>(
72
+ db: Transaction<DB> | Kysely<DB>,
73
+ table: TB & string,
74
+ values: InsertObject<DB, TB & string>,
75
+ returning: SE & `${string} as insertId`,
76
+ ): InsertQueryBuilder<DB, TB & string, Selection<DB, TB & string, SE & `${string} as insertId`>>;
77
+ }
@@ -0,0 +1,86 @@
1
+ import { Dialect } from './dialect.js';
2
+ import {
3
+ AnyColumn,
4
+ ColumnDataType,
5
+ CreateTableBuilder,
6
+ ColumnBuilderCallback,
7
+ InsertObject,
8
+ InsertQueryBuilder,
9
+ SelectExpression,
10
+ Selection,
11
+ Transaction,
12
+ MysqlDialect as KyselyMysqlDialect,
13
+ Kysely,
14
+ } from 'kysely';
15
+
16
+ export class MysqlDialect extends KyselyMysqlDialect implements Dialect {
17
+ name = 'MySQL';
18
+ isStreamingSupported = true;
19
+
20
+ async hasTable(db: Kysely<any>, tableName: string): Promise<boolean> {
21
+ const result = await db
22
+ .selectFrom('information_schema.tables')
23
+ .select('table_name')
24
+ .where('table_name', '=', tableName)
25
+ .execute();
26
+
27
+ return result.length > 0;
28
+ }
29
+
30
+ addAutoIncrementingColumn<TB extends string>(
31
+ builder: CreateTableBuilder<TB>,
32
+ columnName: string,
33
+ callback?: ColumnBuilderCallback
34
+ ): CreateTableBuilder<TB> {
35
+ return builder.addColumn(columnName, 'integer', (col) => {
36
+ col = col.autoIncrement();
37
+ if (callback) {
38
+ col = callback(col);
39
+ }
40
+ return col;
41
+ });
42
+ }
43
+
44
+ addBlobColumn<TB extends string>(
45
+ builder: CreateTableBuilder<TB>,
46
+ columnName: string,
47
+ callback?: ColumnBuilderCallback
48
+ ): CreateTableBuilder<TB> {
49
+ return builder.addColumn(columnName, 'blob', callback);
50
+ }
51
+
52
+ /**
53
+ * In MySQL, the ForeignKey name it creates in `mysql` will be in the following format:
54
+ * `${referenceTable}_${referenceColumnName}__${tableName}_${columnName}`
55
+ * ex: if the reference table is `users` and the reference column is `id` and the table is `profiles` and the column is `userId`,
56
+ * the resulting name for the foreign key is: `users_id__profiles_userId`
57
+ */
58
+ addReferencedColumn<TB extends string>(
59
+ builder: CreateTableBuilder<TB & string>,
60
+ tableName: TB,
61
+ columnName: string,
62
+ columnType: ColumnDataType,
63
+ referenceTable: string,
64
+ referenceColumnName: string,
65
+ onDeleteAction: 'cascade' | 'no action' | 'restrict' | 'set null' | 'set default',
66
+ ): CreateTableBuilder<TB & string> {
67
+ return builder
68
+ .addColumn(columnName, columnType, (col) => col.notNull())
69
+ .addForeignKeyConstraint(
70
+ `${referenceTable}_${referenceColumnName}__${tableName}_${columnName}`,
71
+ [columnName],
72
+ referenceTable,
73
+ [referenceColumnName],
74
+ (constraint) => constraint.onDelete(onDeleteAction)
75
+ );
76
+ }
77
+
78
+ insertThenReturnId<DB, TB extends keyof DB = keyof DB, SE extends SelectExpression<DB, TB & string> = AnyColumn<DB, TB>>(
79
+ db: Transaction<DB> | Kysely<DB>,
80
+ table: TB & string,
81
+ values: InsertObject<DB, TB & string>,
82
+ _returning: SE & `${string} as insertId`,
83
+ ): InsertQueryBuilder<DB, TB & string, Selection<DB, TB & string, SE & `${string} as insertId`>> {
84
+ return db.insertInto(table).values(values);
85
+ }
86
+ }
@@ -0,0 +1,66 @@
1
+ import { Dialect } from './dialect.js';
2
+ import {
3
+ ColumnDataType,
4
+ ColumnBuilderCallback,
5
+ CreateTableBuilder,
6
+ InsertObject,
7
+ InsertQueryBuilder,
8
+ Kysely,
9
+ PostgresDialect as KyselyPostgresDialect,
10
+ SelectExpression,
11
+ Selection,
12
+ Transaction,
13
+ } from 'kysely';
14
+
15
+ export class PostgresDialect extends KyselyPostgresDialect implements Dialect {
16
+ name = 'PostgreSQL';
17
+ isStreamingSupported = true;
18
+
19
+ async hasTable(db: Kysely<any>, tableName: string): Promise<boolean> {
20
+ const result = await db
21
+ .selectFrom('information_schema.tables')
22
+ .select('table_name')
23
+ .where('table_name', '=', tableName)
24
+ .execute();
25
+
26
+ return result.length > 0;
27
+ }
28
+
29
+ addAutoIncrementingColumn<TB extends string>(
30
+ builder: CreateTableBuilder<TB>,
31
+ columnName: string,
32
+ callback?: ColumnBuilderCallback
33
+ ): CreateTableBuilder<TB> {
34
+ return builder.addColumn(columnName, 'serial', callback);
35
+ }
36
+
37
+ addBlobColumn<TB extends string>(
38
+ builder: CreateTableBuilder<TB>,
39
+ columnName: string,
40
+ callback?: ColumnBuilderCallback
41
+ ): CreateTableBuilder<TB> {
42
+ return builder.addColumn(columnName, 'bytea', callback);
43
+ }
44
+
45
+ addReferencedColumn<TB extends string>(
46
+ builder: CreateTableBuilder<TB & string>,
47
+ _tableName: TB,
48
+ columnName: string,
49
+ columnType: ColumnDataType,
50
+ referenceTable: string,
51
+ referenceColumnName: string,
52
+ onDeleteAction: 'cascade' | 'no action' | 'restrict' | 'set null' | 'set default',
53
+ ): CreateTableBuilder<TB & string> {
54
+ return builder.addColumn(columnName, columnType, (col) => col.notNull().references(`${referenceTable}.${referenceColumnName}`).onDelete(onDeleteAction));
55
+ }
56
+
57
+ insertThenReturnId<DB, TB extends keyof DB = keyof DB, SE extends SelectExpression<DB, TB & string> = any>(
58
+ db: Transaction<DB> | Kysely<DB>,
59
+ table: TB & string,
60
+ values: InsertObject<DB, TB & string>,
61
+ returning: SE & `${string} as insertId`,
62
+ ): InsertQueryBuilder<DB, TB & string, Selection<DB, TB & string, SE & `${string} as insertId`>> {
63
+ return db.insertInto(table).values(values).returning(returning);
64
+ }
65
+
66
+ }
@@ -0,0 +1,72 @@
1
+ import { Dialect } from './dialect.js';
2
+ import {
3
+ ColumnBuilderCallback,
4
+ ColumnDataType,
5
+ CreateTableBuilder,
6
+ Kysely,
7
+ InsertObject,
8
+ InsertQueryBuilder,
9
+ SelectExpression,
10
+ Selection,
11
+ SqliteDialect as KyselySqliteDialect,
12
+ Transaction,
13
+ } from 'kysely';
14
+
15
+ export class SqliteDialect extends KyselySqliteDialect implements Dialect {
16
+ name = 'SQLite';
17
+ isStreamingSupported = false;
18
+
19
+ async hasTable(db: Kysely<any>, tableName: string): Promise<boolean> {
20
+ const result = await db
21
+ .selectFrom('sqlite_master')
22
+ .select('name')
23
+ .where('type', '=', 'table')
24
+ .where('name', '=', tableName)
25
+ .execute();
26
+
27
+ return result.length > 0;
28
+ }
29
+
30
+ addAutoIncrementingColumn<TB extends string>(
31
+ builder: CreateTableBuilder<TB>,
32
+ columnName: string,
33
+ callback?: ColumnBuilderCallback
34
+ ): CreateTableBuilder<TB> {
35
+ return builder.addColumn(columnName, 'integer', (col) => {
36
+ col = col.autoIncrement();
37
+ if (callback) {
38
+ col = callback(col);
39
+ }
40
+ return col;
41
+ });
42
+ }
43
+
44
+ addBlobColumn<TB extends string>(
45
+ builder: CreateTableBuilder<TB>,
46
+ columnName: string,
47
+ callback?: ColumnBuilderCallback
48
+ ): CreateTableBuilder<TB> {
49
+ return builder.addColumn(columnName, 'blob', callback);
50
+ }
51
+
52
+ addReferencedColumn<TB extends string>(
53
+ builder: CreateTableBuilder<TB & string>,
54
+ _tableName: TB,
55
+ columnName: string,
56
+ columnType: ColumnDataType,
57
+ referenceTable: string,
58
+ referenceColumnName: string,
59
+ onDeleteAction: 'cascade' | 'no action' | 'restrict' | 'set null' | 'set default',
60
+ ): CreateTableBuilder<TB & string> {
61
+ return builder.addColumn(columnName, columnType, (col) => col.notNull().references(`${referenceTable}.${referenceColumnName}`).onDelete(onDeleteAction));
62
+ }
63
+
64
+ insertThenReturnId<DB, TB extends keyof DB = keyof DB, SE extends SelectExpression<DB, TB & string> = any>(
65
+ db: Transaction<DB> | Kysely<DB>,
66
+ table: TB & string,
67
+ values: InsertObject<DB, TB & string>,
68
+ returning: SE & `${string} as insertId`,
69
+ ): InsertQueryBuilder<DB, TB & string, Selection<DB, TB & string, SE & `${string} as insertId`>> {
70
+ return db.insertInto(table).values(values).returning(returning);
71
+ }
72
+ }