metal-orm 1.1.26 → 1.1.27
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/index.cjs +783 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +154 -48
- package/dist/index.d.ts +154 -48
- package/dist/index.js +771 -75
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/ddl/dialects/index.ts +5 -6
- package/src/core/ddl/dialects/mssql-schema-dialect.ts +129 -126
- package/src/core/ddl/dialects/mysql-schema-dialect.ts +119 -111
- package/src/core/ddl/dialects/postgres-schema-dialect.ts +173 -164
- package/src/core/ddl/dialects/render-reference.test.ts +37 -57
- package/src/core/ddl/dialects/sqlite-schema-dialect.ts +110 -121
- package/src/core/ddl/schema-dialect-composer.ts +129 -0
- package/src/core/ddl/schema-dialect.ts +40 -27
- package/src/core/ddl/schema-diff.ts +119 -90
- package/src/core/driver/mssql-driver.ts +6 -8
- package/src/core/driver/mysql-driver.ts +6 -8
- package/src/core/driver/postgres-driver.ts +6 -8
- package/src/core/driver/sqlite-driver.ts +6 -8
- package/src/index.ts +12 -0
- package/src/core/ddl/dialects/base-schema-dialect.ts +0 -96
package/package.json
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
/** Re-exports for schema dialects. */
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
6
|
-
export { MSSqlSchemaDialect } from './mssql-schema-dialect.js';
|
|
1
|
+
/** Re-exports for composed schema dialects. */
|
|
2
|
+
export { PostgresSchemaDialect, createPostgresSchemaDialect } from './postgres-schema-dialect.js';
|
|
3
|
+
export { MySqlSchemaDialect, createMySqlSchemaDialect } from './mysql-schema-dialect.js';
|
|
4
|
+
export { SQLiteSchemaDialect, createSqliteSchemaDialect } from './sqlite-schema-dialect.js';
|
|
5
|
+
export { MSSqlSchemaDialect, createMssqlSchemaDialect } from './mssql-schema-dialect.js';
|
|
@@ -1,140 +1,143 @@
|
|
|
1
|
-
import { BaseSchemaDialect } from './base-schema-dialect.js';
|
|
2
1
|
import { deriveIndexName } from '../naming-strategy.js';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
createLiteralFormatter,
|
|
4
|
+
renderIndexColumns
|
|
5
|
+
} from '../sql-writing.js';
|
|
6
|
+
import {
|
|
7
|
+
composeSchemaDialect,
|
|
8
|
+
createStandardDropColumnCapability,
|
|
9
|
+
createStandardDropTableCapability,
|
|
10
|
+
type SchemaDialectServices
|
|
11
|
+
} from '../schema-dialect-composer.js';
|
|
12
|
+
import type { SchemaDialect } from '../schema-dialect.js';
|
|
13
|
+
import {
|
|
14
|
+
normalizeColumnType,
|
|
15
|
+
renderTypeWithArgs,
|
|
16
|
+
type ColumnDef
|
|
17
|
+
} from '../../../schema/column-types.js';
|
|
18
|
+
import type { IndexDef, TableDef } from '../../../schema/table.js';
|
|
19
|
+
import type { DatabaseTable } from '../schema-types.js';
|
|
8
20
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
name: DialectName = 'mssql';
|
|
21
|
+
const quoteIdentifier = (id: string): string => `[${id.replace(/]/g, ']]')}]`;
|
|
22
|
+
const literalFormatter = createLiteralFormatter({ booleanTrue: '1', booleanFalse: '0' });
|
|
12
23
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return this._literalFormatter;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
quoteIdentifier(id: string): string {
|
|
23
|
-
return `[${id.replace(/]/g, ']]')}]`;
|
|
24
|
-
}
|
|
24
|
+
const renderMssqlColumnType = (
|
|
25
|
+
column: ColumnDef,
|
|
26
|
+
services: SchemaDialectServices
|
|
27
|
+
): string => {
|
|
28
|
+
const override = column.dialectTypes?.[services.name] ?? column.dialectTypes?.default;
|
|
29
|
+
if (override) return renderTypeWithArgs(override, column.args);
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
const type = normalizeColumnType(column.type);
|
|
32
|
+
switch (type) {
|
|
33
|
+
case 'int':
|
|
34
|
+
case 'integer': return 'INT';
|
|
35
|
+
case 'bigint': return 'BIGINT';
|
|
36
|
+
case 'uuid': return 'UNIQUEIDENTIFIER';
|
|
37
|
+
case 'boolean': return 'BIT';
|
|
38
|
+
case 'json': return 'NVARCHAR(MAX)';
|
|
39
|
+
case 'decimal':
|
|
40
|
+
return column.args?.length ? `DECIMAL(${column.args[0]},${column.args[1] ?? 0})` : 'DECIMAL(18,0)';
|
|
41
|
+
case 'float':
|
|
42
|
+
case 'double': return 'FLOAT';
|
|
43
|
+
case 'timestamptz':
|
|
44
|
+
case 'timestamp':
|
|
45
|
+
case 'datetime': return 'DATETIME2';
|
|
46
|
+
case 'date': return 'DATE';
|
|
47
|
+
case 'varchar': return column.args?.length ? `NVARCHAR(${column.args[0]})` : 'NVARCHAR(255)';
|
|
48
|
+
case 'text': return 'NVARCHAR(MAX)';
|
|
49
|
+
case 'binary': {
|
|
50
|
+
const length = column.args?.[0];
|
|
51
|
+
return length !== undefined ? `BINARY(${length})` : 'BINARY(255)';
|
|
30
52
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
case 'integer':
|
|
36
|
-
return 'INT';
|
|
37
|
-
case 'bigint':
|
|
38
|
-
return 'BIGINT';
|
|
39
|
-
case 'uuid':
|
|
40
|
-
return 'UNIQUEIDENTIFIER';
|
|
41
|
-
case 'boolean':
|
|
42
|
-
return 'BIT';
|
|
43
|
-
case 'json':
|
|
44
|
-
return 'NVARCHAR(MAX)';
|
|
45
|
-
case 'decimal':
|
|
46
|
-
return column.args?.length ? `DECIMAL(${column.args[0]},${column.args[1] ?? 0})` : 'DECIMAL(18,0)';
|
|
47
|
-
case 'float':
|
|
48
|
-
case 'double':
|
|
49
|
-
return 'FLOAT';
|
|
50
|
-
case 'timestamptz':
|
|
51
|
-
case 'timestamp':
|
|
52
|
-
case 'datetime':
|
|
53
|
-
return 'DATETIME2';
|
|
54
|
-
case 'date':
|
|
55
|
-
return 'DATE';
|
|
56
|
-
case 'varchar':
|
|
57
|
-
return column.args?.length ? `NVARCHAR(${column.args[0]})` : 'NVARCHAR(255)';
|
|
58
|
-
case 'text':
|
|
59
|
-
return 'NVARCHAR(MAX)';
|
|
60
|
-
case 'binary': {
|
|
61
|
-
const length = column.args?.[0];
|
|
62
|
-
return length !== undefined ? `BINARY(${length})` : 'BINARY(255)';
|
|
63
|
-
}
|
|
64
|
-
case 'varbinary': {
|
|
65
|
-
const length = column.args?.[0];
|
|
66
|
-
if (typeof length === 'string' && length.toLowerCase() === 'max') {
|
|
67
|
-
return 'VARBINARY(MAX)';
|
|
68
|
-
}
|
|
69
|
-
return length !== undefined ? `VARBINARY(${length})` : 'VARBINARY(255)';
|
|
70
|
-
}
|
|
71
|
-
case 'blob':
|
|
72
|
-
case 'bytea':
|
|
73
|
-
return 'VARBINARY(MAX)';
|
|
74
|
-
case 'enum':
|
|
75
|
-
return 'NVARCHAR(255)';
|
|
76
|
-
case 'vector': {
|
|
77
|
-
const dim = column.vectorOptions?.dimensions ?? column.args?.[0] ?? 3;
|
|
78
|
-
const elemType = column.vectorOptions?.elementType;
|
|
79
|
-
return elemType ? `VECTOR(${dim}, ${elemType})` : `VECTOR(${dim})`;
|
|
80
|
-
}
|
|
81
|
-
case 'halfvec': {
|
|
82
|
-
const dim = column.vectorOptions?.dimensions ?? column.args?.[0] ?? 3;
|
|
83
|
-
return `VECTOR(${dim}, float16)`;
|
|
84
|
-
}
|
|
85
|
-
default:
|
|
86
|
-
return renderTypeWithArgs(String(type).toUpperCase(), column.args);
|
|
53
|
+
case 'varbinary': {
|
|
54
|
+
const length = column.args?.[0];
|
|
55
|
+
if (typeof length === 'string' && length.toLowerCase() === 'max') return 'VARBINARY(MAX)';
|
|
56
|
+
return length !== undefined ? `VARBINARY(${length})` : 'VARBINARY(255)';
|
|
87
57
|
}
|
|
58
|
+
case 'blob':
|
|
59
|
+
case 'bytea': return 'VARBINARY(MAX)';
|
|
60
|
+
case 'enum': return 'NVARCHAR(255)';
|
|
61
|
+
case 'vector': {
|
|
62
|
+
const dimensions = column.vectorOptions?.dimensions ?? column.args?.[0] ?? 3;
|
|
63
|
+
const elementType = column.vectorOptions?.elementType;
|
|
64
|
+
return elementType ? `VECTOR(${dimensions}, ${elementType})` : `VECTOR(${dimensions})`;
|
|
65
|
+
}
|
|
66
|
+
case 'halfvec': {
|
|
67
|
+
const dimensions = column.vectorOptions?.dimensions ?? column.args?.[0] ?? 3;
|
|
68
|
+
return `VECTOR(${dimensions}, float16)`;
|
|
69
|
+
}
|
|
70
|
+
default: return renderTypeWithArgs(String(type).toUpperCase(), column.args);
|
|
88
71
|
}
|
|
72
|
+
};
|
|
89
73
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
74
|
+
export const createMssqlSchemaDialect = (): SchemaDialect =>
|
|
75
|
+
composeSchemaDialect({
|
|
76
|
+
name: 'mssql',
|
|
77
|
+
quoteIdentifier,
|
|
78
|
+
literalFormatter,
|
|
79
|
+
renderColumnType: renderMssqlColumnType,
|
|
80
|
+
renderAutoIncrement: column => column.autoIncrement ? 'IDENTITY(1,1)' : undefined,
|
|
81
|
+
renderIndex(table, index, services) {
|
|
82
|
+
const name = index.name || deriveIndexName(table, index);
|
|
83
|
+
const columns = renderIndexColumns(services, index.columns);
|
|
84
|
+
const unique = index.unique ? 'UNIQUE ' : '';
|
|
85
|
+
const where = index.where ? ` WHERE ${index.where}` : '';
|
|
86
|
+
return `CREATE ${unique}INDEX ${services.quoteIdentifier(name)} ON ${services.formatTableName(table)} (${columns})${where};`;
|
|
87
|
+
},
|
|
88
|
+
supportsPartialIndexes: true,
|
|
89
|
+
mutations: services => ({
|
|
90
|
+
dropTable: createStandardDropTableCapability(services),
|
|
91
|
+
dropColumn: createStandardDropColumnCapability(services),
|
|
92
|
+
dropIndex: {
|
|
93
|
+
compile: (table, index) => [
|
|
94
|
+
`DROP INDEX ${services.quoteIdentifier(index)} ON ${services.formatTableName(table)};`
|
|
95
|
+
]
|
|
96
|
+
},
|
|
97
|
+
alterColumn: {
|
|
98
|
+
compile(table, column, actualColumn, diff) {
|
|
99
|
+
void actualColumn;
|
|
100
|
+
const statements: string[] = [];
|
|
101
|
+
if (diff.typeChanged || diff.nullabilityChanged) {
|
|
102
|
+
const nullability = column.notNull ? 'NOT NULL' : 'NULL';
|
|
103
|
+
statements.push(
|
|
104
|
+
`ALTER TABLE ${services.formatTableName(table)} ALTER COLUMN ${services.quoteIdentifier(column.name)} ${renderMssqlColumnType(column, services)} ${nullability};`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
return statements;
|
|
108
|
+
},
|
|
109
|
+
warning(table, column, actualColumn, diff) {
|
|
110
|
+
void table;
|
|
111
|
+
void column;
|
|
112
|
+
void actualColumn;
|
|
113
|
+
return diff.defaultChanged || diff.autoIncrementChanged
|
|
114
|
+
? 'Altering defaults or identity on MSSQL is not automated (requires dropping/adding default or identity constraints manually).'
|
|
115
|
+
: undefined;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
});
|
|
109
120
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
121
|
+
/** Ergonomic facade; DDL rendering itself is pure composition. */
|
|
122
|
+
export class MSSqlSchemaDialect implements SchemaDialect {
|
|
123
|
+
private readonly delegate = createMssqlSchemaDialect();
|
|
124
|
+
readonly name = this.delegate.name;
|
|
125
|
+
readonly mutations = this.delegate.mutations;
|
|
113
126
|
|
|
114
|
-
|
|
115
|
-
|
|
127
|
+
quoteIdentifier(id: string): string { return this.delegate.quoteIdentifier(id); }
|
|
128
|
+
formatTableName(table: TableDef | DatabaseTable): string { return this.delegate.formatTableName(table); }
|
|
129
|
+
renderColumnType(column: ColumnDef): string { return this.delegate.renderColumnType(column); }
|
|
130
|
+
renderDefault(value: unknown, column: ColumnDef): string { return this.delegate.renderDefault(value, column); }
|
|
131
|
+
renderAutoIncrement(column: ColumnDef, table: TableDef): string | undefined {
|
|
132
|
+
return this.delegate.renderAutoIncrement(column, table);
|
|
116
133
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
void _actual;
|
|
120
|
-
const stmts: string[] = [];
|
|
121
|
-
if (diff.typeChanged || diff.nullabilityChanged) {
|
|
122
|
-
const nullability = column.notNull ? 'NOT NULL' : 'NULL';
|
|
123
|
-
stmts.push(
|
|
124
|
-
`ALTER TABLE ${this.formatTableName(table)} ALTER COLUMN ${this.quoteIdentifier(column.name)} ${this.renderColumnType(column)} ${nullability};`
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
return stmts;
|
|
134
|
+
renderReference(ref: Parameters<SchemaDialect['renderReference']>[0], table: TableDef): string {
|
|
135
|
+
return this.delegate.renderReference(ref, table);
|
|
128
136
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (diff.defaultChanged || diff.autoIncrementChanged) {
|
|
135
|
-
return 'Altering defaults or identity on MSSQL is not automated (requires dropping/adding default or identity constraints manually).';
|
|
136
|
-
}
|
|
137
|
-
return undefined;
|
|
137
|
+
renderIndex(table: TableDef, index: IndexDef): string { return this.delegate.renderIndex(table, index); }
|
|
138
|
+
renderTableOptions(table: TableDef): string | undefined { return this.delegate.renderTableOptions(table); }
|
|
139
|
+
supportsPartialIndexes(): boolean { return this.delegate.supportsPartialIndexes(); }
|
|
140
|
+
preferInlinePkAutoincrement(column: ColumnDef, table: TableDef, pk: string[]): boolean {
|
|
141
|
+
return this.delegate.preferInlinePkAutoincrement(column, table, pk);
|
|
138
142
|
}
|
|
139
143
|
}
|
|
140
|
-
|
|
@@ -1,125 +1,133 @@
|
|
|
1
|
-
import { BaseSchemaDialect } from './base-schema-dialect.js';
|
|
2
1
|
import { deriveIndexName } from '../naming-strategy.js';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
import {
|
|
3
|
+
createLiteralFormatter,
|
|
4
|
+
escapeSqlString,
|
|
5
|
+
renderIndexColumns
|
|
6
|
+
} from '../sql-writing.js';
|
|
7
|
+
import {
|
|
8
|
+
composeSchemaDialect,
|
|
9
|
+
createStandardDropColumnCapability,
|
|
10
|
+
createStandardDropTableCapability,
|
|
11
|
+
type SchemaDialectServices
|
|
12
|
+
} from '../schema-dialect-composer.js';
|
|
13
|
+
import type { SchemaDialect } from '../schema-dialect.js';
|
|
7
14
|
import { renderColumnDefinition } from '../schema-generator.js';
|
|
8
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
normalizeColumnType,
|
|
17
|
+
renderTypeWithArgs,
|
|
18
|
+
type ColumnDef
|
|
19
|
+
} from '../../../schema/column-types.js';
|
|
20
|
+
import type { IndexDef, TableDef } from '../../../schema/table.js';
|
|
21
|
+
import type { DatabaseTable } from '../schema-types.js';
|
|
9
22
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
name: DialectName = 'mysql';
|
|
23
|
+
const quoteIdentifier = (id: string): string => `\`${id}\``;
|
|
24
|
+
const literalFormatter = createLiteralFormatter({ booleanTrue: '1', booleanFalse: '0' });
|
|
13
25
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return this._literalFormatter;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
quoteIdentifier(id: string): string {
|
|
24
|
-
return `\`${id}\``;
|
|
25
|
-
}
|
|
26
|
+
const renderMySqlColumnType = (
|
|
27
|
+
column: ColumnDef,
|
|
28
|
+
services: SchemaDialectServices
|
|
29
|
+
): string => {
|
|
30
|
+
const override = column.dialectTypes?.[services.name] ?? column.dialectTypes?.default;
|
|
31
|
+
if (override) return renderTypeWithArgs(override, column.args);
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
const type = normalizeColumnType(column.type);
|
|
34
|
+
switch (type) {
|
|
35
|
+
case 'int':
|
|
36
|
+
case 'integer': return 'INT';
|
|
37
|
+
case 'bigint': return 'BIGINT';
|
|
38
|
+
case 'uuid': return 'CHAR(36)';
|
|
39
|
+
case 'boolean': return 'TINYINT(1)';
|
|
40
|
+
case 'json': return 'JSON';
|
|
41
|
+
case 'decimal':
|
|
42
|
+
return column.args?.length ? `DECIMAL(${column.args[0]},${column.args[1] ?? 0})` : 'DECIMAL';
|
|
43
|
+
case 'float': return column.args?.length ? `FLOAT(${column.args[0]})` : 'FLOAT';
|
|
44
|
+
case 'double': return 'DOUBLE';
|
|
45
|
+
case 'timestamptz':
|
|
46
|
+
case 'timestamp': return 'TIMESTAMP';
|
|
47
|
+
case 'datetime': return 'DATETIME';
|
|
48
|
+
case 'date': return 'DATE';
|
|
49
|
+
case 'varchar': return column.args?.length ? `VARCHAR(${column.args[0]})` : 'VARCHAR(255)';
|
|
50
|
+
case 'text': return 'TEXT';
|
|
51
|
+
case 'binary': return column.args?.length ? `BINARY(${column.args[0]})` : 'BINARY(255)';
|
|
52
|
+
case 'varbinary': return column.args?.length ? `VARBINARY(${column.args[0]})` : 'VARBINARY(255)';
|
|
53
|
+
case 'blob':
|
|
54
|
+
case 'bytea': return 'BLOB';
|
|
55
|
+
case 'enum':
|
|
56
|
+
return column.args?.length
|
|
57
|
+
? `ENUM(${column.args.map(value => `'${escapeSqlString(String(value))}'`).join(',')})`
|
|
58
|
+
: 'ENUM';
|
|
59
|
+
case 'vector':
|
|
60
|
+
case 'halfvec': {
|
|
61
|
+
const dimensions = column.vectorOptions?.dimensions ?? column.args?.[0] ?? 3;
|
|
62
|
+
return `VECTOR(${dimensions})`;
|
|
31
63
|
}
|
|
32
|
-
|
|
33
|
-
const type = normalizeColumnType(column.type);
|
|
34
|
-
switch (type) {
|
|
35
|
-
case 'int':
|
|
36
|
-
case 'integer':
|
|
37
|
-
return 'INT';
|
|
38
|
-
case 'bigint':
|
|
39
|
-
return 'BIGINT';
|
|
40
|
-
case 'uuid':
|
|
41
|
-
return 'CHAR(36)';
|
|
42
|
-
case 'boolean':
|
|
43
|
-
return 'TINYINT(1)';
|
|
44
|
-
case 'json':
|
|
45
|
-
return 'JSON';
|
|
46
|
-
case 'decimal':
|
|
47
|
-
return column.args?.length ? `DECIMAL(${column.args[0]},${column.args[1] ?? 0})` : 'DECIMAL';
|
|
48
|
-
case 'float':
|
|
49
|
-
return column.args?.length ? `FLOAT(${column.args[0]})` : 'FLOAT';
|
|
50
|
-
case 'double':
|
|
51
|
-
return 'DOUBLE';
|
|
52
|
-
case 'timestamptz':
|
|
53
|
-
case 'timestamp':
|
|
54
|
-
return 'TIMESTAMP';
|
|
55
|
-
case 'datetime':
|
|
56
|
-
return 'DATETIME';
|
|
57
|
-
case 'date':
|
|
58
|
-
return 'DATE';
|
|
59
|
-
case 'varchar':
|
|
60
|
-
return column.args?.length ? `VARCHAR(${column.args[0]})` : 'VARCHAR(255)';
|
|
61
|
-
case 'text':
|
|
62
|
-
return 'TEXT';
|
|
63
|
-
case 'binary':
|
|
64
|
-
return column.args?.length ? `BINARY(${column.args[0]})` : 'BINARY(255)';
|
|
65
|
-
case 'varbinary':
|
|
66
|
-
return column.args?.length ? `VARBINARY(${column.args[0]})` : 'VARBINARY(255)';
|
|
67
|
-
case 'blob':
|
|
68
|
-
case 'bytea':
|
|
69
|
-
return 'BLOB';
|
|
70
|
-
case 'enum':
|
|
71
|
-
return column.args && Array.isArray(column.args) && column.args.length
|
|
72
|
-
? `ENUM(${column.args.map((v: string) => `'${escapeSqlString(v)}'`).join(',')})`
|
|
73
|
-
: 'ENUM';
|
|
74
|
-
case 'vector':
|
|
75
|
-
case 'halfvec': {
|
|
76
|
-
const dim = column.vectorOptions?.dimensions ?? column.args?.[0] ?? 3;
|
|
77
|
-
return `VECTOR(${dim})`;
|
|
78
|
-
}
|
|
79
|
-
default:
|
|
80
|
-
return renderTypeWithArgs(String(type).toUpperCase(), column.args);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
renderDefault(value: unknown): string {
|
|
85
|
-
return this.literalFormatter.formatLiteral(value);
|
|
64
|
+
default: return renderTypeWithArgs(String(type).toUpperCase(), column.args);
|
|
86
65
|
}
|
|
66
|
+
};
|
|
87
67
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
68
|
+
export const createMySqlSchemaDialect = (): SchemaDialect => {
|
|
69
|
+
let dialect!: SchemaDialect;
|
|
70
|
+
dialect = composeSchemaDialect({
|
|
71
|
+
name: 'mysql',
|
|
72
|
+
quoteIdentifier,
|
|
73
|
+
literalFormatter,
|
|
74
|
+
renderColumnType: renderMySqlColumnType,
|
|
75
|
+
renderAutoIncrement: column => column.autoIncrement ? 'AUTO_INCREMENT' : undefined,
|
|
76
|
+
renderIndex(table, index, services) {
|
|
77
|
+
if (index.where) throw new Error('MySQL does not support partial/filtered indexes');
|
|
78
|
+
const name = index.name || deriveIndexName(table, index);
|
|
79
|
+
const columns = renderIndexColumns(services, index.columns);
|
|
80
|
+
const unique = index.unique ? 'UNIQUE ' : '';
|
|
81
|
+
return `CREATE ${unique}INDEX ${services.quoteIdentifier(name)} ON ${services.formatTableName(table)} (${columns});`;
|
|
82
|
+
},
|
|
83
|
+
renderTableOptions(table) {
|
|
84
|
+
const parts: string[] = [];
|
|
85
|
+
if (table.engine) parts.push(`ENGINE=${table.engine}`);
|
|
86
|
+
if (table.charset) parts.push(`DEFAULT CHARSET=${table.charset}`);
|
|
87
|
+
if (table.collation) parts.push(`COLLATE=${table.collation}`);
|
|
88
|
+
return parts.length ? parts.join(' ') : undefined;
|
|
89
|
+
},
|
|
90
|
+
mutations: services => ({
|
|
91
|
+
dropTable: createStandardDropTableCapability(services),
|
|
92
|
+
dropColumn: createStandardDropColumnCapability(services),
|
|
93
|
+
dropIndex: {
|
|
94
|
+
compile: (table, index) => [
|
|
95
|
+
`DROP INDEX ${services.quoteIdentifier(index)} ON ${services.formatTableName(table)};`
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
alterColumn: {
|
|
99
|
+
compile(table, column, actualColumn, diff) {
|
|
100
|
+
void actualColumn;
|
|
101
|
+
void diff;
|
|
102
|
+
const rendered = renderColumnDefinition(table, column, dialect);
|
|
103
|
+
return [`ALTER TABLE ${services.formatTableName(table)} MODIFY COLUMN ${rendered.sql};`];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
});
|
|
108
|
+
return dialect;
|
|
109
|
+
};
|
|
101
110
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return parts.length ? parts.join(' ') : undefined;
|
|
108
|
-
}
|
|
111
|
+
/** Ergonomic facade; DDL rendering itself is pure composition. */
|
|
112
|
+
export class MySqlSchemaDialect implements SchemaDialect {
|
|
113
|
+
private readonly delegate = createMySqlSchemaDialect();
|
|
114
|
+
readonly name = this.delegate.name;
|
|
115
|
+
readonly mutations = this.delegate.mutations;
|
|
109
116
|
|
|
110
|
-
|
|
111
|
-
|
|
117
|
+
quoteIdentifier(id: string): string { return this.delegate.quoteIdentifier(id); }
|
|
118
|
+
formatTableName(table: TableDef | DatabaseTable): string { return this.delegate.formatTableName(table); }
|
|
119
|
+
renderColumnType(column: ColumnDef): string { return this.delegate.renderColumnType(column); }
|
|
120
|
+
renderDefault(value: unknown, column: ColumnDef): string { return this.delegate.renderDefault(value, column); }
|
|
121
|
+
renderAutoIncrement(column: ColumnDef, table: TableDef): string | undefined {
|
|
122
|
+
return this.delegate.renderAutoIncrement(column, table);
|
|
112
123
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return [`DROP INDEX ${this.quoteIdentifier(index)} ON ${this.formatTableName(table)};`];
|
|
124
|
+
renderReference(ref: Parameters<SchemaDialect['renderReference']>[0], table: TableDef): string {
|
|
125
|
+
return this.delegate.renderReference(ref, table);
|
|
116
126
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return [`ALTER TABLE ${this.formatTableName(table)} MODIFY COLUMN ${rendered.sql};`];
|
|
127
|
+
renderIndex(table: TableDef, index: IndexDef): string { return this.delegate.renderIndex(table, index); }
|
|
128
|
+
renderTableOptions(table: TableDef): string | undefined { return this.delegate.renderTableOptions(table); }
|
|
129
|
+
supportsPartialIndexes(): boolean { return this.delegate.supportsPartialIndexes(); }
|
|
130
|
+
preferInlinePkAutoincrement(column: ColumnDef, table: TableDef, pk: string[]): boolean {
|
|
131
|
+
return this.delegate.preferInlinePkAutoincrement(column, table, pk);
|
|
123
132
|
}
|
|
124
133
|
}
|
|
125
|
-
|