@deterministic-code/datasources-mysql 0.1.1 → 0.1.2
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.
- package/dist/MysqlAlterTableStatementRenderer.d.ts +6 -0
- package/dist/MysqlAlterTableStatementRenderer.js +13 -0
- package/dist/MysqlBulkUpdateStatementTextRenderer.d.ts +1 -1
- package/dist/MysqlBulkUpdateStatementTextRenderer.js +9 -0
- package/dist/MysqlCreateRoutineStatementRenderer.d.ts +4 -0
- package/dist/MysqlCreateTableStatementRenderer.d.ts +1 -1
- package/dist/MysqlCreateTableStatementRenderer.js +10 -0
- package/dist/MysqlCreateTriggerStatementRenderer.d.ts +4 -0
- package/dist/MysqlCreateTriggerStatementRenderer.js +7 -0
- package/dist/MysqlDriver.d.ts +5 -1
- package/dist/MysqlDriver.js +76 -0
- package/dist/MysqlDropIndexStatementRenderer.d.ts +4 -0
- package/dist/MysqlDropIndexStatementRenderer.js +6 -0
- package/dist/MysqlDropRoutineStatementRenderer.d.ts +4 -0
- package/dist/MysqlDropRoutineStatementRenderer.js +6 -0
- package/dist/MysqlStatementRenderer.d.ts +12 -1
- package/dist/MysqlStatementRenderer.js +60 -0
- package/dist/MysqlStoredProcedureStatementRenderer.d.ts +10 -0
- package/dist/MysqlStoredProcedureStatementRenderer.js +101 -0
- package/dist/bind.d.ts +1 -1
- package/dist/bind.js +20 -0
- package/dist/columnTypes.js +10 -0
- package/dist/command.d.ts +1 -1
- package/dist/command.js +143 -0
- package/dist/connection-options.js +1 -0
- package/dist/connection.d.ts +1 -1
- package/dist/connection.js +64 -0
- package/dist/converters/BinaryConverter.d.ts +1 -1
- package/dist/converters/BinaryConverter.js +6 -0
- package/dist/converters/BoolConverter.d.ts +1 -1
- package/dist/converters/BoolConverter.js +5 -0
- package/dist/converters/DateTimeConverter.d.ts +1 -1
- package/dist/converters/DateTimeConverter.js +10 -0
- package/dist/converters/DecimalConverter.d.ts +1 -1
- package/dist/converters/DecimalConverter.js +5 -0
- package/dist/converters/MysqlRowTypeConverters.d.ts +1 -1
- package/dist/converters/MysqlRowTypeConverters.js +20 -0
- package/dist/converters/UuidConverter.d.ts +1 -1
- package/dist/converters/UuidConverter.js +5 -0
- package/dist/i-mysql-engine.d.ts +1 -1
- package/dist/i-mysql-engine.js +14 -0
- package/dist/index.js +1 -0
- package/dist/scalar.js +1 -0
- package/dist/transaction.d.ts +1 -1
- package/dist/transaction.js +15 -0
- package/package.json +9 -10
- package/src/MysqlBulkUpdateStatementTextRenderer.ts +0 -10
- package/src/MysqlCreateTableStatementRenderer.ts +0 -12
- package/src/MysqlDriver.ts +0 -54
- package/src/MysqlStatementRenderer.test.ts +0 -64
- package/src/MysqlStatementRenderer.ts +0 -34
- package/src/bind.ts +0 -31
- package/src/columnTypes.ts +0 -10
- package/src/command.ts +0 -197
- package/src/connection-options.ts +0 -6
- package/src/connection.ts +0 -91
- package/src/converters/BinaryConverter.test.ts +0 -12
- package/src/converters/BinaryConverter.ts +0 -9
- package/src/converters/BoolConverter.test.ts +0 -14
- package/src/converters/BoolConverter.ts +0 -6
- package/src/converters/DateTimeConverter.test.ts +0 -14
- package/src/converters/DateTimeConverter.ts +0 -15
- package/src/converters/DecimalConverter.test.ts +0 -11
- package/src/converters/DecimalConverter.ts +0 -7
- package/src/converters/MysqlRowTypeConverters.test.ts +0 -19
- package/src/converters/MysqlRowTypeConverters.ts +0 -25
- package/src/converters/UuidConverter.test.ts +0 -11
- package/src/converters/UuidConverter.ts +0 -6
- package/src/i-mysql-engine.ts +0 -58
- package/src/index.ts +0 -1
- package/src/mysql.test.ts +0 -342
- package/src/scalar.ts +0 -2
- package/src/transaction.ts +0 -21
package/src/command.ts
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ArrayReader,
|
|
3
|
-
CommandMiddlewareHost,
|
|
4
|
-
FirstResultReader,
|
|
5
|
-
DatasourceError,
|
|
6
|
-
ExecuteStoredProcedureStatement,
|
|
7
|
-
Native,
|
|
8
|
-
ParameterDirection,
|
|
9
|
-
ReturnStatement,
|
|
10
|
-
SelectStatement,
|
|
11
|
-
StatementTextRenderer,
|
|
12
|
-
Response,
|
|
13
|
-
splitStatements,
|
|
14
|
-
statementParameters,
|
|
15
|
-
statementReader,
|
|
16
|
-
StreamingReader,
|
|
17
|
-
type Cells,
|
|
18
|
-
type ICommand,
|
|
19
|
-
type IReader,
|
|
20
|
-
type IStatement,
|
|
21
|
-
type Parameter,
|
|
22
|
-
} from "@datasources/core";
|
|
23
|
-
import { bindParameters, toMysql } from "./bind.ts";
|
|
24
|
-
import type { MysqlConnection } from "./connection.ts";
|
|
25
|
-
import type { MysqlExecuteResult } from "./i-mysql-engine.ts";
|
|
26
|
-
import type { Scalar } from "./scalar.ts";
|
|
27
|
-
import { MysqlStatementRenderer } from "./MysqlStatementRenderer.ts";
|
|
28
|
-
|
|
29
|
-
const outputs = (parameters?: Parameter[]) =>
|
|
30
|
-
parameters?.filter(
|
|
31
|
-
(parameter) =>
|
|
32
|
-
parameter.direction && parameter.direction !== ParameterDirection.Input,
|
|
33
|
-
) ?? [];
|
|
34
|
-
|
|
35
|
-
export class MysqlCommand extends CommandMiddlewareHost implements ICommand {
|
|
36
|
-
private readonly statements: StatementTextRenderer;
|
|
37
|
-
|
|
38
|
-
constructor(readonly connection: MysqlConnection, statements?: StatementTextRenderer) {
|
|
39
|
-
super();
|
|
40
|
-
this.statements = statements ?? new StatementTextRenderer(t => new MysqlStatementRenderer(t));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async executeReaderNative(
|
|
44
|
-
text: Native,
|
|
45
|
-
parameters?: Parameter[],
|
|
46
|
-
): Promise<IReader<Cells>> {
|
|
47
|
-
return this.run(text.text, parameters, async (query, params) => {
|
|
48
|
-
if (!query.trim()) return { value: new ArrayReader([]), rows: [] };
|
|
49
|
-
this.connection.ensureOpen();
|
|
50
|
-
const statements = splitStatements(query);
|
|
51
|
-
if (statements.length === 0) return { value: new ArrayReader([]), rows: [] };
|
|
52
|
-
const bound = bindParameters(params);
|
|
53
|
-
if (statements.some((sql) => /^\s*call\b/i.test(sql))) {
|
|
54
|
-
const sets: Cells[][] = [];
|
|
55
|
-
for (const sql of statements) sets.push(...(await this.callResults(sql, bound)));
|
|
56
|
-
return FirstResultReader.capture(resultSetsReader(sets));
|
|
57
|
-
}
|
|
58
|
-
return FirstResultReader.capture(statementReader(statements, (sql) => this.query(sql, bound)));
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async executeReaderStatement(
|
|
63
|
-
statement: IStatement,
|
|
64
|
-
parameters?: Parameter[],
|
|
65
|
-
): Promise<IReader<Cells>> {
|
|
66
|
-
return this.executeReaderNative(new Native(this.statements.render(statement)), parameters);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async executeStatement(statement: IStatement, parameters?: Parameter[]): Promise<Response> {
|
|
70
|
-
if (statement instanceof SelectStatement || statement instanceof ReturnStatement)
|
|
71
|
-
return this.firstCell(statement, parameters);
|
|
72
|
-
if (statement instanceof ExecuteStoredProcedureStatement && statement.name && outputs(parameters).length)
|
|
73
|
-
return this.executeProcedure(this.statements.render(statement), parameters);
|
|
74
|
-
return this.executeNative(new Native(this.statements.render(statement)), parameters);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
private async firstCell(statement: IStatement, parameters?: Parameter[]): Promise<Response> {
|
|
78
|
-
const reader = await this.executeReaderStatement(statement, parameters);
|
|
79
|
-
try {
|
|
80
|
-
if (!(await reader.next())) return new Response(null, 0, parameters);
|
|
81
|
-
const row = reader.current;
|
|
82
|
-
/* v8 ignore next */
|
|
83
|
-
if (!row) throw new DatasourceError("Reader current must be a row");
|
|
84
|
-
const values = Object.values(row);
|
|
85
|
-
return new Response(values.length === 0 ? null : values[0], 1, parameters);
|
|
86
|
-
} finally {
|
|
87
|
-
await reader.dispose();
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async executeNative(text: Native, parameters?: Parameter[]): Promise<Response> {
|
|
92
|
-
return this.run(text.text, parameters, async (query, params) => {
|
|
93
|
-
if (!query.trim()) return { value: new Response(undefined, 0, params), rows: [] };
|
|
94
|
-
this.connection.ensureOpen();
|
|
95
|
-
const named = bindParameters(params);
|
|
96
|
-
let rowsAffected = 0;
|
|
97
|
-
let parameters = params;
|
|
98
|
-
let result: MysqlExecuteResult["result"];
|
|
99
|
-
for (const part of splitStatements(query)) {
|
|
100
|
-
const names = new Set(statementParameters(part));
|
|
101
|
-
const used = Object.fromEntries(
|
|
102
|
-
Object.entries(named).filter(([name]) => names.has(name.replace(/^[$:@]/, ""))),
|
|
103
|
-
);
|
|
104
|
-
const executed = await this.runSql(part, used, params);
|
|
105
|
-
rowsAffected += executed.rowsAffected;
|
|
106
|
-
parameters = executed.parameters ?? params;
|
|
107
|
-
result = executed.result;
|
|
108
|
-
}
|
|
109
|
-
return {
|
|
110
|
-
value: new Response(result, rowsAffected, parameters),
|
|
111
|
-
rows: [],
|
|
112
|
-
};
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
private async executeProcedure(sql: string, parameters?: Parameter[]): Promise<Response> {
|
|
117
|
-
return this.run(sql, parameters, async (query, params) => {
|
|
118
|
-
this.connection.ensureOpen();
|
|
119
|
-
const outs = outputs(params);
|
|
120
|
-
const client = this.connection.require();
|
|
121
|
-
for (const parameter of params!) {
|
|
122
|
-
if (
|
|
123
|
-
!parameter.direction ||
|
|
124
|
-
parameter.direction === ParameterDirection.Input ||
|
|
125
|
-
parameter.direction === ParameterDirection.InputOutput
|
|
126
|
-
)
|
|
127
|
-
await client.query(`SET @${parameter.name} = :${parameter.name}`, {
|
|
128
|
-
[parameter.name]: parameter.value ?? null,
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
await client.query(toMysql(query).replace(/:([A-Za-z_][A-Za-z0-9_]*)/g, "@$1"));
|
|
132
|
-
const [rows] = await client.query(
|
|
133
|
-
`SELECT ${outs.map((parameter) => `@${parameter.name} AS \`${parameter.name}\``).join(", ")}`,
|
|
134
|
-
);
|
|
135
|
-
const row = Array.isArray(rows) ? (rows[0] as Cells | undefined) : undefined;
|
|
136
|
-
return {
|
|
137
|
-
value: new Response(
|
|
138
|
-
undefined,
|
|
139
|
-
0,
|
|
140
|
-
params?.map((parameter) =>
|
|
141
|
-
row && parameter.direction && parameter.direction !== ParameterDirection.Input
|
|
142
|
-
? { ...parameter, value: cellValue(row[parameter.name]) }
|
|
143
|
-
: parameter,
|
|
144
|
-
),
|
|
145
|
-
),
|
|
146
|
-
rows: [],
|
|
147
|
-
};
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
private async runSql(
|
|
152
|
-
sql: string,
|
|
153
|
-
params?: Record<string, Scalar>,
|
|
154
|
-
parameters?: Parameter[],
|
|
155
|
-
): Promise<MysqlExecuteResult> {
|
|
156
|
-
const [result] = await this.connection.require().query(toMysql(sql), params);
|
|
157
|
-
return Array.isArray(result)
|
|
158
|
-
? { rowsAffected: result.length, parameters }
|
|
159
|
-
: { rowsAffected: result.affectedRows ?? 0, result: null, parameters };
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
private query(sql: string, params?: Record<string, Scalar>): AsyncIterable<Cells> {
|
|
163
|
-
return this.connection.require().queryRows(toMysql(sql), params);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
private async callResults(sql: string, params?: Record<string, Scalar>): Promise<Cells[][]> {
|
|
167
|
-
const [result] = await this.connection.require().query(toMysql(sql), params);
|
|
168
|
-
if (!Array.isArray(result)) return [[]];
|
|
169
|
-
return result.filter((item): item is Cells[] => Array.isArray(item));
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const cellValue = (cell: Scalar | object | undefined): Scalar => {
|
|
174
|
-
if (cell === null || cell === undefined) return null;
|
|
175
|
-
if (typeof cell === "string" || typeof cell === "number" || typeof cell === "boolean" || typeof cell === "bigint")
|
|
176
|
-
return cell;
|
|
177
|
-
if (cell instanceof Uint8Array) return new TextDecoder().decode(cell);
|
|
178
|
-
return JSON.stringify(cell);
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
const resultSetsReader = (sets: Cells[][]): StreamingReader => {
|
|
182
|
-
let set = 0;
|
|
183
|
-
let row = 0;
|
|
184
|
-
return new StreamingReader(
|
|
185
|
-
async () => {
|
|
186
|
-
const current = sets[set]?.[row];
|
|
187
|
-
if (current === undefined) return undefined;
|
|
188
|
-
row += 1;
|
|
189
|
-
return current;
|
|
190
|
-
},
|
|
191
|
-
async () => {
|
|
192
|
-
set += 1;
|
|
193
|
-
row = 0;
|
|
194
|
-
return set < sets.length;
|
|
195
|
-
},
|
|
196
|
-
);
|
|
197
|
-
};
|
package/src/connection.ts
DELETED
|
@@ -1,91 +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 { MysqlCommand } from "./command.ts";
|
|
13
|
-
import type { MysqlConnectionOptions } from "./connection-options.ts";
|
|
14
|
-
import {
|
|
15
|
-
mysql2Connect,
|
|
16
|
-
type IMysqlClient,
|
|
17
|
-
type Mysql2Module,
|
|
18
|
-
type MysqlCreateConnection,
|
|
19
|
-
} from "./i-mysql-engine.ts";
|
|
20
|
-
import { MysqlStatementRenderer } from "./MysqlStatementRenderer.ts";
|
|
21
|
-
import { MysqlTransaction } from "./transaction.ts";
|
|
22
|
-
|
|
23
|
-
const require = createRequire(import.meta.url);
|
|
24
|
-
|
|
25
|
-
const isoSql = (isolation: IsolationLevelName): string =>
|
|
26
|
-
isolation === IsolationLevel.ReadUncommitted
|
|
27
|
-
? "READ UNCOMMITTED"
|
|
28
|
-
: isolation === IsolationLevel.ReadCommitted
|
|
29
|
-
? "READ COMMITTED"
|
|
30
|
-
: "REPEATABLE READ";
|
|
31
|
-
|
|
32
|
-
export class MysqlConnection implements IConnection {
|
|
33
|
-
readonly provider = "mysql";
|
|
34
|
-
url: string;
|
|
35
|
-
isOpen = false;
|
|
36
|
-
private client?: IMysqlClient;
|
|
37
|
-
private readonly connect?: MysqlCreateConnection;
|
|
38
|
-
|
|
39
|
-
static from = (options?: DatasourceOptions): MysqlConnection => {
|
|
40
|
-
const url = options?.DATASOURCE_URL ?? "";
|
|
41
|
-
return new MysqlConnection({
|
|
42
|
-
url,
|
|
43
|
-
connect: mysql2Connect(require("mysql2/promise") as Mysql2Module),
|
|
44
|
-
});
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
constructor(options: MysqlConnectionOptions = {}) {
|
|
48
|
-
this.url = options.url ?? "";
|
|
49
|
-
this.connect = options.connect;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
createCommand = (): ICommand =>
|
|
53
|
-
new MysqlCommand(this, new StatementTextRenderer(t => new MysqlStatementRenderer(t)));
|
|
54
|
-
|
|
55
|
-
async open(): Promise<void> {
|
|
56
|
-
if (this.isOpen) throw new DatasourceError("Connection is already open");
|
|
57
|
-
if (!this.client) {
|
|
58
|
-
if (!this.connect) throw new DatasourceError("MySQL engine is required");
|
|
59
|
-
this.client = await this.connect(this.url);
|
|
60
|
-
}
|
|
61
|
-
await this.client.query("SET SESSION sql_mode = CONCAT(@@sql_mode, ',ANSI_QUOTES')");
|
|
62
|
-
this.isOpen = true;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async close(): Promise<void> {
|
|
66
|
-
await this.client?.end();
|
|
67
|
-
this.client = undefined;
|
|
68
|
-
this.isOpen = false;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
[Symbol.asyncDispose] = (): Promise<void> => this.close();
|
|
72
|
-
|
|
73
|
-
async startTransaction(
|
|
74
|
-
isolation: IsolationLevelName = IsolationLevel.ReadCommitted,
|
|
75
|
-
): Promise<ITransaction> {
|
|
76
|
-
this.ensureOpen();
|
|
77
|
-
const client = this.require();
|
|
78
|
-
await client.query(`SET TRANSACTION ISOLATION LEVEL ${isoSql(isolation)}`);
|
|
79
|
-
await client.beginTransaction();
|
|
80
|
-
return new MysqlTransaction(this, isolation);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
ensureOpen(): void {
|
|
84
|
-
if (!this.isOpen) throw new DatasourceError("Connection is not open");
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
require(): IMysqlClient {
|
|
88
|
-
if (!this.client) throw new DatasourceError("Connection is not open");
|
|
89
|
-
return this.client;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
@@ -1,12 +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 raw = new Uint8Array([1, 2, 3, 4]);
|
|
8
|
-
expect(converter.convert(raw)).toBe(raw);
|
|
9
|
-
expect(converter.reverseConvert(raw)).toBe(raw);
|
|
10
|
-
expect(converter.reverseConvert("AQIDBA==")).toEqual(raw);
|
|
11
|
-
});
|
|
12
|
-
});
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { TypeConverter, type Cell } from "@datasources/core";
|
|
2
|
-
|
|
3
|
-
const bytes = (value: Cell): Cell =>
|
|
4
|
-
typeof value === "string" ? Uint8Array.from(Buffer.from(value, "base64")) : value;
|
|
5
|
-
|
|
6
|
-
export class BinaryConverter extends TypeConverter<Cell, Cell> {
|
|
7
|
-
convert = (from: Cell): Cell => bytes(from);
|
|
8
|
-
reverseConvert = (to: Cell): Cell => bytes(to);
|
|
9
|
-
}
|
|
@@ -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,14 +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-02 03:04:05.000");
|
|
11
|
-
expect(converter.reverseConvert("2020-01-02T03:04:05.000Z")).toBe("2020-01-02 03:04:05.000");
|
|
12
|
-
expect(converter.reverseConvert("x")).toBe("x");
|
|
13
|
-
});
|
|
14
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { TypeConverter, type Cell } from "@datasources/core";
|
|
2
|
-
|
|
3
|
-
const stamp = (date: Date): string =>
|
|
4
|
-
date.toISOString().replace("T", " ").replace("Z", "");
|
|
5
|
-
|
|
6
|
-
export class DateTimeConverter extends TypeConverter<Cell, Cell> {
|
|
7
|
-
convert = (from: Cell): Cell =>
|
|
8
|
-
typeof from === "string" ? new Date(from) : from;
|
|
9
|
-
reverseConvert = (to: Cell): Cell =>
|
|
10
|
-
to instanceof Date
|
|
11
|
-
? stamp(to)
|
|
12
|
-
: typeof to === "string" && /^\d{4}-\d{2}-\d{2}T/.test(to)
|
|
13
|
-
? stamp(new Date(to))
|
|
14
|
-
: to;
|
|
15
|
-
}
|
|
@@ -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,19 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { MysqlDriver } from "../MysqlDriver.ts";
|
|
3
|
-
import { reverse, MysqlRowTypeConverters } from "./MysqlRowTypeConverters.ts";
|
|
4
|
-
|
|
5
|
-
describe("MysqlRowTypeConverters", () => {
|
|
6
|
-
it("registers default types", () => {
|
|
7
|
-
expect(Object.keys(new MysqlDriver().rowTypeConverters)).toEqual(Object.keys(MysqlRowTypeConverters));
|
|
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().replace("T", " ").replace("Z", ""));
|
|
15
|
-
expect(reverse(new Uint8Array([1, 2]))).toEqual(new Uint8Array([1, 2]));
|
|
16
|
-
expect(reverse("a")).toBe("a");
|
|
17
|
-
expect(reverse("2024-01-02T00:00:00Z")).toBe("2024-01-02 00:00:00.000");
|
|
18
|
-
});
|
|
19
|
-
});
|
|
@@ -1,25 +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 MysqlRowTypeConverters: 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
|
-
? MysqlRowTypeConverters.bool.reverseConvert(value)
|
|
19
|
-
: value instanceof Date
|
|
20
|
-
|| (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T/.test(value))
|
|
21
|
-
? MysqlRowTypeConverters.datetime.reverseConvert(value)
|
|
22
|
-
: value instanceof Uint8Array
|
|
23
|
-
? MysqlRowTypeConverters.binary.reverseConvert(value)
|
|
24
|
-
: value;
|
|
25
|
-
|
|
@@ -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
|
-
});
|
package/src/i-mysql-engine.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import type { Parameter } from "@datasources/core";
|
|
2
|
-
import type { Cells, Scalar } from "./scalar.ts";
|
|
3
|
-
|
|
4
|
-
export interface MysqlExecuteResult {
|
|
5
|
-
rowsAffected: number;
|
|
6
|
-
result?: Scalar;
|
|
7
|
-
parameters?: Parameter[];
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface MysqlQueryHeader {
|
|
11
|
-
affectedRows?: number;
|
|
12
|
-
insertId?: Scalar;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface IMysqlClient {
|
|
16
|
-
query(
|
|
17
|
-
sql: string,
|
|
18
|
-
params?: Record<string, Scalar>,
|
|
19
|
-
): Promise<[MysqlQueryHeader | Cells[]]>;
|
|
20
|
-
queryRows(sql: string, params?: Record<string, Scalar>): AsyncIterable<Cells>;
|
|
21
|
-
beginTransaction(): Promise<void>;
|
|
22
|
-
commit(): Promise<void>;
|
|
23
|
-
rollback(): Promise<void>;
|
|
24
|
-
end(): Promise<void>;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
interface MysqlCoreQuery {
|
|
28
|
-
stream(): AsyncIterable<Cells>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface Mysql2PromiseConnection extends IMysqlClient {
|
|
32
|
-
connection: {
|
|
33
|
-
query(sql: string, params?: Record<string, Scalar>): MysqlCoreQuery;
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export type MysqlCreateConnection = (url: string) => Promise<IMysqlClient>;
|
|
38
|
-
|
|
39
|
-
export type Mysql2Module = {
|
|
40
|
-
createConnection: (
|
|
41
|
-
options: { uri: string; namedPlaceholders: boolean },
|
|
42
|
-
) => Promise<IMysqlClient>;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export const mysql2Connect = (mysql: Mysql2Module): MysqlCreateConnection => async (uri: string) => {
|
|
46
|
-
const client = (await mysql.createConnection({
|
|
47
|
-
uri,
|
|
48
|
-
namedPlaceholders: true,
|
|
49
|
-
})) as Mysql2PromiseConnection;
|
|
50
|
-
return {
|
|
51
|
-
query: (sql, params) => client.query(sql, params),
|
|
52
|
-
queryRows: (sql, params) => client.connection.query(sql, params).stream(),
|
|
53
|
-
beginTransaction: () => client.beginTransaction(),
|
|
54
|
-
commit: () => client.commit(),
|
|
55
|
-
rollback: () => client.rollback(),
|
|
56
|
-
end: () => client.end(),
|
|
57
|
-
};
|
|
58
|
-
};
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { MysqlDriver } from "./MysqlDriver.ts";
|