@deterministic-code/datasources-sqlite 0.1.1 → 0.1.3

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 (63) hide show
  1. package/dist/SqliteAlterTableStatementRenderer.d.ts +5 -0
  2. package/dist/SqliteAlterTableStatementRenderer.js +27 -0
  3. package/dist/SqliteCreateTableStatementRenderer.d.ts +1 -1
  4. package/dist/SqliteCreateTableStatementRenderer.js +18 -0
  5. package/dist/SqliteCreateTriggerStatementRenderer.d.ts +4 -0
  6. package/dist/SqliteCreateTriggerStatementRenderer.js +12 -0
  7. package/dist/SqliteDriver.d.ts +5 -1
  8. package/dist/SqliteDriver.js +64 -0
  9. package/dist/SqliteStatementRenderer.d.ts +3 -1
  10. package/dist/SqliteStatementRenderer.js +26 -0
  11. package/dist/columnTypes.js +10 -0
  12. package/dist/command.d.ts +1 -1
  13. package/dist/command.js +163 -0
  14. package/dist/connection-options.js +1 -0
  15. package/dist/connection.d.ts +1 -1
  16. package/dist/connection.js +58 -0
  17. package/dist/converters/BinaryConverter.d.ts +1 -1
  18. package/dist/converters/BinaryConverter.js +5 -0
  19. package/dist/converters/BoolConverter.d.ts +1 -1
  20. package/dist/converters/BoolConverter.js +5 -0
  21. package/dist/converters/DateTimeConverter.d.ts +1 -1
  22. package/dist/converters/DateTimeConverter.js +5 -0
  23. package/dist/converters/DecimalConverter.d.ts +1 -1
  24. package/dist/converters/DecimalConverter.js +5 -0
  25. package/dist/converters/SqliteRowTypeConverters.d.ts +1 -1
  26. package/dist/converters/SqliteRowTypeConverters.js +19 -0
  27. package/dist/converters/UuidConverter.d.ts +1 -1
  28. package/dist/converters/UuidConverter.js +5 -0
  29. package/dist/i-sqlite-driver.d.ts +1 -1
  30. package/dist/i-sqlite-driver.js +1 -0
  31. package/dist/index.d.ts +0 -1
  32. package/dist/index.js +1 -0
  33. package/dist/sqlitePath.js +7 -0
  34. package/dist/transaction.d.ts +1 -1
  35. package/dist/transaction.js +15 -0
  36. package/package.json +9 -10
  37. package/src/SqliteCreateTableStatementRenderer.ts +0 -24
  38. package/src/SqliteDriver.ts +0 -53
  39. package/src/SqliteStatementRenderer.test.ts +0 -60
  40. package/src/SqliteStatementRenderer.ts +0 -28
  41. package/src/columnTypes.ts +0 -10
  42. package/src/command.ts +0 -231
  43. package/src/connection-options.ts +0 -7
  44. package/src/connection.ts +0 -83
  45. package/src/converters/BinaryConverter.test.ts +0 -11
  46. package/src/converters/BinaryConverter.ts +0 -6
  47. package/src/converters/BoolConverter.test.ts +0 -14
  48. package/src/converters/BoolConverter.ts +0 -6
  49. package/src/converters/DateTimeConverter.test.ts +0 -13
  50. package/src/converters/DateTimeConverter.ts +0 -8
  51. package/src/converters/DecimalConverter.test.ts +0 -11
  52. package/src/converters/DecimalConverter.ts +0 -7
  53. package/src/converters/SqliteRowTypeConverters.test.ts +0 -18
  54. package/src/converters/SqliteRowTypeConverters.ts +0 -24
  55. package/src/converters/UuidConverter.test.ts +0 -11
  56. package/src/converters/UuidConverter.ts +0 -6
  57. package/src/createFromDriver.test.ts +0 -15
  58. package/src/expected-repository-console.test.ts +0 -95
  59. package/src/i-sqlite-driver.ts +0 -21
  60. package/src/index.ts +0 -2
  61. package/src/sqlite.test.ts +0 -296
  62. package/src/sqlitePath.ts +0 -8
  63. package/src/transaction.ts +0 -21
