@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
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { DatasourceError, IsolationLevel, StatementTextRenderer, } from "@deterministic-code/datasources";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { MysqlCommand } from "./command.js";
|
|
4
|
+
import { mysql2Connect, } from "./i-mysql-engine.js";
|
|
5
|
+
import { MysqlStatementRenderer } from "./MysqlStatementRenderer.js";
|
|
6
|
+
import { MysqlTransaction } from "./transaction.js";
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const isoSql = (isolation) => isolation === IsolationLevel.ReadUncommitted
|
|
9
|
+
? "READ UNCOMMITTED"
|
|
10
|
+
: isolation === IsolationLevel.ReadCommitted
|
|
11
|
+
? "READ COMMITTED"
|
|
12
|
+
: "REPEATABLE READ";
|
|
13
|
+
export class MysqlConnection {
|
|
14
|
+
provider = "mysql";
|
|
15
|
+
url;
|
|
16
|
+
isOpen = false;
|
|
17
|
+
client;
|
|
18
|
+
connect;
|
|
19
|
+
static from = (options) => {
|
|
20
|
+
const url = options?.DATASOURCE_URL ?? "";
|
|
21
|
+
return new MysqlConnection({
|
|
22
|
+
url,
|
|
23
|
+
connect: mysql2Connect(require("mysql2/promise")),
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
constructor(options = {}) {
|
|
27
|
+
this.url = options.url ?? "";
|
|
28
|
+
this.connect = options.connect;
|
|
29
|
+
}
|
|
30
|
+
createCommand = () => new MysqlCommand(this, new StatementTextRenderer(t => new MysqlStatementRenderer(t)));
|
|
31
|
+
async open() {
|
|
32
|
+
if (this.isOpen)
|
|
33
|
+
throw new DatasourceError("Connection is already open");
|
|
34
|
+
if (!this.client) {
|
|
35
|
+
if (!this.connect)
|
|
36
|
+
throw new DatasourceError("MySQL engine is required");
|
|
37
|
+
this.client = await this.connect(this.url);
|
|
38
|
+
}
|
|
39
|
+
await this.client.query("SET SESSION sql_mode = CONCAT(@@sql_mode, ',ANSI_QUOTES')");
|
|
40
|
+
this.isOpen = true;
|
|
41
|
+
}
|
|
42
|
+
async close() {
|
|
43
|
+
await this.client?.end();
|
|
44
|
+
this.client = undefined;
|
|
45
|
+
this.isOpen = false;
|
|
46
|
+
}
|
|
47
|
+
[Symbol.asyncDispose] = () => this.close();
|
|
48
|
+
async startTransaction(isolation = IsolationLevel.Serializable) {
|
|
49
|
+
this.ensureOpen();
|
|
50
|
+
const client = this.require();
|
|
51
|
+
await client.query(`SET TRANSACTION ISOLATION LEVEL ${isoSql(isolation)}`);
|
|
52
|
+
await client.beginTransaction();
|
|
53
|
+
return new MysqlTransaction(this, isolation);
|
|
54
|
+
}
|
|
55
|
+
ensureOpen() {
|
|
56
|
+
if (!this.isOpen)
|
|
57
|
+
throw new DatasourceError("Connection is not open");
|
|
58
|
+
}
|
|
59
|
+
require() {
|
|
60
|
+
if (!this.client)
|
|
61
|
+
throw new DatasourceError("Connection is not open");
|
|
62
|
+
return this.client;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TypeConverter, type Cell } from "@datasources
|
|
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,6 @@
|
|
|
1
|
+
import { TypeConverter } from "@deterministic-code/datasources";
|
|
2
|
+
const bytes = (value) => typeof value === "string" ? Uint8Array.from(Buffer.from(value, "base64")) : value;
|
|
3
|
+
export class BinaryConverter extends TypeConverter {
|
|
4
|
+
convert = (from) => bytes(from);
|
|
5
|
+
reverseConvert = (to) => bytes(to);
|
|
6
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TypeConverter, type Cell } from "@datasources
|
|
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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TypeConverter, type Cell } from "@datasources
|
|
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,10 @@
|
|
|
1
|
+
import { TypeConverter } from "@deterministic-code/datasources";
|
|
2
|
+
const stamp = (date) => date.toISOString().replace("T", " ").replace("Z", "");
|
|
3
|
+
export class DateTimeConverter extends TypeConverter {
|
|
4
|
+
convert = (from) => typeof from === "string" ? new Date(from) : from;
|
|
5
|
+
reverseConvert = (to) => to instanceof Date
|
|
6
|
+
? stamp(to)
|
|
7
|
+
: typeof to === "string" && /^\d{4}-\d{2}-\d{2}T/.test(to)
|
|
8
|
+
? stamp(new Date(to))
|
|
9
|
+
: to;
|
|
10
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TypeConverter, type Cell } from "@datasources
|
|
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;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { type Cell, type TypeConverter } from "@datasources
|
|
1
|
+
import { type Cell, type TypeConverter } from "@deterministic-code/datasources";
|
|
2
2
|
export declare const MysqlRowTypeConverters: Record<string, TypeConverter<Cell, Cell>>;
|
|
3
3
|
export declare const reverse: (value: Cell) => Cell;
|
|
@@ -0,0 +1,20 @@
|
|
|
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 MysqlRowTypeConverters = {
|
|
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
|
+
? MysqlRowTypeConverters.bool.reverseConvert(value)
|
|
15
|
+
: value instanceof Date
|
|
16
|
+
|| (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T/.test(value))
|
|
17
|
+
? MysqlRowTypeConverters.datetime.reverseConvert(value)
|
|
18
|
+
: value instanceof Uint8Array
|
|
19
|
+
? MysqlRowTypeConverters.binary.reverseConvert(value)
|
|
20
|
+
: value;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TypeConverter, type Cell } from "@datasources
|
|
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;
|
package/dist/i-mysql-engine.d.ts
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const mysql2Connect = (mysql) => async (uri) => {
|
|
2
|
+
const client = (await mysql.createConnection({
|
|
3
|
+
uri,
|
|
4
|
+
namedPlaceholders: true,
|
|
5
|
+
}));
|
|
6
|
+
return {
|
|
7
|
+
query: (sql, params) => client.query(sql, params),
|
|
8
|
+
queryRows: (sql, params) => client.connection.query(sql, params).stream(),
|
|
9
|
+
beginTransaction: () => client.beginTransaction(),
|
|
10
|
+
commit: () => client.commit(),
|
|
11
|
+
rollback: () => client.rollback(),
|
|
12
|
+
end: () => client.end(),
|
|
13
|
+
};
|
|
14
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MysqlDriver } from "./MysqlDriver.js";
|
package/dist/scalar.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/transaction.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ITransaction, type IsolationLevelName } from "@datasources
|
|
1
|
+
import { type ITransaction, type IsolationLevelName } from "@deterministic-code/datasources";
|
|
2
2
|
import type { MysqlConnection } from "./connection.js";
|
|
3
3
|
export declare class MysqlTransaction implements ITransaction {
|
|
4
4
|
readonly connection: MysqlConnection;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IsolationLevel, } from "@deterministic-code/datasources";
|
|
2
|
+
export class MysqlTransaction {
|
|
3
|
+
connection;
|
|
4
|
+
isolation;
|
|
5
|
+
constructor(connection, isolation = IsolationLevel.ReadCommitted) {
|
|
6
|
+
this.connection = connection;
|
|
7
|
+
this.isolation = isolation;
|
|
8
|
+
}
|
|
9
|
+
async commit() {
|
|
10
|
+
await this.connection.require().commit();
|
|
11
|
+
}
|
|
12
|
+
async abort() {
|
|
13
|
+
await this.connection.require().rollback();
|
|
14
|
+
}
|
|
15
|
+
}
|
package/package.json
CHANGED
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deterministic-code/datasources-mysql",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"main": "./
|
|
6
|
-
"types": "./dist/index.d.
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.js",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
|
-
"types": "./dist/index.d.
|
|
10
|
-
"import": "./
|
|
11
|
-
"default": "./
|
|
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": {
|
|
22
|
-
"
|
|
23
|
-
"
|
|
21
|
+
"@deterministic-code/datasources": "^0.1.2",
|
|
22
|
+
"mysql2": "^3.14.0"
|
|
24
23
|
}
|
|
25
24
|
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { BulkUpdateStatementTextRenderer, type BulkUpdateStatement } from "@datasources/core";
|
|
2
|
-
|
|
3
|
-
export class MysqlBulkUpdateStatementTextRenderer extends BulkUpdateStatementTextRenderer {
|
|
4
|
-
override render = (statement: BulkUpdateStatement): string => {
|
|
5
|
-
const assigns = statement.set
|
|
6
|
-
.map((column) => `${statement.table}.${column} = data.${column}`)
|
|
7
|
-
.join(", ");
|
|
8
|
-
return `UPDATE ${statement.table} JOIN ${this.source(statement)} ON ${this.on(statement)} SET ${assigns}`;
|
|
9
|
-
};
|
|
10
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { CreateTableStatementTextRenderer, type Column } from "@datasources/core";
|
|
2
|
-
import { columnTypes } from "./columnTypes.ts";
|
|
3
|
-
|
|
4
|
-
export class MysqlCreateTableStatementRenderer extends CreateTableStatementTextRenderer {
|
|
5
|
-
protected typeName(column: Column): string {
|
|
6
|
-
return columnTypes[column.type] ?? column.type;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
protected identity(column: Column): string {
|
|
10
|
-
return column.identity ? " AUTO_INCREMENT" : "";
|
|
11
|
-
}
|
|
12
|
-
}
|
package/src/MysqlDriver.ts
DELETED
|
@@ -1,54 +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 { MysqlConnection } from "./connection.ts";
|
|
15
|
-
import { MysqlCommand } from "./command.ts";
|
|
16
|
-
import { MysqlTransaction } from "./transaction.ts";
|
|
17
|
-
import { MysqlRowTypeConverters } from "./converters/MysqlRowTypeConverters.ts";
|
|
18
|
-
import { MysqlStatementRenderer } from "./MysqlStatementRenderer.ts";
|
|
19
|
-
import { columnTypes } from "./columnTypes.ts";
|
|
20
|
-
|
|
21
|
-
export { columnTypes };
|
|
22
|
-
|
|
23
|
-
const statements = new StatementTextRenderer(t => new MysqlStatementRenderer(t));
|
|
24
|
-
|
|
25
|
-
export class MysqlDriver implements IDriver {
|
|
26
|
-
readonly statementRenderer = statements;
|
|
27
|
-
readonly information: Information = {
|
|
28
|
-
descriptions: [
|
|
29
|
-
"MySQL / MariaDB server driver.",
|
|
30
|
-
"Full connection, command, transaction, and repository support.",
|
|
31
|
-
],
|
|
32
|
-
overrides: [
|
|
33
|
-
"Overrides SelectInsertedIdStatement to SELECT LAST_INSERT_ID() AS {column}",
|
|
34
|
-
"Overrides CreateTableStatement identity to AUTO_INCREMENT",
|
|
35
|
-
"Overrides CreateTableStatement type mapping (int→INT, uuid→CHAR(36), string/datetime→TEXT, bool→TINYINT, decimal→DECIMAL(18,4), float→DOUBLE, binary→BLOB)",
|
|
36
|
-
],
|
|
37
|
-
changeLogs: [],
|
|
38
|
-
};
|
|
39
|
-
rowTypeConverters: Record<string, TypeConverter<Cell, Cell>> = MysqlRowTypeConverters;
|
|
40
|
-
columnType = (name: string): string =>
|
|
41
|
-
columnTypes[name] ??
|
|
42
|
-
(() => {
|
|
43
|
-
throw new DatasourceError(`Unknown mysql type "${name}"`);
|
|
44
|
-
})();
|
|
45
|
-
connection = (options?: DatasourceOptions): IConnection =>
|
|
46
|
-
MysqlConnection.from(options);
|
|
47
|
-
command = (connection: IConnection): ICommand =>
|
|
48
|
-
new MysqlCommand(connection as MysqlConnection, statements);
|
|
49
|
-
transaction = (
|
|
50
|
-
connection: IConnection,
|
|
51
|
-
isolation: IsolationLevel = "readCommitted",
|
|
52
|
-
): ITransaction =>
|
|
53
|
-
new MysqlTransaction(connection as MysqlConnection, isolation);
|
|
54
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BulkUpdateStatement,
|
|
3
|
-
ColumnDefault,
|
|
4
|
-
CreateTableStatement,
|
|
5
|
-
DefaultStatementTextRenderer,
|
|
6
|
-
ForeignKey,
|
|
7
|
-
SelectInsertedIdStatement,
|
|
8
|
-
NotNull,
|
|
9
|
-
PrimaryKey,
|
|
10
|
-
ReferentialAction,
|
|
11
|
-
SelectStatement,
|
|
12
|
-
StatementTextRenderer,
|
|
13
|
-
} from "@datasources/core";
|
|
14
|
-
import { describe, expect, it } from "vitest";
|
|
15
|
-
import { MysqlCreateTableStatementRenderer } from "./MysqlCreateTableStatementRenderer.ts";
|
|
16
|
-
import { MysqlStatementRenderer } from "./MysqlStatementRenderer.ts";
|
|
17
|
-
|
|
18
|
-
describe("MysqlStatementRenderer", () => {
|
|
19
|
-
const renderer = new StatementTextRenderer(t => new MysqlStatementRenderer(t));
|
|
20
|
-
|
|
21
|
-
it("renders inserted id and create table", () => {
|
|
22
|
-
expect(renderer.render(new SelectInsertedIdStatement("users", "id"))).toBe(
|
|
23
|
-
"SELECT LAST_INSERT_ID() AS id",
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
const create = new CreateTableStatement(
|
|
27
|
-
"orders",
|
|
28
|
-
[
|
|
29
|
-
{ name: "id", type: "INTEGER", default: new ColumnDefault("0", "df_id"), notNull: new NotNull("nn_id") },
|
|
30
|
-
{ name: "user_id", type: "INTEGER" },
|
|
31
|
-
],
|
|
32
|
-
[
|
|
33
|
-
new PrimaryKey("pk_orders", ["id"]),
|
|
34
|
-
new ForeignKey("fk_orders_user", ["user_id"], "users", ["id"], ReferentialAction.Cascade),
|
|
35
|
-
],
|
|
36
|
-
);
|
|
37
|
-
expect(renderer.render(create)).toBe(new MysqlCreateTableStatementRenderer().render(create));
|
|
38
|
-
expect(renderer.render(new SelectStatement({ table: "users", fields: ["id"] }))).toBe(
|
|
39
|
-
"SELECT id FROM users",
|
|
40
|
-
);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("renders type default and identity", () => {
|
|
44
|
-
const create = new CreateTableStatement("users", [
|
|
45
|
-
{ name: "id", type: "int", default: new ColumnDefault("0"), notNull: new NotNull(), identity: true },
|
|
46
|
-
]);
|
|
47
|
-
expect(renderer.render(create)).toBe(
|
|
48
|
-
"CREATE TABLE users (id INT AUTO_INCREMENT DEFAULT 0 NOT NULL)",
|
|
49
|
-
);
|
|
50
|
-
expect(DefaultStatementTextRenderer.instance.render(create)).toBe(
|
|
51
|
-
"CREATE TABLE users (id int DEFAULT 0 NOT NULL)",
|
|
52
|
-
);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("renders bulk update as join", () => {
|
|
56
|
-
const update = new BulkUpdateStatement("parents", ["label"], ["id"], [
|
|
57
|
-
{ fields: [{ name: "label", value: "a" }], ids: [{ name: "id", value: 1 }] },
|
|
58
|
-
{ fields: [{ name: "label", value: "b" }], ids: [{ name: "id", value: 2 }] },
|
|
59
|
-
]);
|
|
60
|
-
expect(renderer.render(update)).toBe(
|
|
61
|
-
"UPDATE parents JOIN (SELECT $label__0 AS label, $id__0 AS id UNION ALL SELECT $label__1 AS label, $id__1 AS id) AS data ON parents.id = data.id SET parents.label = data.label",
|
|
62
|
-
);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BulkUpdateStatement,
|
|
3
|
-
CreateTableStatement,
|
|
4
|
-
SelectInsertedIdStatement,
|
|
5
|
-
SelectInsertedIdStatementTextRenderer,
|
|
6
|
-
StatementRenderer,
|
|
7
|
-
type StatementTextRenderer,
|
|
8
|
-
} from "@datasources/core";
|
|
9
|
-
import { MysqlBulkUpdateStatementTextRenderer } from "./MysqlBulkUpdateStatementTextRenderer.ts";
|
|
10
|
-
import { MysqlCreateTableStatementRenderer } from "./MysqlCreateTableStatementRenderer.ts";
|
|
11
|
-
|
|
12
|
-
class MysqlSelectInsertedIdStatementTextRenderer extends SelectInsertedIdStatementTextRenderer {
|
|
13
|
-
override render(statement: SelectInsertedIdStatement): string {
|
|
14
|
-
return `SELECT LAST_INSERT_ID() AS ${statement.column}`;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export class MysqlStatementRenderer extends StatementRenderer {
|
|
19
|
-
constructor(text: StatementTextRenderer) {
|
|
20
|
-
super(text);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
protected override visitSelectInsertedId(inserted: SelectInsertedIdStatement): string {
|
|
24
|
-
return new MysqlSelectInsertedIdStatementTextRenderer().render(inserted);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
protected override visitCreateTable(create: CreateTableStatement): string {
|
|
28
|
-
return new MysqlCreateTableStatementRenderer().render(create);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
protected override visitBulkUpdate(update: BulkUpdateStatement): string {
|
|
32
|
-
return new MysqlBulkUpdateStatementTextRenderer().render(update);
|
|
33
|
-
}
|
|
34
|
-
}
|
package/src/bind.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { parametersToRecord, type Cell, type Parameter } from "@datasources/core";
|
|
2
|
-
import { reverse } from "./converters/MysqlRowTypeConverters.ts";
|
|
3
|
-
import type { Scalar } from "./scalar.ts";
|
|
4
|
-
|
|
5
|
-
const NAME = /\$([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
6
|
-
const TOKEN = /\$[A-Za-z_][A-Za-z0-9_]*|'[^']*'|"[^"]*"|`[^`]*`|\b[A-Za-z_][A-Za-z0-9_]*\b/g;
|
|
7
|
-
|
|
8
|
-
export const withoutReturning = (sql: string): string =>
|
|
9
|
-
sql.replace(/\s+RETURNING\b[^;]*$/i, "");
|
|
10
|
-
|
|
11
|
-
const quoteReserved = (sql: string): string =>
|
|
12
|
-
sql.replace(TOKEN, (token, offset: number) => {
|
|
13
|
-
const skip = token.startsWith("$") || token.startsWith("'") || token.startsWith("\"") || token.startsWith("`");
|
|
14
|
-
const reserved = !skip && token.toLowerCase() === "key"
|
|
15
|
-
&& !/\b(?:PRIMARY|FOREIGN|UNIQUE)\s+$/i.test(sql.slice(0, offset));
|
|
16
|
-
const mixed = !skip && /[A-Z]/.test(token) && /[a-z]/.test(token);
|
|
17
|
-
return reserved || mixed ? `\`${token}\`` : token;
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
export const toMysql = (sql: string): string =>
|
|
21
|
-
quoteReserved(withoutReturning(sql)).replace(NAME, (_match, name: string) => `:${name}`);
|
|
22
|
-
|
|
23
|
-
export const bindParameters = (
|
|
24
|
-
parameters?: Parameter[] | null,
|
|
25
|
-
): Record<string, Scalar> => {
|
|
26
|
-
const record = parametersToRecord(parameters);
|
|
27
|
-
const bound: Record<string, Scalar> = {};
|
|
28
|
-
for (const [name, value] of Object.entries(record))
|
|
29
|
-
bound[name] = reverse(value as Cell) as Scalar;
|
|
30
|
-
return bound;
|
|
31
|
-
};
|