metal-orm 1.0.45 → 1.0.47
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 +1092 -323
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +99 -9
- package/dist/index.d.ts +99 -9
- package/dist/index.js +1087 -323
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/generate-entities.mjs +36 -9
- package/src/codegen/typescript.ts +22 -10
- package/src/core/ast/adapters.ts +2 -1
- package/src/core/ast/expression-builders.ts +13 -0
- package/src/core/ast/expression-nodes.ts +25 -5
- package/src/core/ast/expression-visitor.ts +5 -0
- package/src/core/ast/query.ts +9 -1
- package/src/core/ddl/dialects/base-schema-dialect.ts +2 -1
- package/src/core/ddl/dialects/mssql-schema-dialect.ts +10 -23
- package/src/core/ddl/dialects/mysql-schema-dialect.ts +10 -24
- package/src/core/ddl/dialects/postgres-schema-dialect.ts +10 -23
- package/src/core/ddl/dialects/render-reference.test.ts +2 -1
- package/src/core/ddl/dialects/sqlite-schema-dialect.ts +9 -23
- package/src/core/ddl/introspect/catalogs/index.ts +4 -1
- package/src/core/ddl/introspect/catalogs/mssql.ts +126 -0
- package/src/core/ddl/introspect/catalogs/mysql.ts +89 -0
- package/src/core/ddl/introspect/catalogs/postgres.ts +2 -1
- package/src/core/ddl/introspect/catalogs/sqlite.ts +47 -0
- package/src/core/ddl/introspect/functions/mssql.ts +84 -0
- package/src/core/ddl/introspect/mssql.ts +471 -194
- package/src/core/ddl/introspect/mysql.ts +336 -125
- package/src/core/ddl/introspect/postgres.ts +45 -5
- package/src/core/ddl/introspect/run-select.ts +3 -8
- package/src/core/ddl/introspect/sqlite.ts +113 -59
- package/src/core/ddl/schema-dialect.ts +2 -1
- package/src/core/ddl/schema-diff.ts +2 -1
- package/src/core/ddl/schema-generator.ts +2 -1
- package/src/core/ddl/schema-types.ts +3 -1
- package/src/core/ddl/sql-writing.ts +2 -1
- package/src/core/dialect/abstract.ts +12 -1
- package/src/core/dialect/mssql/index.ts +4 -10
- package/src/core/functions/datetime.ts +2 -1
- package/src/core/functions/numeric.ts +2 -1
- package/src/core/functions/text.ts +2 -1
- package/src/decorators/{column.ts → column-decorator.ts} +4 -1
- package/src/decorators/index.ts +1 -1
- package/src/index.ts +2 -1
- package/src/orm/entity-metadata.ts +2 -1
- package/src/orm/lazy-batch.ts +2 -1
- package/src/orm/orm-session.ts +2 -1
- package/src/query-builder/column-selector.ts +2 -1
- package/src/query-builder/delete.ts +2 -1
- package/src/query-builder/insert.ts +2 -1
- package/src/query-builder/query-ast-service.ts +4 -3
- package/src/query-builder/relation-projection-helper.ts +2 -1
- package/src/query-builder/relation-service.ts +2 -1
- package/src/query-builder/select/predicate-facet.ts +2 -1
- package/src/query-builder/select/projection-facet.ts +2 -1
- package/src/query-builder/select-helpers.ts +2 -1
- package/src/query-builder/select-query-state.ts +2 -0
- package/src/query-builder/select.ts +2 -1
- package/src/query-builder/update.ts +2 -1
- package/src/schema/{column.ts → column-types.ts} +317 -290
- package/src/schema/table-guards.ts +1 -1
- package/src/schema/table.ts +1 -1
- package/src/schema/types.ts +10 -8
package/package.json
CHANGED
|
@@ -267,6 +267,7 @@ const renderColumnExpression = (column, tablePk) => {
|
|
|
267
267
|
};
|
|
268
268
|
|
|
269
269
|
const mapRelations = tables => {
|
|
270
|
+
const normalizeName = name => (typeof name === 'string' && name.includes('.') ? name.split('.').pop() : name);
|
|
270
271
|
const relationMap = new Map();
|
|
271
272
|
const relationKeys = new Map();
|
|
272
273
|
const fkIndex = new Map();
|
|
@@ -283,12 +284,15 @@ const mapRelations = tables => {
|
|
|
283
284
|
}
|
|
284
285
|
}
|
|
285
286
|
|
|
286
|
-
const findTable = name =>
|
|
287
|
+
const findTable = name => {
|
|
288
|
+
const norm = normalizeName(name);
|
|
289
|
+
return tables.find(t => t.name === name || t.name === norm);
|
|
290
|
+
};
|
|
287
291
|
|
|
288
292
|
const pivotTables = new Set();
|
|
289
293
|
for (const table of tables) {
|
|
290
294
|
const fkCols = fkIndex.get(table.name) || [];
|
|
291
|
-
const distinctTargets = Array.from(new Set(fkCols.map(c => c.references.table)));
|
|
295
|
+
const distinctTargets = Array.from(new Set(fkCols.map(c => normalizeName(c.references.table))));
|
|
292
296
|
if (fkCols.length === 2 && distinctTargets.length === 2) {
|
|
293
297
|
const [a, b] = fkCols;
|
|
294
298
|
pivotTables.add(table.name);
|
|
@@ -329,8 +333,11 @@ const mapRelations = tables => {
|
|
|
329
333
|
const fkCols = fkIndex.get(table.name) || [];
|
|
330
334
|
for (const fk of fkCols) {
|
|
331
335
|
const targetTable = fk.references.table;
|
|
336
|
+
const targetKey = normalizeName(targetTable);
|
|
332
337
|
const belongsKey = relationKeys.get(table.name);
|
|
333
|
-
const hasManyKey = relationKeys.get(
|
|
338
|
+
const hasManyKey = targetKey ? relationKeys.get(targetKey) : undefined;
|
|
339
|
+
|
|
340
|
+
if (!belongsKey || !hasManyKey) continue;
|
|
334
341
|
|
|
335
342
|
const belongsProp = deriveBelongsToName(fk.name, targetTable);
|
|
336
343
|
if (!belongsKey.has(belongsProp)) {
|
|
@@ -346,7 +353,7 @@ const mapRelations = tables => {
|
|
|
346
353
|
const hasManyProp = deriveHasManyName(table.name);
|
|
347
354
|
if (!hasManyKey.has(hasManyProp)) {
|
|
348
355
|
hasManyKey.add(hasManyProp);
|
|
349
|
-
relationMap.get(
|
|
356
|
+
relationMap.get(targetKey)?.push({
|
|
350
357
|
kind: 'hasMany',
|
|
351
358
|
property: hasManyProp,
|
|
352
359
|
target: table.name,
|
|
@@ -362,12 +369,32 @@ const mapRelations = tables => {
|
|
|
362
369
|
const renderEntityFile = (schema, options) => {
|
|
363
370
|
const tables = schema.tables.map(t => ({
|
|
364
371
|
name: t.name,
|
|
372
|
+
schema: t.schema,
|
|
365
373
|
columns: t.columns,
|
|
366
374
|
primaryKey: t.primaryKey || []
|
|
367
375
|
}));
|
|
368
376
|
|
|
369
377
|
const classNames = new Map();
|
|
370
|
-
tables.forEach(t =>
|
|
378
|
+
tables.forEach(t => {
|
|
379
|
+
const className = deriveClassName(t.name);
|
|
380
|
+
classNames.set(t.name, className);
|
|
381
|
+
if (t.schema) {
|
|
382
|
+
const qualified = `${t.schema}.${t.name}`;
|
|
383
|
+
if (!classNames.has(qualified)) {
|
|
384
|
+
classNames.set(qualified, className);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
const resolveClassName = target => {
|
|
390
|
+
if (!target) return undefined;
|
|
391
|
+
if (classNames.has(target)) return classNames.get(target);
|
|
392
|
+
const fallback = target.split('.').pop();
|
|
393
|
+
if (fallback && classNames.has(fallback)) {
|
|
394
|
+
return classNames.get(fallback);
|
|
395
|
+
}
|
|
396
|
+
return undefined;
|
|
397
|
+
};
|
|
371
398
|
|
|
372
399
|
const relations = mapRelations(tables);
|
|
373
400
|
|
|
@@ -469,7 +496,7 @@ const renderEntityFile = (schema, options) => {
|
|
|
469
496
|
|
|
470
497
|
const rels = relations.get(table.name) || [];
|
|
471
498
|
for (const rel of rels) {
|
|
472
|
-
const targetClass =
|
|
499
|
+
const targetClass = resolveClassName(rel.target);
|
|
473
500
|
if (!targetClass) continue;
|
|
474
501
|
switch (rel.kind) {
|
|
475
502
|
case 'belongsTo':
|
|
@@ -487,10 +514,10 @@ const renderEntityFile = (schema, options) => {
|
|
|
487
514
|
lines.push('');
|
|
488
515
|
break;
|
|
489
516
|
case 'belongsToMany':
|
|
517
|
+
const pivotClass = resolveClassName(rel.pivotTable);
|
|
518
|
+
if (!pivotClass) break;
|
|
490
519
|
lines.push(
|
|
491
|
-
` @BelongsToMany({ target: () => ${targetClass}, pivotTable: () => ${
|
|
492
|
-
rel.pivotTable
|
|
493
|
-
)}, pivotForeignKeyToRoot: '${escapeJsString(rel.pivotForeignKeyToRoot)}', pivotForeignKeyToTarget: '${escapeJsString(rel.pivotForeignKeyToTarget)}' })`
|
|
520
|
+
` @BelongsToMany({ target: () => ${targetClass}, pivotTable: () => ${pivotClass}, pivotForeignKeyToRoot: '${escapeJsString(rel.pivotForeignKeyToRoot)}', pivotForeignKeyToTarget: '${escapeJsString(rel.pivotForeignKeyToTarget)}' })`
|
|
494
521
|
);
|
|
495
522
|
lines.push(` ${rel.property}!: ManyToManyCollection<${targetClass}>;`);
|
|
496
523
|
lines.push('');
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
LiteralNode,
|
|
18
18
|
FunctionNode,
|
|
19
19
|
AliasRefNode,
|
|
20
|
+
CastExpressionNode,
|
|
20
21
|
ExpressionVisitor,
|
|
21
22
|
OperandVisitor,
|
|
22
23
|
visitExpression,
|
|
@@ -41,7 +42,8 @@ type SelectionColumn =
|
|
|
41
42
|
| FunctionNode
|
|
42
43
|
| ScalarSubqueryNode
|
|
43
44
|
| CaseExpressionNode
|
|
44
|
-
| WindowFunctionNode
|
|
45
|
+
| WindowFunctionNode
|
|
46
|
+
| CastExpressionNode;
|
|
45
47
|
|
|
46
48
|
export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVisitor<string> {
|
|
47
49
|
constructor(private namingStrategy: NamingStrategy = new DefaultNamingStrategy()) { }
|
|
@@ -181,15 +183,16 @@ export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVi
|
|
|
181
183
|
return `${this.namingStrategy.tableToSymbol(term.table)}.${term.name}`;
|
|
182
184
|
case 'AliasRef':
|
|
183
185
|
return this.visitAliasRef(term);
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
186
|
+
case 'Literal':
|
|
187
|
+
case 'Function':
|
|
188
|
+
case 'JsonPath':
|
|
189
|
+
case 'ScalarSubquery':
|
|
190
|
+
case 'CaseExpression':
|
|
191
|
+
case 'WindowFunction':
|
|
192
|
+
case 'Cast':
|
|
193
|
+
return this.printOperand(term);
|
|
194
|
+
default:
|
|
195
|
+
return this.printExpression(term);
|
|
193
196
|
}
|
|
194
197
|
}
|
|
195
198
|
|
|
@@ -263,6 +266,10 @@ export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVi
|
|
|
263
266
|
return this.printWindowFunctionOperand(node);
|
|
264
267
|
}
|
|
265
268
|
|
|
269
|
+
public visitCast(node: CastExpressionNode): string {
|
|
270
|
+
return this.printCastOperand(node);
|
|
271
|
+
}
|
|
272
|
+
|
|
266
273
|
public visitAliasRef(node: AliasRefNode): string {
|
|
267
274
|
return `aliasRef('${node.name}')`;
|
|
268
275
|
}
|
|
@@ -454,6 +461,11 @@ export class TypeScriptGenerator implements ExpressionVisitor<string>, OperandVi
|
|
|
454
461
|
return result;
|
|
455
462
|
}
|
|
456
463
|
|
|
464
|
+
private printCastOperand(node: CastExpressionNode): string {
|
|
465
|
+
const typeLiteral = node.castType.replace(/'/g, "\\'");
|
|
466
|
+
return `cast(${this.printOperand(node.expression)}, '${typeLiteral}')`;
|
|
467
|
+
}
|
|
468
|
+
|
|
457
469
|
/**
|
|
458
470
|
* Converts method chain lines to inline format
|
|
459
471
|
* @param lines - Method chain lines
|
package/src/core/ast/adapters.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ColumnDef } from '../../schema/column.js';
|
|
1
|
+
import { ColumnDef } from '../../schema/column-types.js';
|
|
2
2
|
import { TableDef } from '../../schema/table.js';
|
|
3
3
|
import { ColumnRef, TableRef } from './types.js';
|
|
4
4
|
|
|
@@ -25,3 +25,4 @@ export const toTableRef = (table: TableRef | TableDef): TableRef => ({
|
|
|
25
25
|
schema: table.schema,
|
|
26
26
|
alias: hasAlias(table) ? table.alias : undefined
|
|
27
27
|
});
|
|
28
|
+
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
JsonPathNode,
|
|
8
8
|
OperandNode,
|
|
9
9
|
CaseExpressionNode,
|
|
10
|
+
CastExpressionNode,
|
|
10
11
|
BinaryExpressionNode,
|
|
11
12
|
ExpressionNode,
|
|
12
13
|
LogicalExpressionNode,
|
|
@@ -407,6 +408,18 @@ export const caseWhen = (
|
|
|
407
408
|
else: elseValue !== undefined ? toOperand(elseValue) : undefined
|
|
408
409
|
});
|
|
409
410
|
|
|
411
|
+
/**
|
|
412
|
+
* Builds a CAST expression node for casting values to SQL types.
|
|
413
|
+
*/
|
|
414
|
+
export const cast = (
|
|
415
|
+
expression: OperandNode | ColumnRef | string | number | boolean | null,
|
|
416
|
+
castType: string
|
|
417
|
+
): CastExpressionNode => ({
|
|
418
|
+
type: 'Cast',
|
|
419
|
+
expression: toOperand(expression),
|
|
420
|
+
castType
|
|
421
|
+
});
|
|
422
|
+
|
|
410
423
|
/**
|
|
411
424
|
* Creates an EXISTS expression
|
|
412
425
|
* @param subquery - Subquery to check for existence
|
|
@@ -95,6 +95,19 @@ export interface CaseExpressionNode {
|
|
|
95
95
|
alias?: string;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* AST node representing a CAST expression (CAST(value AS type)).
|
|
100
|
+
*/
|
|
101
|
+
export interface CastExpressionNode {
|
|
102
|
+
type: 'Cast';
|
|
103
|
+
/** Expression being cast */
|
|
104
|
+
expression: OperandNode;
|
|
105
|
+
/** SQL type literal, e.g. "varchar(255)" */
|
|
106
|
+
castType: string;
|
|
107
|
+
/** Optional alias for the result */
|
|
108
|
+
alias?: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
98
111
|
/**
|
|
99
112
|
* AST node representing a window function
|
|
100
113
|
*/
|
|
@@ -133,7 +146,9 @@ export type OperandNode =
|
|
|
133
146
|
| JsonPathNode
|
|
134
147
|
| ScalarSubqueryNode
|
|
135
148
|
| CaseExpressionNode
|
|
136
|
-
|
|
|
149
|
+
| CastExpressionNode
|
|
150
|
+
| WindowFunctionNode
|
|
151
|
+
| ArithmeticExpressionNode;
|
|
137
152
|
|
|
138
153
|
const operandTypes = new Set<OperandNode['type']>([
|
|
139
154
|
'AliasRef',
|
|
@@ -143,7 +158,9 @@ const operandTypes = new Set<OperandNode['type']>([
|
|
|
143
158
|
'JsonPath',
|
|
144
159
|
'ScalarSubquery',
|
|
145
160
|
'CaseExpression',
|
|
146
|
-
'
|
|
161
|
+
'Cast',
|
|
162
|
+
'WindowFunction',
|
|
163
|
+
'ArithmeticExpression'
|
|
147
164
|
]);
|
|
148
165
|
|
|
149
166
|
const hasTypeProperty = (value: unknown): value is { type?: string } =>
|
|
@@ -158,12 +175,15 @@ export const isFunctionNode = (node: unknown): node is FunctionNode =>
|
|
|
158
175
|
isOperandNode(node) && node.type === 'Function';
|
|
159
176
|
export const isCaseExpressionNode = (node: unknown): node is CaseExpressionNode =>
|
|
160
177
|
isOperandNode(node) && node.type === 'CaseExpression';
|
|
178
|
+
|
|
179
|
+
export const isCastExpressionNode = (node: unknown): node is CastExpressionNode =>
|
|
180
|
+
isOperandNode(node) && node.type === 'Cast';
|
|
161
181
|
export const isWindowFunctionNode = (node: unknown): node is WindowFunctionNode =>
|
|
162
182
|
isOperandNode(node) && node.type === 'WindowFunction';
|
|
163
183
|
export const isExpressionSelectionNode = (
|
|
164
|
-
node: ColumnRef | FunctionNode | CaseExpressionNode | WindowFunctionNode
|
|
165
|
-
): node is FunctionNode | CaseExpressionNode | WindowFunctionNode =>
|
|
166
|
-
isFunctionNode(node) || isCaseExpressionNode(node) || isWindowFunctionNode(node);
|
|
184
|
+
node: ColumnRef | FunctionNode | CaseExpressionNode | CastExpressionNode | WindowFunctionNode
|
|
185
|
+
): node is FunctionNode | CaseExpressionNode | CastExpressionNode | WindowFunctionNode =>
|
|
186
|
+
isFunctionNode(node) || isCaseExpressionNode(node) || isCastExpressionNode(node) || isWindowFunctionNode(node);
|
|
167
187
|
|
|
168
188
|
/**
|
|
169
189
|
* AST node representing a binary expression (e.g., column = value)
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
JsonPathNode,
|
|
15
15
|
ScalarSubqueryNode,
|
|
16
16
|
CaseExpressionNode,
|
|
17
|
+
CastExpressionNode,
|
|
17
18
|
WindowFunctionNode,
|
|
18
19
|
AliasRefNode
|
|
19
20
|
} from './expression-nodes.js';
|
|
@@ -42,6 +43,7 @@ export interface OperandVisitor<R> {
|
|
|
42
43
|
visitJsonPath?(node: JsonPathNode): R;
|
|
43
44
|
visitScalarSubquery?(node: ScalarSubqueryNode): R;
|
|
44
45
|
visitCaseExpression?(node: CaseExpressionNode): R;
|
|
46
|
+
visitCast?(node: CastExpressionNode): R;
|
|
45
47
|
visitWindowFunction?(node: WindowFunctionNode): R;
|
|
46
48
|
visitAliasRef?(node: AliasRefNode): R;
|
|
47
49
|
otherwise?(node: OperandNode): R;
|
|
@@ -196,6 +198,9 @@ export const visitOperand = <R>(node: OperandNode, visitor: OperandVisitor<R>):
|
|
|
196
198
|
case 'AliasRef':
|
|
197
199
|
if (visitor.visitAliasRef) return visitor.visitAliasRef(node);
|
|
198
200
|
break;
|
|
201
|
+
case 'Cast':
|
|
202
|
+
if (visitor.visitCast) return visitor.visitCast(node);
|
|
203
|
+
break;
|
|
199
204
|
default:
|
|
200
205
|
break;
|
|
201
206
|
}
|
package/src/core/ast/query.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AliasRefNode,
|
|
3
3
|
CaseExpressionNode,
|
|
4
|
+
CastExpressionNode,
|
|
4
5
|
ColumnNode,
|
|
5
6
|
ExpressionNode,
|
|
6
7
|
FunctionNode,
|
|
@@ -121,7 +122,14 @@ export interface SelectQueryNode {
|
|
|
121
122
|
/** FROM clause table (either a Table or a FunctionTable) */
|
|
122
123
|
from: TableSourceNode;
|
|
123
124
|
/** SELECT clause columns */
|
|
124
|
-
columns: (
|
|
125
|
+
columns: (
|
|
126
|
+
ColumnNode |
|
|
127
|
+
FunctionNode |
|
|
128
|
+
ScalarSubqueryNode |
|
|
129
|
+
CaseExpressionNode |
|
|
130
|
+
CastExpressionNode |
|
|
131
|
+
WindowFunctionNode
|
|
132
|
+
)[];
|
|
125
133
|
/** JOIN clauses */
|
|
126
134
|
joins: JoinNode[];
|
|
127
135
|
/** Optional WHERE clause */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SchemaDialect, DialectName } from '../schema-dialect.js';
|
|
2
2
|
import { formatLiteral, quoteQualified, LiteralFormatter } from '../sql-writing.js';
|
|
3
|
-
import { ColumnDef, ForeignKeyReference } from '../../../schema/column.js';
|
|
3
|
+
import { ColumnDef, ForeignKeyReference } from '../../../schema/column-types.js';
|
|
4
4
|
import { IndexDef, TableDef } from '../../../schema/table.js';
|
|
5
5
|
import { DatabaseTable, DatabaseColumn, ColumnDiff } from '../schema-types.js';
|
|
6
6
|
|
|
@@ -93,3 +93,4 @@ export abstract class BaseSchemaDialect implements SchemaDialect {
|
|
|
93
93
|
return false;
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
|
+
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseSchemaDialect } from './base-schema-dialect.js';
|
|
2
2
|
import { deriveIndexName } from '../naming-strategy.js';
|
|
3
3
|
import { renderIndexColumns, createLiteralFormatter } from '../sql-writing.js';
|
|
4
|
-
import { ColumnDef } from '../../../schema/column.js';
|
|
4
|
+
import { ColumnDef, normalizeColumnType, renderTypeWithArgs } from '../../../schema/column-types.js';
|
|
5
5
|
import { IndexDef, TableDef } from '../../../schema/table.js';
|
|
6
6
|
import { ColumnDiff, DatabaseColumn, DatabaseTable } from '../schema-types.js';
|
|
7
7
|
import { DialectName } from '../schema-dialect.js';
|
|
@@ -24,54 +24,43 @@ export class MSSqlSchemaDialect extends BaseSchemaDialect {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
renderColumnType(column: ColumnDef): string {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
const override = column.dialectTypes?.[this.name] ?? column.dialectTypes?.default;
|
|
28
|
+
if (override) {
|
|
29
|
+
return renderTypeWithArgs(override, column.args);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const type = normalizeColumnType(column.type);
|
|
33
|
+
switch (type) {
|
|
30
34
|
case 'int':
|
|
31
35
|
case 'integer':
|
|
32
36
|
return 'INT';
|
|
33
|
-
case 'BIGINT':
|
|
34
37
|
case 'bigint':
|
|
35
38
|
return 'BIGINT';
|
|
36
|
-
case 'UUID':
|
|
37
39
|
case 'uuid':
|
|
38
40
|
return 'UNIQUEIDENTIFIER';
|
|
39
|
-
case 'BOOLEAN':
|
|
40
41
|
case 'boolean':
|
|
41
42
|
return 'BIT';
|
|
42
|
-
case 'JSON':
|
|
43
43
|
case 'json':
|
|
44
44
|
return 'NVARCHAR(MAX)';
|
|
45
|
-
case 'DECIMAL':
|
|
46
45
|
case 'decimal':
|
|
47
46
|
return column.args?.length ? `DECIMAL(${column.args[0]},${column.args[1] ?? 0})` : 'DECIMAL(18,0)';
|
|
48
|
-
case 'FLOAT':
|
|
49
47
|
case 'float':
|
|
50
|
-
case 'DOUBLE':
|
|
51
48
|
case 'double':
|
|
52
49
|
return 'FLOAT';
|
|
53
|
-
case 'TIMESTAMPTZ':
|
|
54
50
|
case 'timestamptz':
|
|
55
|
-
case 'TIMESTAMP':
|
|
56
51
|
case 'timestamp':
|
|
57
|
-
case 'DATETIME':
|
|
58
52
|
case 'datetime':
|
|
59
53
|
return 'DATETIME2';
|
|
60
|
-
case 'DATE':
|
|
61
54
|
case 'date':
|
|
62
55
|
return 'DATE';
|
|
63
|
-
case 'VARCHAR':
|
|
64
56
|
case 'varchar':
|
|
65
57
|
return column.args?.length ? `NVARCHAR(${column.args[0]})` : 'NVARCHAR(255)';
|
|
66
|
-
case 'TEXT':
|
|
67
58
|
case 'text':
|
|
68
59
|
return 'NVARCHAR(MAX)';
|
|
69
|
-
case 'BINARY':
|
|
70
60
|
case 'binary': {
|
|
71
61
|
const length = column.args?.[0];
|
|
72
62
|
return length !== undefined ? `BINARY(${length})` : 'BINARY(255)';
|
|
73
63
|
}
|
|
74
|
-
case 'VARBINARY':
|
|
75
64
|
case 'varbinary': {
|
|
76
65
|
const length = column.args?.[0];
|
|
77
66
|
if (typeof length === 'string' && length.toLowerCase() === 'max') {
|
|
@@ -79,16 +68,13 @@ export class MSSqlSchemaDialect extends BaseSchemaDialect {
|
|
|
79
68
|
}
|
|
80
69
|
return length !== undefined ? `VARBINARY(${length})` : 'VARBINARY(255)';
|
|
81
70
|
}
|
|
82
|
-
case 'BLOB':
|
|
83
71
|
case 'blob':
|
|
84
|
-
case 'BYTEA':
|
|
85
72
|
case 'bytea':
|
|
86
73
|
return 'VARBINARY(MAX)';
|
|
87
|
-
case 'ENUM':
|
|
88
74
|
case 'enum':
|
|
89
75
|
return 'NVARCHAR(255)';
|
|
90
76
|
default:
|
|
91
|
-
return String(
|
|
77
|
+
return renderTypeWithArgs(String(type).toUpperCase(), column.args);
|
|
92
78
|
}
|
|
93
79
|
}
|
|
94
80
|
|
|
@@ -142,3 +128,4 @@ export class MSSqlSchemaDialect extends BaseSchemaDialect {
|
|
|
142
128
|
return undefined;
|
|
143
129
|
}
|
|
144
130
|
}
|
|
131
|
+
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseSchemaDialect } from './base-schema-dialect.js';
|
|
2
2
|
import { deriveIndexName } from '../naming-strategy.js';
|
|
3
3
|
import { renderIndexColumns, escapeSqlString, createLiteralFormatter } from '../sql-writing.js';
|
|
4
|
-
import { ColumnDef } from '../../../schema/column.js';
|
|
4
|
+
import { ColumnDef, normalizeColumnType, renderTypeWithArgs } from '../../../schema/column-types.js';
|
|
5
5
|
import { IndexDef, TableDef } from '../../../schema/table.js';
|
|
6
6
|
import { ColumnDiff, DatabaseColumn, DatabaseTable } from '../schema-types.js';
|
|
7
7
|
import { renderColumnDefinition } from '../schema-generator.js';
|
|
@@ -25,69 +25,54 @@ export class MySqlSchemaDialect extends BaseSchemaDialect {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
renderColumnType(column: ColumnDef): string {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
const override = column.dialectTypes?.[this.name] ?? column.dialectTypes?.default;
|
|
29
|
+
if (override) {
|
|
30
|
+
return renderTypeWithArgs(override, column.args);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const type = normalizeColumnType(column.type);
|
|
34
|
+
switch (type) {
|
|
31
35
|
case 'int':
|
|
32
36
|
case 'integer':
|
|
33
37
|
return 'INT';
|
|
34
|
-
case 'BIGINT':
|
|
35
38
|
case 'bigint':
|
|
36
39
|
return 'BIGINT';
|
|
37
|
-
case 'UUID':
|
|
38
40
|
case 'uuid':
|
|
39
41
|
return 'CHAR(36)';
|
|
40
|
-
case 'BOOLEAN':
|
|
41
42
|
case 'boolean':
|
|
42
43
|
return 'TINYINT(1)';
|
|
43
|
-
case 'JSON':
|
|
44
44
|
case 'json':
|
|
45
45
|
return 'JSON';
|
|
46
|
-
case 'DECIMAL':
|
|
47
46
|
case 'decimal':
|
|
48
47
|
return column.args?.length ? `DECIMAL(${column.args[0]},${column.args[1] ?? 0})` : 'DECIMAL';
|
|
49
|
-
case 'FLOAT':
|
|
50
48
|
case 'float':
|
|
51
49
|
return column.args?.length ? `FLOAT(${column.args[0]})` : 'FLOAT';
|
|
52
|
-
case 'DOUBLE':
|
|
53
50
|
case 'double':
|
|
54
51
|
return 'DOUBLE';
|
|
55
|
-
case 'TIMESTAMPTZ':
|
|
56
52
|
case 'timestamptz':
|
|
57
|
-
return 'TIMESTAMP';
|
|
58
|
-
case 'TIMESTAMP':
|
|
59
53
|
case 'timestamp':
|
|
60
54
|
return 'TIMESTAMP';
|
|
61
|
-
case 'DATETIME':
|
|
62
55
|
case 'datetime':
|
|
63
56
|
return 'DATETIME';
|
|
64
|
-
case 'DATE':
|
|
65
57
|
case 'date':
|
|
66
58
|
return 'DATE';
|
|
67
|
-
case 'VARCHAR':
|
|
68
59
|
case 'varchar':
|
|
69
60
|
return column.args?.length ? `VARCHAR(${column.args[0]})` : 'VARCHAR(255)';
|
|
70
|
-
case 'TEXT':
|
|
71
61
|
case 'text':
|
|
72
62
|
return 'TEXT';
|
|
73
|
-
case 'BINARY':
|
|
74
63
|
case 'binary':
|
|
75
64
|
return column.args?.length ? `BINARY(${column.args[0]})` : 'BINARY(255)';
|
|
76
|
-
case 'VARBINARY':
|
|
77
65
|
case 'varbinary':
|
|
78
66
|
return column.args?.length ? `VARBINARY(${column.args[0]})` : 'VARBINARY(255)';
|
|
79
|
-
case 'BLOB':
|
|
80
67
|
case 'blob':
|
|
81
|
-
case 'BYTEA':
|
|
82
68
|
case 'bytea':
|
|
83
69
|
return 'BLOB';
|
|
84
|
-
case 'ENUM':
|
|
85
70
|
case 'enum':
|
|
86
71
|
return column.args && Array.isArray(column.args) && column.args.length
|
|
87
72
|
? `ENUM(${column.args.map((v: string) => `'${escapeSqlString(v)}'`).join(',')})`
|
|
88
73
|
: 'ENUM';
|
|
89
74
|
default:
|
|
90
|
-
return String(
|
|
75
|
+
return renderTypeWithArgs(String(type).toUpperCase(), column.args);
|
|
91
76
|
}
|
|
92
77
|
}
|
|
93
78
|
|
|
@@ -132,3 +117,4 @@ export class MySqlSchemaDialect extends BaseSchemaDialect {
|
|
|
132
117
|
return [`ALTER TABLE ${this.formatTableName(table)} MODIFY COLUMN ${rendered.sql};`];
|
|
133
118
|
}
|
|
134
119
|
}
|
|
120
|
+
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseSchemaDialect } from './base-schema-dialect.js';
|
|
2
2
|
import { deriveIndexName } from '../naming-strategy.js';
|
|
3
3
|
import { renderIndexColumns, createLiteralFormatter } from '../sql-writing.js';
|
|
4
|
-
import { ColumnDef, ForeignKeyReference } from '../../../schema/column.js';
|
|
4
|
+
import { ColumnDef, ForeignKeyReference, normalizeColumnType, renderTypeWithArgs } from '../../../schema/column-types.js';
|
|
5
5
|
import { IndexDef, TableDef } from '../../../schema/table.js';
|
|
6
6
|
import { ColumnDiff, DatabaseColumn, DatabaseTable } from '../schema-types.js';
|
|
7
7
|
import { DialectName } from '../schema-dialect.js';
|
|
@@ -24,64 +24,50 @@ export class PostgresSchemaDialect extends BaseSchemaDialect {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
renderColumnType(column: ColumnDef): string {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
const override = column.dialectTypes?.[this.name] ?? column.dialectTypes?.default;
|
|
28
|
+
if (override) {
|
|
29
|
+
return renderTypeWithArgs(override, column.args);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const type = normalizeColumnType(column.type);
|
|
33
|
+
switch (type) {
|
|
30
34
|
case 'int':
|
|
31
35
|
case 'integer':
|
|
32
36
|
return 'integer';
|
|
33
|
-
case 'BIGINT':
|
|
34
37
|
case 'bigint':
|
|
35
38
|
return 'bigint';
|
|
36
|
-
case 'UUID':
|
|
37
39
|
case 'uuid':
|
|
38
40
|
return 'uuid';
|
|
39
|
-
case 'BOOLEAN':
|
|
40
41
|
case 'boolean':
|
|
41
42
|
return 'boolean';
|
|
42
|
-
case 'JSON':
|
|
43
43
|
case 'json':
|
|
44
44
|
return 'jsonb';
|
|
45
|
-
case 'DECIMAL':
|
|
46
45
|
case 'decimal':
|
|
47
46
|
return column.args?.length ? `numeric(${column.args[0]}, ${column.args[1] ?? 0})` : 'numeric';
|
|
48
|
-
case 'FLOAT':
|
|
49
47
|
case 'float':
|
|
50
|
-
case 'DOUBLE':
|
|
51
48
|
case 'double':
|
|
52
49
|
return 'double precision';
|
|
53
|
-
case 'TIMESTAMPTZ':
|
|
54
50
|
case 'timestamptz':
|
|
55
51
|
return 'timestamptz';
|
|
56
|
-
case 'TIMESTAMP':
|
|
57
52
|
case 'timestamp':
|
|
58
53
|
return 'timestamp';
|
|
59
|
-
case 'DATE':
|
|
60
54
|
case 'date':
|
|
61
55
|
return 'date';
|
|
62
|
-
case 'DATETIME':
|
|
63
56
|
case 'datetime':
|
|
64
57
|
return 'timestamp';
|
|
65
|
-
case 'VARCHAR':
|
|
66
58
|
case 'varchar':
|
|
67
59
|
return column.args?.length ? `varchar(${column.args[0]})` : 'varchar';
|
|
68
|
-
case 'TEXT':
|
|
69
60
|
case 'text':
|
|
70
61
|
return 'text';
|
|
71
|
-
case 'ENUM':
|
|
72
62
|
case 'enum':
|
|
73
63
|
return 'text';
|
|
74
|
-
case 'BINARY':
|
|
75
64
|
case 'binary':
|
|
76
|
-
case 'VARBINARY':
|
|
77
65
|
case 'varbinary':
|
|
78
|
-
case 'BLOB':
|
|
79
66
|
case 'blob':
|
|
80
|
-
case 'BYTEA':
|
|
81
67
|
case 'bytea':
|
|
82
68
|
return 'bytea';
|
|
83
69
|
default:
|
|
84
|
-
return String(
|
|
70
|
+
return renderTypeWithArgs(String(type).toLowerCase(), column.args);
|
|
85
71
|
}
|
|
86
72
|
}
|
|
87
73
|
|
|
@@ -164,3 +150,4 @@ export class PostgresSchemaDialect extends BaseSchemaDialect {
|
|
|
164
150
|
return undefined;
|
|
165
151
|
}
|
|
166
152
|
}
|
|
153
|
+
|
|
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest';
|
|
|
2
2
|
import { BaseSchemaDialect } from './base-schema-dialect.js';
|
|
3
3
|
import { PostgresSchemaDialect } from './postgres-schema-dialect.js';
|
|
4
4
|
import { TableDef } from '../../../schema/table.js';
|
|
5
|
-
import { ForeignKeyReference } from '../../../schema/column.js';
|
|
5
|
+
import { ForeignKeyReference } from '../../../schema/column-types.js';
|
|
6
6
|
import { createLiteralFormatter } from '../sql-writing.js';
|
|
7
7
|
|
|
8
8
|
class DummySchemaDialect extends BaseSchemaDialect {
|
|
@@ -67,3 +67,4 @@ describe('renderReference deferrable handling', () => {
|
|
|
67
67
|
expect(sql).not.toContain('DEFERRABLE INITIALLY DEFERRED');
|
|
68
68
|
});
|
|
69
69
|
});
|
|
70
|
+
|