@@ -0,0 +1,5 @@
1
+ import { AlterTableStatementTextRenderer, type AlterAction, type Column } from "@deterministic-code/datasources";
2
+ export declare class SqliteAlterTableStatementRenderer extends AlterTableStatementTextRenderer {
3
+ protected typeName(column: Column): string;
4
+ protected actionSql(action: AlterAction): string;
5
+ }
@@ -0,0 +1,27 @@
1
+ import { AlterTableStatementTextRenderer, } from "@deterministic-code/datasources";
2
+ import { columnTypes } from "./columnTypes.js";
3
+ export class SqliteAlterTableStatementRenderer extends AlterTableStatementTextRenderer {
4
+ typeName(column) {
5
+ return columnTypes[column.type] ?? column.type;
6
+ }
7
+ actionSql(action) {
8
+ return ({
9
+ alterColumn: () => {
10
+ throw new Error("SQLite cannot ALTER COLUMN");
11
+ },
12
+ addConstraint: () => {
13
+ throw new Error("SQLite cannot ADD CONSTRAINT");
14
+ },
15
+ dropConstraint: () => {
16
+ throw new Error("SQLite cannot DROP CONSTRAINT");
17
+ },
18
+ addColumn: () => super.actionSql(action),
19
+ dropColumn: () => super.actionSql(action),
20
+ renameColumn: () => super.actionSql(action),
21
+ renameTable: () => super.actionSql(action),
22
+ }[action.kind] ??
23
+ (() => {
24
+ throw new Error("empty alter");
25
+ }))();
26
+ }
27
+ }
@@ -1,4 +1,4 @@
1
- import { CreateTableStatement, CreateTableStatementTextRenderer, type Column } from "@datasources/core";
1
+ import { CreateTableStatement, CreateTableStatementTextRenderer, type Column } from "@deterministic-code/datasources";
2
2
  export declare class SqliteCreateTableStatementRenderer extends CreateTableStatementTextRenderer {
3
3
  render(statement: CreateTableStatement): string;
4
4
  protected typeName(column: Column): string;
@@ -0,0 +1,18 @@
1
+ import { CreateTableStatement, CreateTableStatementTextRenderer } from "@deterministic-code/datasources";
2
+ import { columnTypes } from "./columnTypes.js";
3
+ const primaryKey = (constraint) => constraint.kind === "primaryKey";
4
+ export class SqliteCreateTableStatementRenderer extends CreateTableStatementTextRenderer {
5
+ render(statement) {
6
+ const identity = new Set(statement.columns.filter((column) => column.identity).map((column) => column.name));
7
+ const constraints = statement.constraints.filter((constraint) => !primaryKey(constraint) || !constraint.columns.every((column) => identity.has(column)));
8
+ return super.render(constraints.length === statement.constraints.length
9
+ ? statement
10
+ : new CreateTableStatement(statement.table, statement.columns, constraints));
11
+ }
12
+ typeName(column) {
13
+ return columnTypes[column.type] ?? column.type;
14
+ }
15
+ identity(column) {
16
+ return column.identity ? " PRIMARY KEY AUTOINCREMENT" : "";
17
+ }
18
+ }
@@ -0,0 +1,4 @@
1
+ import { CreateTriggerStatementTextRenderer, type CreateTriggerStatement } from "@deterministic-code/datasources";
2
+ export declare class SqliteCreateTriggerStatementRenderer extends CreateTriggerStatementTextRenderer {
3
+ render(statement: CreateTriggerStatement): string;
4
+ }
@@ -0,0 +1,12 @@
1
+ import { CreateTriggerStatementTextRenderer } from "@deterministic-code/datasources";
2
+ export class SqliteCreateTriggerStatementRenderer extends CreateTriggerStatementTextRenderer {
3
+ render(statement) {
4
+ return `CREATE TRIGGER ${statement.name}
5
+ AFTER UPDATE ON ${statement.table}
6
+ FOR EACH ROW
7
+ WHEN NEW.${statement.updatedColumn} IS OLD.${statement.updatedColumn}
8
+ BEGIN
9
+ UPDATE ${statement.table} SET ${statement.updatedColumn} = ${statement.utcNow} WHERE ${statement.keyColumn} = OLD.${statement.keyColumn};
10
+ END`;
11
+ }
12
+ }
@@ -1,10 +1,14 @@
1
- import { StatementTextRenderer, type Cell, type DatasourceOptions, type ICommand, type IConnection, type IDriver, type Information, type ITransaction, type IsolationLevel, type TypeConverter } from "@datasources/core";
1
+ import { DefaultValueConverter, DeterministicTypeConverter, StatementTextRenderer, type Cell, type DatasourceOptions, type ICommand, type IConnection, type IDriver, type Information, type ITransaction, type IsolationLevel, type TypeConverter } from "@deterministic-code/datasources";
2
2
  import { columnTypes } from "./columnTypes.js";
3
3
  export { columnTypes };
4
4
  export declare class SqliteDriver implements IDriver {
5
5
  readonly statementRenderer: StatementTextRenderer;
6
6
  readonly information: Information;
7
7
  rowTypeConverters: Record<string, TypeConverter<Cell, Cell>>;
8
+ readonly quoteLeft = "\"";
9
+ readonly quoteRight = "\"";
10
+ readonly typeConverter: DeterministicTypeConverter;
11
+ readonly defaultValueConverter: DefaultValueConverter;
8
12
  columnType: (name: string) => string;
9
13
  connection: (options?: DatasourceOptions) => IConnection;
10
14
  command: (connection: IConnection) => ICommand;
@@ -0,0 +1,64 @@
1
+ import { DatasourceError, DefaultValueConverter, DeterministicTypeConverter, StatementTextRenderer, } from "@deterministic-code/datasources";
2
+ import { SqliteConnection } from "./connection.js";
3
+ import { SqliteCommand } from "./command.js";
4
+ import { SqliteTransaction } from "./transaction.js";
5
+ import { SqliteRowTypeConverters } from "./converters/SqliteRowTypeConverters.js";
6
+ import { SqliteStatementRenderer } from "./SqliteStatementRenderer.js";
7
+ import { columnTypes } from "./columnTypes.js";
8
+ export { columnTypes };
9
+ const statements = new StatementTextRenderer(t => new SqliteStatementRenderer(t));
10
+ export class SqliteDriver {
11
+ statementRenderer = statements;
12
+ information = {
13
+ descriptions: [
14
+ "Embedded SQL database for local development and tests.",
15
+ "Full connection, command, transaction, and repository support.",
16
+ ],
17
+ overrides: [
18
+ "Overrides SelectInsertedIdStatement to SELECT last_insert_rowid() AS {column}",
19
+ "Overrides CreateTableStatement type mapping (int→INTEGER, bool→BOOLEAN, uuid/string/datetime→TEXT, decimal→NUMERIC, float→REAL, binary→BLOB)",
20
+ ],
21
+ changeLogs: [],
22
+ };
23
+ rowTypeConverters = SqliteRowTypeConverters;
24
+ quoteLeft = '"';
25
+ quoteRight = '"';
26
+ typeConverter = new DeterministicTypeConverter({
27
+ string: "TEXT",
28
+ character: "TEXT",
29
+ number: "INTEGER",
30
+ integer: "INTEGER",
31
+ unsignedinteger: "INTEGER",
32
+ smallinteger: "INTEGER",
33
+ unsignedsmallinteger: "INTEGER",
34
+ biginteger: "INTEGER",
35
+ unsignedbiginteger: "INTEGER",
36
+ float: "REAL",
37
+ decimal: "NUMERIC",
38
+ boolean: "BOOLEAN",
39
+ datetime: "TEXT",
40
+ binary: "BLOB",
41
+ uuid: "TEXT",
42
+ reference: "INTEGER",
43
+ }, {
44
+ dialectName: "sqlite",
45
+ stringUnlimited: "TEXT",
46
+ stringSized: (n) => `VARCHAR(${n})`,
47
+ });
48
+ defaultValueConverter = new DefaultValueConverter({
49
+ newId: () => "",
50
+ now: () => `(strftime('%Y-%m-%dT%H:%M:%f', 'now', 'localtime'))`,
51
+ utcNow: () => `(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))`,
52
+ booleanOn: "1",
53
+ booleanOff: "0",
54
+ hex: (arg) => `X'${arg}'`,
55
+ hexReverse: /^X'(.*)'$/,
56
+ });
57
+ columnType = (name) => columnTypes[name] ??
58
+ (() => {
59
+ throw new DatasourceError(`Unknown sqlite type "${name}"`);
60
+ })();
61
+ connection = (options) => SqliteConnection.from(options);
62
+ command = (connection) => new SqliteCommand(connection, statements);
63
+ transaction = (connection, isolation = "readCommitted") => new SqliteTransaction(connection, isolation);
64
+ }
@@ -1,6 +1,8 @@
1
- import { CreateTableStatement, SelectInsertedIdStatement, StatementRenderer, type StatementTextRenderer } from "@datasources/core";
1
+ import { AlterTableStatement, CreateTableStatement, CreateTriggerStatement, SelectInsertedIdStatement, StatementRenderer, type StatementTextRenderer } from "@deterministic-code/datasources";
2
2
  export declare class SqliteStatementRenderer extends StatementRenderer {
3
3
  constructor(text: StatementTextRenderer);
4
4
  protected visitSelectInsertedId(inserted: SelectInsertedIdStatement): string;
5
5
  protected visitCreateTable(create: CreateTableStatement): string;
6
+ protected visitAlterTable(alter: AlterTableStatement): string;
7
+ protected visitCreateTrigger(trigger: CreateTriggerStatement): string;
6
8
  }
@@ -0,0 +1,26 @@
1
+ import { SelectInsertedIdStatementTextRenderer, StatementRenderer, } from "@deterministic-code/datasources";
2
+ import { SqliteAlterTableStatementRenderer } from "./SqliteAlterTableStatementRenderer.js";
3
+ import { SqliteCreateTableStatementRenderer } from "./SqliteCreateTableStatementRenderer.js";
4
+ import { SqliteCreateTriggerStatementRenderer } from "./SqliteCreateTriggerStatementRenderer.js";
5
+ class SqliteSelectInsertedIdStatementTextRenderer extends SelectInsertedIdStatementTextRenderer {
6
+ render(statement) {
7
+ return `SELECT last_insert_rowid() AS ${statement.column}`;
8
+ }
9
+ }
10
+ export class SqliteStatementRenderer extends StatementRenderer {
11
+ constructor(text) {
12
+ super(text);
13
+ }
14
+ visitSelectInsertedId(inserted) {
15
+ return new SqliteSelectInsertedIdStatementTextRenderer().render(inserted);
16
+ }
17
+ visitCreateTable(create) {
18
+ return new SqliteCreateTableStatementRenderer().render(create);
19
+ }
20
+ visitAlterTable(alter) {
21
+ return new SqliteAlterTableStatementRenderer().renderAlter(alter);
22
+ }
23
+ visitCreateTrigger(trigger) {
24
+ return new SqliteCreateTriggerStatementRenderer().render(trigger);
25
+ }
26
+ }
@@ -0,0 +1,10 @@
1
+ export const columnTypes = {
2
+ int: "INTEGER",
3
+ uuid: "TEXT",
4
+ string: "TEXT",
5
+ bool: "BOOLEAN",
6
+ decimal: "NUMERIC",
7
+ float: "REAL",
8
+ datetime: "TEXT",
9
+ binary: "BLOB",
10
+ };
package/dist/command.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CommandMiddlewareHost, Native, StatementTextRenderer, Response, type Cells, type ICommand, type IReader, type IStatement, type Parameter } from "@datasources/core";
1
+ import { CommandMiddlewareHost, Native, StatementTextRenderer, Response, type Cells, type ICommand, type IReader, type IStatement, type Parameter } from "@deterministic-code/datasources";
2
2
  import type { SqliteConnection } from "./connection.js";
3
3
  export declare class SqliteCommand extends CommandMiddlewareHost implements ICommand {
4
4
  readonly connection: SqliteConnection;
@@ -0,0 +1,163 @@
1
+ import { ArrayReader, CommandMiddlewareHost, FirstResultReader, DatasourceError, Native, ReturnStatement, SelectStatement, StatementTextRenderer, parametersToRecord, Response, splitStatements, statementParameters, StreamingReader, } from "@deterministic-code/datasources";
2
+ import { reverse, SqliteRowTypeConverters } from "./converters/SqliteRowTypeConverters.js";
3
+ import { SqliteStatementRenderer } from "./SqliteStatementRenderer.js";
4
+ const bound = (parameters) => {
5
+ const record = parametersToRecord(parameters);
6
+ return Object.fromEntries(Object.entries(record).map(([name, value]) => [name, reverse(value)]));
7
+ };
8
+ const toSqlite = (sql, params) => {
9
+ const values = [];
10
+ const text = sql.replace(/\$([A-Za-z_][A-Za-z0-9_]*)/g, (_match, name) => {
11
+ values.push(params[name] ?? null);
12
+ return "?";
13
+ });
14
+ return { text, values };
15
+ };
16
+ export class SqliteCommand extends CommandMiddlewareHost {
17
+ connection;
18
+ statements;
19
+ constructor(connection, statements) {
20
+ super();
21
+ this.connection = connection;
22
+ this.statements = statements ?? new StatementTextRenderer(t => new SqliteStatementRenderer(t));
23
+ }
24
+ async executeReaderNative(text, parameters) {
25
+ return this.run(text.text, parameters, async (query, params) => {
26
+ if (!query.trim())
27
+ return { value: new ArrayReader([]), rows: [] };
28
+ this.connection.ensureOpen();
29
+ const statements = splitStatements(query);
30
+ if (statements.length === 0)
31
+ return { value: new ArrayReader([]), rows: [] };
32
+ const paramsBound = bound(params);
33
+ let index = 0;
34
+ let iter = this.iterate(statements[0], paramsBound);
35
+ return FirstResultReader.capture(new StreamingReader(async () => {
36
+ const step = iter.next();
37
+ return step.done ? undefined : step.value;
38
+ }, async () => {
39
+ iter.return();
40
+ index += 1;
41
+ const sql = statements[index];
42
+ if (!sql)
43
+ return false;
44
+ iter = this.iterate(sql, paramsBound);
45
+ return true;
46
+ }, async () => {
47
+ iter.return();
48
+ }));
49
+ });
50
+ }
51
+ async executeReaderStatement(statement, parameters) {
52
+ return this.executeReaderNative(new Native(this.statements.render(statement)), parameters);
53
+ }
54
+ async executeStatement(statement, parameters) {
55
+ return statement instanceof SelectStatement || statement instanceof ReturnStatement
56
+ ? this.firstCell(statement, parameters)
57
+ : this.executeNative(new Native(this.statements.render(statement)), parameters);
58
+ }
59
+ async firstCell(statement, parameters) {
60
+ const reader = await this.executeReaderStatement(statement, parameters);
61
+ try {
62
+ if (!(await reader.next()))
63
+ return new Response(null, 0, parameters);
64
+ const row = reader.current;
65
+ /* v8 ignore next */
66
+ if (!row)
67
+ throw new DatasourceError("Reader current must be a row");
68
+ const values = Object.values(row);
69
+ return new Response(values.length === 0 ? null : values[0], 1, parameters);
70
+ }
71
+ finally {
72
+ await reader.dispose();
73
+ }
74
+ }
75
+ async executeNative(text, parameters) {
76
+ return this.run(text.text, parameters, async (query, params) => {
77
+ if (!query.trim())
78
+ return { value: new Response(undefined, 0, params), rows: [] };
79
+ this.connection.ensureOpen();
80
+ const db = this.connection.require();
81
+ const named = bound(params);
82
+ let changes = 0;
83
+ for (const sql of splitStatements(query)) {
84
+ const names = new Set(statementParameters(sql));
85
+ const used = Object.fromEntries(Object.entries(named).filter(([name]) => names.has(name.replace(/^[$:@]/, ""))));
86
+ const { text, values } = toSqlite(sql, used);
87
+ changes += db.prepare(text).run(...values).changes;
88
+ }
89
+ return { value: new Response(null, changes, params), rows: [] };
90
+ });
91
+ }
92
+ iterate(sql, params) {
93
+ const statement = this.connection.require().prepare(sql);
94
+ const columns = statement.columns?.() ?? [];
95
+ const names = qualified(columns);
96
+ const declared = columns.map((column) => column.type ?? null);
97
+ const raw = names.some((name, index) => name !== columns[index]?.name)
98
+ ? statement.raw?.(true).iterate(params)
99
+ : undefined;
100
+ const rows = raw ? namedRows(raw, names, declared) : closable(statement.iterate(params), columns);
101
+ return rows[Symbol.iterator]();
102
+ }
103
+ }
104
+ const booleanDeclared = (declared) => declared?.toUpperCase() === "BOOLEAN";
105
+ const cell = (value, declared) => value == null ? null : booleanDeclared(declared) ? SqliteRowTypeConverters.bool.convert(value) : value;
106
+ const closable = (iter, columns) => {
107
+ const stop = iter.return ? iter.return.bind(iter) : undefined;
108
+ const rows = {
109
+ next: () => {
110
+ const step = iter.next();
111
+ if (step.done || !step.value)
112
+ return step;
113
+ const value = Object.fromEntries(Object.entries(step.value).map(([name, item]) => [
114
+ name,
115
+ cell(item, columns.find((column) => column.name === name)?.type),
116
+ ]));
117
+ return { done: false, value };
118
+ },
119
+ return: () => {
120
+ if (stop)
121
+ stop();
122
+ return { done: true, value: undefined };
123
+ },
124
+ [Symbol.iterator]() {
125
+ return rows;
126
+ },
127
+ };
128
+ return rows;
129
+ };
130
+ const namedRows = (iter, names, declared) => {
131
+ /* v8 ignore next */
132
+ const stop = iter.return ? iter.return.bind(iter) : undefined;
133
+ const rows = {
134
+ next: () => {
135
+ const step = iter.next();
136
+ return step.done
137
+ ? { done: true, value: undefined }
138
+ : {
139
+ done: false,
140
+ value: Object.fromEntries(names.map((name, index) => [name, cell(step.value[index], declared[index])])),
141
+ };
142
+ },
143
+ return: () => {
144
+ /* v8 ignore next */
145
+ if (stop)
146
+ stop();
147
+ return { done: true, value: undefined };
148
+ },
149
+ [Symbol.iterator]() {
150
+ return rows;
151
+ },
152
+ };
153
+ return rows;
154
+ };
155
+ const qualified = (columns) => {
156
+ const names = columns.map((column) => column.name);
157
+ const duplicated = new Set(names.filter((name, index) => names.indexOf(name) !== index));
158
+ return duplicated.size === 0
159
+ ? names
160
+ : columns.map((column, index) => duplicated.has(names[index]) && column.table && column.column
161
+ ? `${column.table}.${column.column}`
162
+ : names[index]);
163
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,4 @@
1
- import { type DatasourceOptions, type ICommand, type IConnection, type IsolationLevelName, type ITransaction } from "@datasources/core";
1
+ import { type DatasourceOptions, type ICommand, type IConnection, type IsolationLevelName, type ITransaction } from "@deterministic-code/datasources";
2
2
  import type { SqliteConnectionOptions } from "./connection-options.js";
3
3
  import type { SqliteDatabase } from "./i-sqlite-driver.js";
4
4
  export declare class SqliteConnection implements IConnection {
@@ -0,0 +1,58 @@
1
+ import { DatasourceError, IsolationLevel, StatementTextRenderer, } from "@deterministic-code/datasources";
2
+ import { createRequire } from "node:module";
3
+ import { SqliteCommand } from "./command.js";
4
+ import { filenameOf } from "./sqlitePath.js";
5
+ import { SqliteStatementRenderer } from "./SqliteStatementRenderer.js";
6
+ import { SqliteTransaction } from "./transaction.js";
7
+ const require = createRequire(import.meta.url);
8
+ const pragma = (isolation) => isolation === IsolationLevel.ReadUncommitted
9
+ ? "PRAGMA read_uncommitted = 1"
10
+ : "PRAGMA read_uncommitted = 0";
11
+ export class SqliteConnection {
12
+ provider = "sqlite";
13
+ filename;
14
+ isOpen = false;
15
+ db;
16
+ Database;
17
+ static from = (options) => new SqliteConnection({
18
+ url: options?.DATASOURCE_URL,
19
+ Database: require("better-sqlite3"),
20
+ });
21
+ constructor(options = {}) {
22
+ this.filename = filenameOf(options);
23
+ this.Database = options.Database;
24
+ }
25
+ createCommand = () => new SqliteCommand(this, new StatementTextRenderer(t => new SqliteStatementRenderer(t)));
26
+ async open() {
27
+ if (this.isOpen)
28
+ throw new DatasourceError("Connection is already open");
29
+ if (!this.Database)
30
+ throw new DatasourceError("SQLite driver is required");
31
+ this.db = new this.Database(this.filename, { timeout: 0 });
32
+ this.isOpen = true;
33
+ }
34
+ async close() {
35
+ this.db?.close();
36
+ this.db = undefined;
37
+ this.isOpen = false;
38
+ }
39
+ [Symbol.asyncDispose] = () => this.close();
40
+ async startTransaction(isolation = IsolationLevel.Serializable) {
41
+ this.ensureOpen();
42
+ this.exec(pragma(isolation));
43
+ this.exec("BEGIN");
44
+ return new SqliteTransaction(this, isolation);
45
+ }
46
+ ensureOpen() {
47
+ if (!this.isOpen)
48
+ throw new DatasourceError("Connection is not open");
49
+ }
50
+ require() {
51
+ if (!this.db)
52
+ throw new DatasourceError("Connection is not open");
53
+ return this.db;
54
+ }
55
+ exec(sql) {
56
+ this.require().exec(sql);
57
+ }
58
+ }
@@ -1,4 +1,4 @@
1
- import { TypeConverter, type Cell } from "@datasources/core";
1
+ import { TypeConverter, type Cell } from "@deterministic-code/datasources";
2
2
  export declare class BinaryConverter extends TypeConverter<Cell, Cell> {
3
3
  convert: (from: Cell) => Cell;
4
4
  reverseConvert: (to: Cell) => Cell;
@@ -0,0 +1,5 @@
1
+ import { TypeConverter } from "@deterministic-code/datasources";
2
+ export class BinaryConverter extends TypeConverter {
3
+ convert = (from) => from;
4
+ reverseConvert = (to) => to;
5
+ }
@@ -1,4 +1,4 @@
1
- import { TypeConverter, type Cell } from "@datasources/core";
1
+ import { TypeConverter, type Cell } from "@deterministic-code/datasources";
2
2
  export declare class BoolConverter extends TypeConverter<Cell, Cell> {
3
3
  convert: (from: Cell) => Cell;
4
4
  reverseConvert: (to: Cell) => Cell;
@@ -0,0 +1,5 @@
1
+ import { TypeConverter } from "@deterministic-code/datasources";
2
+ export class BoolConverter extends TypeConverter {
3
+ convert = (from) => (typeof from === "number" ? from !== 0 : from);
4
+ reverseConvert = (to) => (typeof to === "boolean" ? (to ? 1 : 0) : to);
5
+ }
@@ -1,4 +1,4 @@
1
- import { TypeConverter, type Cell } from "@datasources/core";
1
+ import { TypeConverter, type Cell } from "@deterministic-code/datasources";
2
2
  export declare class DateTimeConverter extends TypeConverter<Cell, Cell> {
3
3
  convert: (from: Cell) => Cell;
4
4
  reverseConvert: (to: Cell) => Cell;
@@ -0,0 +1,5 @@
1
+ import { TypeConverter } from "@deterministic-code/datasources";
2
+ export class DateTimeConverter extends TypeConverter {
3
+ convert = (from) => typeof from === "string" ? new Date(from) : from;
4
+ reverseConvert = (to) => to instanceof Date ? to.toISOString() : to;
5
+ }
@@ -1,4 +1,4 @@
1
- import { TypeConverter, type Cell } from "@datasources/core";
1
+ import { TypeConverter, type Cell } from "@deterministic-code/datasources";
2
2
  export declare class DecimalConverter extends TypeConverter<Cell, Cell> {
3
3
  convert: (from: Cell) => Cell;
4
4
  reverseConvert: (to: Cell) => Cell;
@@ -0,0 +1,5 @@
1
+ import { TypeConverter } from "@deterministic-code/datasources";
2
+ export class DecimalConverter extends TypeConverter {
3
+ convert = (from) => from;
4
+ reverseConvert = (to) => typeof to === "number" ? String(to) : to;
5
+ }
@@ -1,3 +1,3 @@
1
- import { type Cell, type TypeConverter } from "@datasources/core";
1
+ import { type Cell, type TypeConverter } from "@deterministic-code/datasources";
2
2
  export declare const SqliteRowTypeConverters: Record<string, TypeConverter<Cell, Cell>>;
3
3
  export declare const reverse: (value: Cell) => Cell;
@@ -0,0 +1,19 @@
1
+ import { BinaryConverter } from "./BinaryConverter.js";
2
+ import { BoolConverter } from "./BoolConverter.js";
3
+ import { DateTimeConverter } from "./DateTimeConverter.js";
4
+ import { DecimalConverter } from "./DecimalConverter.js";
5
+ import { UuidConverter } from "./UuidConverter.js";
6
+ export const SqliteRowTypeConverters = {
7
+ bool: new BoolConverter(),
8
+ datetime: new DateTimeConverter(),
9
+ uuid: new UuidConverter(),
10
+ decimal: new DecimalConverter(),
11
+ binary: new BinaryConverter(),
12
+ };
13
+ export const reverse = (value) => typeof value === "boolean"
14
+ ? SqliteRowTypeConverters.bool.reverseConvert(value)
15
+ : value instanceof Date
16
+ ? SqliteRowTypeConverters.datetime.reverseConvert(value)
17
+ : value instanceof Uint8Array
18
+ ? SqliteRowTypeConverters.binary.reverseConvert(value)
19
+ : value;
@@ -1,4 +1,4 @@
1
- import { TypeConverter, type Cell } from "@datasources/core";
1
+ import { TypeConverter, type Cell } from "@deterministic-code/datasources";
2
2
  export declare class UuidConverter extends TypeConverter<Cell, Cell> {
3
3
  convert: (from: Cell) => Cell;
4
4
  reverseConvert: (to: Cell) => Cell;
@@ -0,0 +1,5 @@
1
+ import { TypeConverter } from "@deterministic-code/datasources";
2
+ export class UuidConverter extends TypeConverter {
3
+ convert = (from) => from;
4
+ reverseConvert = (to) => to;
5
+ }
@@ -1,4 +1,4 @@
1
- import type { Cell, Cells, Scalar } from "@datasources/core";
1
+ import type { Cell, Cells, Scalar } from "@deterministic-code/datasources";
2
2
  export interface SqliteStatement {
3
3
  run(params?: Record<string, Scalar>): {
4
4
  changes: number;
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.d.ts CHANGED
@@ -1,2 +1 @@
1
1
  export { SqliteDriver } from "./SqliteDriver.js";
2
- export { SqliteStatementRenderer } from "./SqliteStatementRenderer.js";
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { SqliteDriver } from "./SqliteDriver.js";
@@ -0,0 +1,7 @@
1
+ export const sqliteFilename = (url) => {
2
+ if (!/^sqlite:/i.test(url))
3
+ return undefined;
4
+ const path = url.replace(/^sqlite:(?:\/\/\/|\/\/)?/i, "");
5
+ return path === "" || path === ":memory" || path === ":memory:" ? ":memory:" : path;
6
+ };
7
+ export const filenameOf = (options) => options.filename ?? (options.url ? sqliteFilename(options.url) ?? ":memory:" : ":memory:");
@@ -1,4 +1,4 @@
1
- import { type ITransaction, type IsolationLevelName } from "@datasources/core";
1
+ import { type ITransaction, type IsolationLevelName } from "@deterministic-code/datasources";
2
2
  import type { SqliteConnection } from "./connection.js";
3
3
  export declare class SqliteTransaction implements ITransaction {
4
4
  readonly connection: SqliteConnection;
@@ -0,0 +1,15 @@
1
+ import { IsolationLevel, } from "@deterministic-code/datasources";
2
+ export class SqliteTransaction {
3
+ connection;
4
+ isolation;
5
+ constructor(connection, isolation = IsolationLevel.ReadCommitted) {
6
+ this.connection = connection;
7
+ this.isolation = isolation;
8
+ }
9
+ async commit() {
10
+ this.connection.exec("COMMIT");
11
+ }
12
+ async abort() {
13
+ this.connection.exec("ROLLBACK");
14
+ }
15
+ }
package/package.json CHANGED
@@ -1,26 +1,25 @@
1
1
  {
2
2
  "name": "@deterministic-code/datasources-sqlite",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
- "main": "./src/index.ts",
6
- "types": "./dist/index.d.ts",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.js",
7
7
  "exports": {
8
8
  ".": {
9
- "types": "./dist/index.d.ts",
10
- "import": "./src/index.ts",
11
- "default": "./src/index.ts"
9
+ "types": "./dist/index.d.js",
10
+ "import": "./dist/index.js",
11
+ "default": "./dist/index.js"
12
12
  }
13
13
  },
14
14
  "files": [
15
- "dist",
16
- "src"
15
+ "dist"
17
16
  ],
18
17
  "publishConfig": {
19
18
  "access": "public"
20
19
  },
21
20
  "dependencies": {
21
+ "@deterministic-code/datasources": "^0.1.3",
22
22
  "@types/better-sqlite3": "^7.6.13",
23
- "better-sqlite3": "^12.10.0",
24
- "@deterministic-code/datasources": "^0.1.1"
23
+ "better-sqlite3": "^12.10.0"
25
24
  }
26
25
  }