@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
@@ -1,24 +0,0 @@
1
- import { CreateTableStatement, CreateTableStatementTextRenderer, PrimaryKey, type Column } from "@datasources/core";
2
- import { columnTypes } from "./columnTypes.ts";
3
-
4
- export class SqliteCreateTableStatementRenderer extends CreateTableStatementTextRenderer {
5
- override render(statement: CreateTableStatement): string {
6
- const identity = new Set(statement.columns.filter((column) => column.identity).map((column) => column.name));
7
- const constraints = statement.constraints.filter(
8
- (constraint) => !(constraint instanceof PrimaryKey) || !constraint.columns.every((column) => identity.has(column)),
9
- );
10
- return super.render(
11
- constraints.length === statement.constraints.length
12
- ? statement
13
- : new CreateTableStatement(statement.table, statement.columns, constraints),
14
- );
15
- }
16
-
17
- protected typeName(column: Column): string {
18
- return columnTypes[column.type] ?? column.type;
19
- }
20
-
21
- protected identity(column: Column): string {
22
- return column.identity ? " PRIMARY KEY AUTOINCREMENT" : "";
23
- }
24
- }
@@ -1,53 +0,0 @@
1
- import {
2
- DatasourceError,
3
- StatementTextRenderer,
4
- type Cell,
5
- type DatasourceOptions,
6
- type ICommand,
7
- type IConnection,
8
- type IDriver,
9
- type Information,
10
- type ITransaction,
11
- type IsolationLevel,
12
- type TypeConverter,
13
- } from "@datasources/core";
14
- import { SqliteConnection } from "./connection.ts";
15
- import { SqliteCommand } from "./command.ts";
16
- import { SqliteTransaction } from "./transaction.ts";
17
- import { SqliteRowTypeConverters } from "./converters/SqliteRowTypeConverters.ts";
18
- import { SqliteStatementRenderer } from "./SqliteStatementRenderer.ts";
19
- import { columnTypes } from "./columnTypes.ts";
20
-
21
- export { columnTypes };
22
-
23
- const statements = new StatementTextRenderer(t => new SqliteStatementRenderer(t));
24
-
25
- export class SqliteDriver implements IDriver {
26
- readonly statementRenderer = statements;
27
- readonly information: Information = {
28
- descriptions: [
29
- "Embedded SQL database for local development and tests.",
30
- "Full connection, command, transaction, and repository support.",
31
- ],
32
- overrides: [
33
- "Overrides SelectInsertedIdStatement to SELECT last_insert_rowid() AS {column}",
34
- "Overrides CreateTableStatement type mapping (int→INTEGER, bool→BOOLEAN, uuid/string/datetime→TEXT, decimal→NUMERIC, float→REAL, binary→BLOB)",
35
- ],
36
- changeLogs: [],
37
- };
38
- rowTypeConverters: Record<string, TypeConverter<Cell, Cell>> = SqliteRowTypeConverters;
39
- columnType = (name: string): string =>
40
- columnTypes[name] ??
41
- (() => {
42
- throw new DatasourceError(`Unknown sqlite type "${name}"`);
43
- })();
44
- connection = (options?: DatasourceOptions): IConnection =>
45
- SqliteConnection.from(options);
46
- command = (connection: IConnection): ICommand =>
47
- new SqliteCommand(connection as SqliteConnection, statements);
48
- transaction = (
49
- connection: IConnection,
50
- isolation: IsolationLevel = "readCommitted",
51
- ): ITransaction =>
52
- new SqliteTransaction(connection as SqliteConnection, isolation);
53
- }
@@ -1,60 +0,0 @@
1
- import {
2
- ColumnDefault,
3
- CreateTableStatement,
4
- DefaultStatementTextRenderer,
5
- ForeignKey,
6
- SelectInsertedIdStatement,
7
- NotNull,
8
- PrimaryKey,
9
- ReferentialAction,
10
- SelectStatement,
11
- StatementTextRenderer,
12
- } from "@datasources/core";
13
- import { describe, expect, it } from "vitest";
14
- import { SqliteCreateTableStatementRenderer } from "./SqliteCreateTableStatementRenderer.ts";
15
- import { SqliteStatementRenderer } from "./SqliteStatementRenderer.ts";
16
-
17
- describe("SqliteStatementRenderer", () => {
18
- const renderer = new StatementTextRenderer(t => new SqliteStatementRenderer(t));
19
-
20
- it("renders inserted id and create table", () => {
21
- expect(renderer.render(new SelectInsertedIdStatement("users", "id"))).toBe(
22
- "SELECT last_insert_rowid() AS id",
23
- );
24
-
25
- const create = new CreateTableStatement(
26
- "orders",
27
- [
28
- { name: "id", type: "INTEGER", default: new ColumnDefault("0", "df_id"), notNull: new NotNull("nn_id") },
29
- { name: "user_id", type: "INTEGER" },
30
- ],
31
- [
32
- new PrimaryKey("pk_orders", ["id"]),
33
- new ForeignKey("fk_orders_user", ["user_id"], "users", ["id"], ReferentialAction.Cascade),
34
- ],
35
- );
36
- expect(renderer.render(create)).toBe(new SqliteCreateTableStatementRenderer().render(create));
37
- expect(renderer.render(new SelectStatement({ table: "users", fields: ["id"] }))).toBe(
38
- "SELECT id FROM users",
39
- );
40
- });
41
-
42
- it("renders canonical types", () => {
43
- const create = new CreateTableStatement("users", [
44
- { name: "id", type: "int", default: new ColumnDefault("0"), notNull: new NotNull(), identity: true },
45
- ]);
46
- expect(renderer.render(create)).toBe(
47
- "CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT DEFAULT 0 NOT NULL)",
48
- );
49
- expect(DefaultStatementTextRenderer.instance.render(create)).toBe(
50
- "CREATE TABLE users (id int DEFAULT 0 NOT NULL)",
51
- );
52
-
53
- const keyed = new CreateTableStatement(
54
- "users",
55
- [{ name: "id", type: "int", identity: true }],
56
- [new PrimaryKey("pk_users", ["id"])],
57
- );
58
- expect(renderer.render(keyed)).toBe("CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT)");
59
- });
60
- });
@@ -1,28 +0,0 @@
1
- import {
2
- CreateTableStatement,
3
- SelectInsertedIdStatement,
4
- SelectInsertedIdStatementTextRenderer,
5
- StatementRenderer,
6
- type StatementTextRenderer,
7
- } from "@datasources/core";
8
- import { SqliteCreateTableStatementRenderer } from "./SqliteCreateTableStatementRenderer.ts";
9
-
10
- class SqliteSelectInsertedIdStatementTextRenderer extends SelectInsertedIdStatementTextRenderer {
11
- override render(statement: SelectInsertedIdStatement): string {
12
- return `SELECT last_insert_rowid() AS ${statement.column}`;
13
- }
14
- }
15
-
16
- export class SqliteStatementRenderer extends StatementRenderer {
17
- constructor(text: StatementTextRenderer) {
18
- super(text);
19
- }
20
-
21
- protected override visitSelectInsertedId(inserted: SelectInsertedIdStatement): string {
22
- return new SqliteSelectInsertedIdStatementTextRenderer().render(inserted);
23
- }
24
-
25
- protected override visitCreateTable(create: CreateTableStatement): string {
26
- return new SqliteCreateTableStatementRenderer().render(create);
27
- }
28
- }
@@ -1,10 +0,0 @@
1
- export const columnTypes: Record<string, string> = {
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/src/command.ts DELETED
@@ -1,231 +0,0 @@
1
- import {
2
- ArrayReader,
3
- CommandMiddlewareHost,
4
- FirstResultReader,
5
- DatasourceError,
6
- Native,
7
- ReturnStatement,
8
- SelectStatement,
9
- StatementTextRenderer,
10
- parametersToRecord,
11
- Response,
12
- splitStatements,
13
- statementParameters,
14
- StreamingReader,
15
- type Cell,
16
- type Cells,
17
- type Scalar,
18
- type ICommand,
19
- type IReader,
20
- type IStatement,
21
- type Parameter,
22
- } from "@datasources/core";
23
- import type { SqliteConnection } from "./connection.ts";
24
- import type { SqliteStatement } from "./i-sqlite-driver.ts";
25
- import { reverse, SqliteRowTypeConverters } from "./converters/SqliteRowTypeConverters.ts";
26
- import { SqliteStatementRenderer } from "./SqliteStatementRenderer.ts";
27
-
28
- const bound = (parameters?: Parameter[]): Record<string, Scalar> => {
29
- const record = parametersToRecord(parameters);
30
- return Object.fromEntries(
31
- Object.entries(record).map(([name, value]) => [name, reverse(value)]),
32
- ) as Record<string, Scalar>;
33
- };
34
-
35
- const toSqlite = (sql: string, params: Record<string, Scalar>): { text: string; values: Scalar[] } => {
36
- const values: Scalar[] = [];
37
- const text = sql.replace(/\$([A-Za-z_][A-Za-z0-9_]*)/g, (_match, name: string) => {
38
- values.push(params[name] ?? null);
39
- return "?";
40
- });
41
- return { text, values };
42
- };
43
-
44
- export class SqliteCommand extends CommandMiddlewareHost implements ICommand {
45
- private readonly statements: StatementTextRenderer;
46
-
47
- constructor(readonly connection: SqliteConnection, statements?: StatementTextRenderer) {
48
- super();
49
- this.statements = statements ?? new StatementTextRenderer(t => new SqliteStatementRenderer(t));
50
- }
51
-
52
- async executeReaderNative(
53
- text: Native,
54
- parameters?: Parameter[],
55
- ): Promise<IReader<Cells>> {
56
- return this.run(text.text, parameters, async (query, params) => {
57
- if (!query.trim()) return { value: new ArrayReader([]), rows: [] };
58
- this.connection.ensureOpen();
59
- const statements = splitStatements(query);
60
- if (statements.length === 0) return { value: new ArrayReader([]), rows: [] };
61
- const paramsBound = bound(params);
62
- let index = 0;
63
- let iter = this.iterate(statements[0] as string, paramsBound);
64
- return FirstResultReader.capture(
65
- new StreamingReader(
66
- async () => {
67
- const step = iter.next();
68
- return step.done ? undefined : step.value;
69
- },
70
- async () => {
71
- iter.return();
72
- index += 1;
73
- const sql = statements[index];
74
- if (!sql) return false;
75
- iter = this.iterate(sql, paramsBound);
76
- return true;
77
- },
78
- async () => {
79
- iter.return();
80
- },
81
- ),
82
- );
83
- });
84
- }
85
-
86
- async executeReaderStatement(
87
- statement: IStatement,
88
- parameters?: Parameter[],
89
- ): Promise<IReader<Cells>> {
90
- return this.executeReaderNative(new Native(this.statements.render(statement)), parameters);
91
- }
92
-
93
- async executeStatement(statement: IStatement, parameters?: Parameter[]): Promise<Response> {
94
- return statement instanceof SelectStatement || statement instanceof ReturnStatement
95
- ? this.firstCell(statement, parameters)
96
- : this.executeNative(new Native(this.statements.render(statement)), parameters);
97
- }
98
-
99
- private async firstCell(statement: IStatement, parameters?: Parameter[]): Promise<Response> {
100
- const reader = await this.executeReaderStatement(statement, parameters);
101
- try {
102
- if (!(await reader.next())) return new Response(null, 0, parameters);
103
- const row = reader.current;
104
- /* v8 ignore next */
105
- if (!row) throw new DatasourceError("Reader current must be a row");
106
- const values = Object.values(row);
107
- return new Response(values.length === 0 ? null : values[0], 1, parameters);
108
- } finally {
109
- await reader.dispose();
110
- }
111
- }
112
-
113
- async executeNative(text: Native, parameters?: Parameter[]): Promise<Response> {
114
- return this.run(text.text, parameters, async (query, params) => {
115
- if (!query.trim()) return { value: new Response(undefined, 0, params), rows: [] };
116
- this.connection.ensureOpen();
117
- const db = this.connection.require();
118
- const named = bound(params);
119
- let changes = 0;
120
- for (const sql of splitStatements(query)) {
121
- const names = new Set(statementParameters(sql));
122
- const used = Object.fromEntries(
123
- Object.entries(named).filter(([name]) => names.has(name.replace(/^[$:@]/, ""))),
124
- );
125
- const { text, values } = toSqlite(sql, used);
126
- changes += db.prepare(text).run(...values).changes;
127
- }
128
- return { value: new Response(null, changes, params), rows: [] };
129
- });
130
- }
131
-
132
- private iterate(sql: string, params: Record<string, Scalar>): IterableIterator<Cells> & {
133
- return(): IteratorResult<Cells>;
134
- } {
135
- const statement = this.connection.require().prepare(sql) as ColumnStatement;
136
- const columns = statement.columns?.() ?? [];
137
- const names = qualified(columns);
138
- const declared = columns.map((column) => column.type ?? null);
139
- const raw = names.some((name, index) => name !== columns[index]?.name)
140
- ? statement.raw?.(true).iterate(params)
141
- : undefined;
142
- const rows = raw ? namedRows(raw, names, declared) : closable(statement.iterate(params), columns);
143
- return rows[Symbol.iterator]();
144
- }
145
- }
146
-
147
- type SqliteColumn = { name: string; column: string | null; table: string | null; type?: string | null };
148
-
149
- const booleanDeclared = (declared?: string | null): boolean =>
150
- declared?.toUpperCase() === "BOOLEAN";
151
-
152
- const cell = (value: Cell | null | undefined, declared?: string | null): Cell | null =>
153
- value == null ? null : booleanDeclared(declared) ? SqliteRowTypeConverters.bool.convert(value) : value;
154
-
155
- type ColumnStatement = SqliteStatement & {
156
- columns?: () => SqliteColumn[];
157
- raw?: (enabled: boolean) => {
158
- iterate(params?: Record<string, Scalar>): IterableIterator<Cell[]>;
159
- };
160
- };
161
-
162
- const closable = (
163
- iter: IterableIterator<Cells>,
164
- columns: SqliteColumn[],
165
- ): IterableIterator<Cells> & { return(): IteratorResult<Cells> } => {
166
- const stop = iter.return ? iter.return.bind(iter) : undefined;
167
- const rows: IterableIterator<Cells> & { return(): IteratorResult<Cells> } = {
168
- next: () => {
169
- const step = iter.next();
170
- if (step.done || !step.value) return step;
171
- const value = Object.fromEntries(
172
- Object.entries(step.value).map(([name, item]) => [
173
- name,
174
- cell(item, columns.find((column) => column.name === name)?.type),
175
- ]),
176
- ) as Cells;
177
- return { done: false, value };
178
- },
179
- return: () => {
180
- if (stop) stop();
181
- return { done: true, value: undefined };
182
- },
183
- [Symbol.iterator]() {
184
- return rows;
185
- },
186
- };
187
- return rows;
188
- };
189
-
190
- const namedRows = (
191
- iter: IterableIterator<Cell[]>,
192
- names: string[],
193
- declared: (string | null)[],
194
- ): IterableIterator<Cells> & { return(): IteratorResult<Cells> } => {
195
- /* v8 ignore next */
196
- const stop = iter.return ? iter.return.bind(iter) : undefined;
197
- const rows: IterableIterator<Cells> & { return(): IteratorResult<Cells> } = {
198
- next: () => {
199
- const step = iter.next();
200
- return step.done
201
- ? { done: true, value: undefined }
202
- : {
203
- done: false,
204
- value: Object.fromEntries(
205
- names.map((name, index) => [name, cell(step.value[index], declared[index])]),
206
- ),
207
- };
208
- },
209
- return: () => {
210
- /* v8 ignore next */
211
- if (stop) stop();
212
- return { done: true, value: undefined };
213
- },
214
- [Symbol.iterator]() {
215
- return rows;
216
- },
217
- };
218
- return rows;
219
- };
220
-
221
- const qualified = (columns: SqliteColumn[]): string[] => {
222
- const names = columns.map((column) => column.name);
223
- const duplicated = new Set(names.filter((name, index) => names.indexOf(name) !== index));
224
- return duplicated.size === 0
225
- ? names
226
- : columns.map((column, index) =>
227
- duplicated.has(names[index]!) && column.table && column.column
228
- ? `${column.table}.${column.column}`
229
- : names[index]!
230
- );
231
- };
@@ -1,7 +0,0 @@
1
- import type { SqliteDatabaseCtor } from "./i-sqlite-driver.ts";
2
-
3
- export interface SqliteConnectionOptions {
4
- filename?: string;
5
- url?: string;
6
- Database?: SqliteDatabaseCtor;
7
- }
package/src/connection.ts DELETED
@@ -1,83 +0,0 @@
1
- import {
2
- DatasourceError,
3
- IsolationLevel,
4
- StatementTextRenderer,
5
- type DatasourceOptions,
6
- type ICommand,
7
- type IConnection,
8
- type IsolationLevelName,
9
- type ITransaction,
10
- } from "@datasources/core";
11
- import { createRequire } from "node:module";
12
- import { SqliteCommand } from "./command.ts";
13
- import type { SqliteConnectionOptions } from "./connection-options.ts";
14
- import type { SqliteDatabase, SqliteDatabaseCtor } from "./i-sqlite-driver.ts";
15
- import { filenameOf } from "./sqlitePath.ts";
16
- import { SqliteStatementRenderer } from "./SqliteStatementRenderer.ts";
17
- import { SqliteTransaction } from "./transaction.ts";
18
-
19
- const require = createRequire(import.meta.url);
20
-
21
- const pragma = (isolation: IsolationLevelName): string =>
22
- isolation === IsolationLevel.ReadUncommitted
23
- ? "PRAGMA read_uncommitted = 1"
24
- : "PRAGMA read_uncommitted = 0";
25
-
26
- export class SqliteConnection implements IConnection {
27
- readonly provider = "sqlite";
28
- filename: string;
29
- isOpen = false;
30
- private db?: SqliteDatabase;
31
- private readonly Database?: SqliteDatabaseCtor;
32
-
33
- static from = (options?: DatasourceOptions): SqliteConnection =>
34
- new SqliteConnection({
35
- url: options?.DATASOURCE_URL,
36
- Database: require("better-sqlite3") as SqliteDatabaseCtor,
37
- });
38
-
39
- constructor(options: SqliteConnectionOptions = {}) {
40
- this.filename = filenameOf(options);
41
- this.Database = options.Database;
42
- }
43
-
44
- createCommand = (): ICommand =>
45
- new SqliteCommand(this, new StatementTextRenderer(t => new SqliteStatementRenderer(t)));
46
-
47
- async open(): Promise<void> {
48
- if (this.isOpen) throw new DatasourceError("Connection is already open");
49
- if (!this.Database) throw new DatasourceError("SQLite driver is required");
50
- this.db = new this.Database(this.filename, { timeout: 0 });
51
- this.isOpen = true;
52
- }
53
-
54
- async close(): Promise<void> {
55
- this.db?.close();
56
- this.db = undefined;
57
- this.isOpen = false;
58
- }
59
-
60
- [Symbol.asyncDispose] = (): Promise<void> => this.close();
61
-
62
- async startTransaction(
63
- isolation: IsolationLevelName = IsolationLevel.ReadCommitted,
64
- ): Promise<ITransaction> {
65
- this.ensureOpen();
66
- this.exec(pragma(isolation));
67
- this.exec("BEGIN");
68
- return new SqliteTransaction(this, isolation);
69
- }
70
-
71
- ensureOpen(): void {
72
- if (!this.isOpen) throw new DatasourceError("Connection is not open");
73
- }
74
-
75
- require(): SqliteDatabase {
76
- if (!this.db) throw new DatasourceError("Connection is not open");
77
- return this.db;
78
- }
79
-
80
- exec(sql: string): void {
81
- this.require().exec(sql);
82
- }
83
- }
@@ -1,11 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { BinaryConverter } from "./BinaryConverter.ts";
3
-
4
- describe("BinaryConverter", () => {
5
- it("maps binary", () => {
6
- const converter = new BinaryConverter();
7
- const bytes = new Uint8Array([1, 2]);
8
- expect(converter.convert(bytes)).toBe(bytes);
9
- expect(converter.reverseConvert(bytes)).toBe(bytes);
10
- });
11
- });
@@ -1,6 +0,0 @@
1
- import { TypeConverter, type Cell } from "@datasources/core";
2
-
3
- export class BinaryConverter extends TypeConverter<Cell, Cell> {
4
- convert = (from: Cell): Cell => from;
5
- reverseConvert = (to: Cell): Cell => to;
6
- }
@@ -1,14 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { BoolConverter } from "./BoolConverter.ts";
3
-
4
- describe("BoolConverter", () => {
5
- it("maps bool", () => {
6
- const converter = new BoolConverter();
7
- expect(converter.convert(1)).toBe(true);
8
- expect(converter.convert(0)).toBe(false);
9
- expect(converter.convert("x")).toBe("x");
10
- expect(converter.reverseConvert(true)).toBe(1);
11
- expect(converter.reverseConvert(false)).toBe(0);
12
- expect(converter.reverseConvert("x")).toBe("x");
13
- });
14
- });
@@ -1,6 +0,0 @@
1
- import { TypeConverter, type Cell } from "@datasources/core";
2
-
3
- export class BoolConverter extends TypeConverter<Cell, Cell> {
4
- convert = (from: Cell): Cell => (typeof from === "number" ? from !== 0 : from);
5
- reverseConvert = (to: Cell): Cell => (typeof to === "boolean" ? (to ? 1 : 0) : to);
6
- }
@@ -1,13 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { DateTimeConverter } from "./DateTimeConverter.ts";
3
-
4
- describe("DateTimeConverter", () => {
5
- it("maps datetime", () => {
6
- const converter = new DateTimeConverter();
7
- const date = new Date("2020-01-02T03:04:05.000Z");
8
- expect(converter.convert("2020-01-02T03:04:05.000Z")).toEqual(date);
9
- expect(converter.convert(date)).toBe(date);
10
- expect(converter.reverseConvert(date)).toBe("2020-01-02T03:04:05.000Z");
11
- expect(converter.reverseConvert("x")).toBe("x");
12
- });
13
- });
@@ -1,8 +0,0 @@
1
- import { TypeConverter, type Cell } from "@datasources/core";
2
-
3
- export class DateTimeConverter extends TypeConverter<Cell, Cell> {
4
- convert = (from: Cell): Cell =>
5
- typeof from === "string" ? new Date(from) : from;
6
- reverseConvert = (to: Cell): Cell =>
7
- to instanceof Date ? to.toISOString() : to;
8
- }
@@ -1,11 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { DecimalConverter } from "./DecimalConverter.ts";
3
-
4
- describe("DecimalConverter", () => {
5
- it("maps decimal", () => {
6
- const converter = new DecimalConverter();
7
- expect(converter.convert("10.5")).toBe("10.5");
8
- expect(converter.reverseConvert(10.5)).toBe("10.5");
9
- expect(converter.reverseConvert("10.5")).toBe("10.5");
10
- });
11
- });
@@ -1,7 +0,0 @@
1
- import { TypeConverter, type Cell } from "@datasources/core";
2
-
3
- export class DecimalConverter extends TypeConverter<Cell, Cell> {
4
- convert = (from: Cell): Cell => from;
5
- reverseConvert = (to: Cell): Cell =>
6
- typeof to === "number" ? String(to) : to;
7
- }
@@ -1,18 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { SqliteDriver } from "../SqliteDriver.ts";
3
- import { reverse, SqliteRowTypeConverters } from "./SqliteRowTypeConverters.ts";
4
-
5
- describe("SqliteRowTypeConverters", () => {
6
- it("registers default types", () => {
7
- expect(Object.keys(new SqliteDriver().rowTypeConverters)).toEqual(Object.keys(SqliteRowTypeConverters));
8
- });
9
-
10
- it("reverses booleans, dates, and bytes", () => {
11
- const when = new Date("2024-01-02T00:00:00.000Z");
12
- expect(reverse(true)).toBe(1);
13
- expect(reverse(false)).toBe(0);
14
- expect(reverse(when)).toBe(when.toISOString());
15
- expect(reverse(new Uint8Array([1, 2]))).toEqual(new Uint8Array([1, 2]));
16
- expect(reverse("a")).toBe("a");
17
- });
18
- });
@@ -1,24 +0,0 @@
1
- import { type Cell, type TypeConverter } from "@datasources/core";
2
- import { BinaryConverter } from "./BinaryConverter.ts";
3
- import { BoolConverter } from "./BoolConverter.ts";
4
- import { DateTimeConverter } from "./DateTimeConverter.ts";
5
- import { DecimalConverter } from "./DecimalConverter.ts";
6
- import { UuidConverter } from "./UuidConverter.ts";
7
-
8
- export const SqliteRowTypeConverters: Record<string, TypeConverter<Cell, Cell>> = {
9
- bool: new BoolConverter(),
10
- datetime: new DateTimeConverter(),
11
- uuid: new UuidConverter(),
12
- decimal: new DecimalConverter(),
13
- binary: new BinaryConverter(),
14
- };
15
-
16
- export const reverse = (value: Cell): Cell =>
17
- typeof value === "boolean"
18
- ? SqliteRowTypeConverters.bool.reverseConvert(value)
19
- : value instanceof Date
20
- ? SqliteRowTypeConverters.datetime.reverseConvert(value)
21
- : value instanceof Uint8Array
22
- ? SqliteRowTypeConverters.binary.reverseConvert(value)
23
- : value;
24
-
@@ -1,11 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { UuidConverter } from "./UuidConverter.ts";
3
-
4
- describe("UuidConverter", () => {
5
- it("maps uuid", () => {
6
- const converter = new UuidConverter();
7
- const id = "550e8400-e29b-41d4-a716-446655440000";
8
- expect(converter.convert(id)).toBe(id);
9
- expect(converter.reverseConvert(id)).toBe(id);
10
- });
11
- });
@@ -1,6 +0,0 @@
1
- import { TypeConverter, type Cell } from "@datasources/core";
2
-
3
- export class UuidConverter extends TypeConverter<Cell, Cell> {
4
- convert = (from: Cell): Cell => from;
5
- reverseConvert = (to: Cell): Cell => to;
6
- }
@@ -1,15 +0,0 @@
1
- import { CRUDRepository, Datasource } from "@datasources/core";
2
- import { expect, it } from "vitest";
3
- import { SqliteDriver } from "./SqliteDriver.ts";
4
-
5
- class Item {
6
- id = 0;
7
- name = "";
8
- }
9
-
10
- it("create from a driver", () => {
11
- const driver = new SqliteDriver();
12
- const ds = new Datasource("sqlite", driver, { DATASOURCE_URL: "sqlite:///:memory:" });
13
- const repo = ds.createRepository(Item);
14
- expect(repo instanceof CRUDRepository).toBe(true);
15
- });