metal-orm 1.0.14 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/README.md +40 -45
  2. package/dist/decorators/index.cjs +1600 -27
  3. package/dist/decorators/index.cjs.map +1 -1
  4. package/dist/decorators/index.d.cts +6 -2
  5. package/dist/decorators/index.d.ts +6 -2
  6. package/dist/decorators/index.js +1599 -27
  7. package/dist/decorators/index.js.map +1 -1
  8. package/dist/index.cjs +4608 -3429
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +511 -159
  11. package/dist/index.d.ts +511 -159
  12. package/dist/index.js +4526 -3415
  13. package/dist/index.js.map +1 -1
  14. package/dist/{select-CCp1oz9p.d.cts → select-Bkv8g8u_.d.cts} +193 -67
  15. package/dist/{select-CCp1oz9p.d.ts → select-Bkv8g8u_.d.ts} +193 -67
  16. package/package.json +1 -1
  17. package/src/codegen/typescript.ts +38 -35
  18. package/src/core/ast/adapters.ts +21 -0
  19. package/src/core/ast/aggregate-functions.ts +13 -13
  20. package/src/core/ast/builders.ts +56 -43
  21. package/src/core/ast/expression-builders.ts +34 -34
  22. package/src/core/ast/expression-nodes.ts +18 -16
  23. package/src/core/ast/expression-visitor.ts +122 -69
  24. package/src/core/ast/expression.ts +6 -4
  25. package/src/core/ast/join-metadata.ts +15 -0
  26. package/src/core/ast/join-node.ts +22 -20
  27. package/src/core/ast/join.ts +5 -5
  28. package/src/core/ast/query.ts +52 -88
  29. package/src/core/ast/types.ts +20 -0
  30. package/src/core/ast/window-functions.ts +55 -55
  31. package/src/core/ddl/dialects/base-schema-dialect.ts +20 -6
  32. package/src/core/ddl/dialects/mssql-schema-dialect.ts +32 -8
  33. package/src/core/ddl/dialects/mysql-schema-dialect.ts +21 -10
  34. package/src/core/ddl/dialects/postgres-schema-dialect.ts +52 -7
  35. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +23 -9
  36. package/src/core/ddl/introspect/catalogs/index.ts +1 -0
  37. package/src/core/ddl/introspect/catalogs/postgres.ts +143 -0
  38. package/src/core/ddl/introspect/context.ts +9 -0
  39. package/src/core/ddl/introspect/functions/postgres.ts +26 -0
  40. package/src/core/ddl/introspect/mssql.ts +149 -149
  41. package/src/core/ddl/introspect/mysql.ts +99 -99
  42. package/src/core/ddl/introspect/postgres.ts +245 -154
  43. package/src/core/ddl/introspect/registry.ts +26 -0
  44. package/src/core/ddl/introspect/run-select.ts +25 -0
  45. package/src/core/ddl/introspect/sqlite.ts +7 -7
  46. package/src/core/ddl/introspect/types.ts +23 -19
  47. package/src/core/ddl/introspect/utils.ts +1 -1
  48. package/src/core/ddl/naming-strategy.ts +10 -0
  49. package/src/core/ddl/schema-dialect.ts +41 -0
  50. package/src/core/ddl/schema-diff.ts +211 -179
  51. package/src/core/ddl/schema-generator.ts +16 -90
  52. package/src/core/ddl/schema-introspect.ts +25 -32
  53. package/src/core/ddl/schema-plan-executor.ts +17 -0
  54. package/src/core/ddl/schema-types.ts +46 -39
  55. package/src/core/ddl/sql-writing.ts +170 -0
  56. package/src/core/dialect/abstract.ts +144 -126
  57. package/src/core/dialect/base/cte-compiler.ts +33 -0
  58. package/src/core/dialect/base/function-table-formatter.ts +132 -0
  59. package/src/core/dialect/base/groupby-compiler.ts +21 -0
  60. package/src/core/dialect/base/join-compiler.ts +26 -0
  61. package/src/core/dialect/base/orderby-compiler.ts +21 -0
  62. package/src/core/dialect/base/pagination-strategy.ts +32 -0
  63. package/src/core/dialect/base/returning-strategy.ts +56 -0
  64. package/src/core/dialect/base/sql-dialect.ts +181 -204
  65. package/src/core/dialect/dialect-factory.ts +91 -0
  66. package/src/core/dialect/mssql/functions.ts +101 -0
  67. package/src/core/dialect/mssql/index.ts +128 -126
  68. package/src/core/dialect/mysql/functions.ts +101 -0
  69. package/src/core/dialect/mysql/index.ts +20 -18
  70. package/src/core/dialect/postgres/functions.ts +95 -0
  71. package/src/core/dialect/postgres/index.ts +30 -28
  72. package/src/core/dialect/sqlite/functions.ts +115 -0
  73. package/src/core/dialect/sqlite/index.ts +30 -28
  74. package/src/core/driver/database-driver.ts +11 -0
  75. package/src/core/driver/mssql-driver.ts +20 -0
  76. package/src/core/driver/mysql-driver.ts +20 -0
  77. package/src/core/driver/postgres-driver.ts +20 -0
  78. package/src/core/driver/sqlite-driver.ts +20 -0
  79. package/src/core/execution/db-executor.ts +63 -0
  80. package/src/core/execution/executors/mssql-executor.ts +39 -0
  81. package/src/core/execution/executors/mysql-executor.ts +47 -0
  82. package/src/core/execution/executors/postgres-executor.ts +32 -0
  83. package/src/core/execution/executors/sqlite-executor.ts +31 -0
  84. package/src/core/functions/datetime.ts +132 -0
  85. package/src/core/functions/numeric.ts +179 -0
  86. package/src/core/functions/standard-strategy.ts +47 -0
  87. package/src/core/functions/text.ts +147 -0
  88. package/src/core/functions/types.ts +18 -0
  89. package/src/core/hydration/types.ts +57 -0
  90. package/src/decorators/bootstrap.ts +10 -0
  91. package/src/decorators/relations.ts +15 -0
  92. package/src/index.ts +30 -19
  93. package/src/orm/entity-metadata.ts +7 -0
  94. package/src/orm/entity.ts +58 -27
  95. package/src/orm/hydration.ts +25 -17
  96. package/src/orm/lazy-batch.ts +46 -2
  97. package/src/orm/orm-context.ts +60 -60
  98. package/src/orm/query-logger.ts +1 -1
  99. package/src/orm/relation-change-processor.ts +43 -2
  100. package/src/orm/relations/has-one.ts +139 -0
  101. package/src/orm/transaction-runner.ts +1 -1
  102. package/src/orm/unit-of-work.ts +60 -60
  103. package/src/query-builder/delete.ts +22 -5
  104. package/src/query-builder/hydration-manager.ts +2 -1
  105. package/src/query-builder/hydration-planner.ts +8 -7
  106. package/src/query-builder/insert.ts +22 -5
  107. package/src/query-builder/relation-conditions.ts +9 -8
  108. package/src/query-builder/relation-service.ts +3 -2
  109. package/src/query-builder/select.ts +66 -61
  110. package/src/query-builder/update.ts +22 -5
  111. package/src/schema/column.ts +246 -246
  112. package/src/schema/relation.ts +35 -1
  113. package/src/schema/table.ts +28 -28
  114. package/src/schema/types.ts +41 -31
  115. package/src/orm/db-executor.ts +0 -11
@@ -1,179 +1,211 @@
1
- import { TableDef } from '../../schema/table.js';
2
- import { DbExecutor } from '../../orm/db-executor.js';
3
- import {
4
- SchemaDialect,
5
- deriveIndexName,
6
- generateCreateTableSql,
7
- renderColumnDefinition
8
- } from './schema-generator.js';
9
- import { DatabaseSchema, DatabaseTable } from './schema-types.js';
10
-
11
- export type SchemaChangeKind =
12
- | 'createTable'
13
- | 'dropTable'
14
- | 'addColumn'
15
- | 'dropColumn'
16
- | 'alterColumn'
17
- | 'addIndex'
18
- | 'dropIndex';
19
-
20
- export interface SchemaChange {
21
- kind: SchemaChangeKind;
22
- table: string;
23
- description: string;
24
- statements: string[];
25
- safe: boolean;
26
- }
27
-
28
- export interface SchemaPlan {
29
- changes: SchemaChange[];
30
- warnings: string[];
31
- }
32
-
33
- export interface SchemaDiffOptions {
34
- /** Allow destructive operations (drops) */
35
- allowDestructive?: boolean;
36
- }
37
-
38
- const tableKey = (name: string, schema?: string) => (schema ? `${schema}.${name}` : name);
39
-
40
- const mapTables = (schema: DatabaseSchema) => {
41
- const map = new Map<string, DatabaseTable>();
42
- for (const table of schema.tables) {
43
- map.set(tableKey(table.name, table.schema), table);
44
- }
45
- return map;
46
- };
47
-
48
- const buildAddColumnSql = (table: TableDef, colName: string, dialect: SchemaDialect): string => {
49
- const column = table.columns[colName];
50
- const rendered = renderColumnDefinition(table, column, dialect);
51
- return `ALTER TABLE ${dialect.formatTableName(table)} ADD ${rendered.sql};`;
52
- };
53
-
54
- export const diffSchema = (
55
- expectedTables: TableDef[],
56
- actualSchema: DatabaseSchema,
57
- dialect: SchemaDialect,
58
- options: SchemaDiffOptions = {}
59
- ): SchemaPlan => {
60
- const allowDestructive = options.allowDestructive ?? false;
61
- const plan: SchemaPlan = { changes: [], warnings: [] };
62
-
63
- const actualMap = mapTables(actualSchema);
64
-
65
- // Create missing tables and indexes
66
- for (const table of expectedTables) {
67
- const key = tableKey(table.name, table.schema);
68
- const actual = actualMap.get(key);
69
- if (!actual) {
70
- const { tableSql, indexSql } = generateCreateTableSql(table, dialect);
71
- plan.changes.push({
72
- kind: 'createTable',
73
- table: key,
74
- description: `Create table ${key}`,
75
- statements: [tableSql, ...indexSql],
76
- safe: true
77
- });
78
- continue;
79
- }
80
-
81
- // Columns
82
- const actualCols = new Map(actual.columns.map(c => [c.name, c]));
83
- for (const colName of Object.keys(table.columns)) {
84
- if (!actualCols.has(colName)) {
85
- plan.changes.push({
86
- kind: 'addColumn',
87
- table: key,
88
- description: `Add column ${colName} to ${key}`,
89
- statements: [buildAddColumnSql(table, colName, dialect)],
90
- safe: true
91
- });
92
- }
93
- }
94
- for (const colName of actualCols.keys()) {
95
- if (!table.columns[colName]) {
96
- plan.changes.push({
97
- kind: 'dropColumn',
98
- table: key,
99
- description: `Drop column ${colName} from ${key}`,
100
- statements: allowDestructive ? dialect.dropColumnSql(actual, colName) : [],
101
- safe: false
102
- });
103
- const warning = dialect.warnDropColumn?.(actual, colName);
104
- if (warning) plan.warnings.push(warning);
105
- }
106
- }
107
-
108
- // Indexes (naive: based on name or derived name)
109
- const expectedIndexes = table.indexes ?? [];
110
- const actualIndexes = actual.indexes ?? [];
111
- const actualIndexMap = new Map(actualIndexes.map(idx => [idx.name, idx]));
112
-
113
- for (const idx of expectedIndexes) {
114
- const name = idx.name || deriveIndexName(table, idx);
115
- if (!actualIndexMap.has(name)) {
116
- plan.changes.push({
117
- kind: 'addIndex',
118
- table: key,
119
- description: `Create index ${name} on ${key}`,
120
- statements: [dialect.renderIndex(table, { ...idx, name })],
121
- safe: true
122
- });
123
- }
124
- }
125
-
126
- for (const idx of actualIndexes) {
127
- if (idx.name && !expectedIndexes.find(expected => (expected.name || deriveIndexName(table, expected)) === idx.name)) {
128
- plan.changes.push({
129
- kind: 'dropIndex',
130
- table: key,
131
- description: `Drop index ${idx.name} on ${key}`,
132
- statements: allowDestructive ? dialect.dropIndexSql(actual, idx.name) : [],
133
- safe: false
134
- });
135
- }
136
- }
137
- }
138
-
139
- // Extra tables
140
- for (const actual of actualSchema.tables) {
141
- const key = tableKey(actual.name, actual.schema);
142
- if (!expectedTables.find(t => tableKey(t.name, t.schema) === key)) {
143
- plan.changes.push({
144
- kind: 'dropTable',
145
- table: key,
146
- description: `Drop table ${key}`,
147
- statements: allowDestructive ? dialect.dropTableSql(actual) : [],
148
- safe: false
149
- });
150
- }
151
- }
152
-
153
- return plan;
154
- };
155
-
156
- export interface SynchronizeOptions extends SchemaDiffOptions {
157
- dryRun?: boolean;
158
- }
159
-
160
- export const synchronizeSchema = async (
161
- expectedTables: TableDef[],
162
- actualSchema: DatabaseSchema,
163
- dialect: SchemaDialect,
164
- executor: DbExecutor,
165
- options: SynchronizeOptions = {}
166
- ): Promise<SchemaPlan> => {
167
- const plan = diffSchema(expectedTables, actualSchema, dialect, options);
168
- if (options.dryRun) return plan;
169
-
170
- for (const change of plan.changes) {
171
- if (!change.statements.length) continue;
172
- if (!change.safe && !options.allowDestructive) continue;
173
- for (const stmt of change.statements) {
174
- if (!stmt.trim()) continue;
175
- await executor.executeSql(stmt);
176
- }
177
- }
178
- return plan;
179
- };
1
+ import { TableDef } from '../../schema/table.js';
2
+ import { ColumnDef } from '../../schema/column.js';
3
+ import type { DbExecutor } from '../execution/db-executor.js';
4
+ import { SchemaDialect } from './schema-dialect.js';
5
+ import { deriveIndexName } from './naming-strategy.js';
6
+ import { generateCreateTableSql, renderColumnDefinition } from './schema-generator.js';
7
+ import { ColumnDiff, DatabaseColumn, DatabaseSchema, DatabaseTable } from './schema-types.js';
8
+
9
+ export type SchemaChangeKind =
10
+ | 'createTable'
11
+ | 'dropTable'
12
+ | 'addColumn'
13
+ | 'dropColumn'
14
+ | 'alterColumn'
15
+ | 'addIndex'
16
+ | 'dropIndex';
17
+
18
+ export interface SchemaChange {
19
+ kind: SchemaChangeKind;
20
+ table: string;
21
+ description: string;
22
+ statements: string[];
23
+ safe: boolean;
24
+ }
25
+
26
+ export interface SchemaPlan {
27
+ changes: SchemaChange[];
28
+ warnings: string[];
29
+ }
30
+
31
+ export interface SchemaDiffOptions {
32
+ /** Allow destructive operations (drops) */
33
+ allowDestructive?: boolean;
34
+ }
35
+
36
+ const tableKey = (name: string, schema?: string) => (schema ? `${schema}.${name}` : name);
37
+
38
+ const mapTables = (schema: DatabaseSchema) => {
39
+ const map = new Map<string, DatabaseTable>();
40
+ for (const table of schema.tables) {
41
+ map.set(tableKey(table.name, table.schema), table);
42
+ }
43
+ return map;
44
+ };
45
+
46
+ const buildAddColumnSql = (table: TableDef, colName: string, dialect: SchemaDialect): string => {
47
+ const column = table.columns[colName];
48
+ const rendered = renderColumnDefinition(table, column, dialect);
49
+ return `ALTER TABLE ${dialect.formatTableName(table)} ADD ${rendered.sql};`;
50
+ };
51
+
52
+ const normalizeType = (value: string | undefined): string => (value || '').toLowerCase().replace(/\s+/g, ' ').trim();
53
+ const normalizeDefault = (value: unknown): string | undefined => {
54
+ if (value === undefined || value === null) return undefined;
55
+ return String(value).trim();
56
+ };
57
+
58
+ const diffColumn = (expected: ColumnDef, actual: DatabaseColumn, dialect: SchemaDialect): ColumnDiff => {
59
+ const expectedType = normalizeType(dialect.renderColumnType(expected));
60
+ const actualType = normalizeType(actual.type);
61
+ const expectedDefault =
62
+ expected.default !== undefined ? normalizeDefault(dialect.renderDefault(expected.default, expected)) : undefined;
63
+ const actualDefault = normalizeDefault(actual.default);
64
+ return {
65
+ typeChanged: expectedType !== actualType,
66
+ nullabilityChanged: !!expected.notNull !== !!actual.notNull,
67
+ defaultChanged: expectedDefault !== actualDefault,
68
+ autoIncrementChanged: !!expected.autoIncrement !== !!actual.autoIncrement
69
+ };
70
+ };
71
+
72
+ export const diffSchema = (
73
+ expectedTables: TableDef[],
74
+ actualSchema: DatabaseSchema,
75
+ dialect: SchemaDialect,
76
+ options: SchemaDiffOptions = {}
77
+ ): SchemaPlan => {
78
+ const allowDestructive = options.allowDestructive ?? false;
79
+ const plan: SchemaPlan = { changes: [], warnings: [] };
80
+
81
+ const actualMap = mapTables(actualSchema);
82
+
83
+ // Create missing tables and indexes
84
+ for (const table of expectedTables) {
85
+ const key = tableKey(table.name, table.schema);
86
+ const actual = actualMap.get(key);
87
+ if (!actual) {
88
+ const { tableSql, indexSql } = generateCreateTableSql(table, dialect);
89
+ plan.changes.push({
90
+ kind: 'createTable',
91
+ table: key,
92
+ description: `Create table ${key}`,
93
+ statements: [tableSql, ...indexSql],
94
+ safe: true
95
+ });
96
+ continue;
97
+ }
98
+
99
+ // Columns
100
+ const actualCols = new Map(actual.columns.map(c => [c.name, c]));
101
+ for (const colName of Object.keys(table.columns)) {
102
+ if (!actualCols.has(colName)) {
103
+ plan.changes.push({
104
+ kind: 'addColumn',
105
+ table: key,
106
+ description: `Add column ${colName} to ${key}`,
107
+ statements: [buildAddColumnSql(table, colName, dialect)],
108
+ safe: true
109
+ });
110
+ } else {
111
+ const expectedCol = table.columns[colName];
112
+ const actualCol = actualCols.get(colName)!;
113
+ const colDiff = diffColumn(expectedCol, actualCol, dialect);
114
+ const shouldAlter =
115
+ colDiff.typeChanged || colDiff.nullabilityChanged || colDiff.defaultChanged || colDiff.autoIncrementChanged;
116
+ if (shouldAlter) {
117
+ const statements = dialect.alterColumnSql?.(table, expectedCol, actualCol, colDiff) ?? [];
118
+ if (statements.length > 0) {
119
+ plan.changes.push({
120
+ kind: 'alterColumn',
121
+ table: key,
122
+ description: `Alter column ${colName} on ${key}`,
123
+ statements,
124
+ safe: true
125
+ });
126
+ }
127
+ const warning = dialect.warnAlterColumn?.(table, expectedCol, actualCol, colDiff);
128
+ if (warning) plan.warnings.push(warning);
129
+ }
130
+ }
131
+ }
132
+ for (const colName of actualCols.keys()) {
133
+ if (!table.columns[colName]) {
134
+ plan.changes.push({
135
+ kind: 'dropColumn',
136
+ table: key,
137
+ description: `Drop column ${colName} from ${key}`,
138
+ statements: allowDestructive ? dialect.dropColumnSql(actual, colName) : [],
139
+ safe: false
140
+ });
141
+ const warning = dialect.warnDropColumn?.(actual, colName);
142
+ if (warning) plan.warnings.push(warning);
143
+ }
144
+ }
145
+
146
+ // Indexes (naive: based on name or derived name)
147
+ const expectedIndexes = table.indexes ?? [];
148
+ const actualIndexes = actual.indexes ?? [];
149
+ const actualIndexMap = new Map(actualIndexes.map(idx => [idx.name, idx]));
150
+
151
+ for (const idx of expectedIndexes) {
152
+ const name = idx.name || deriveIndexName(table, idx);
153
+ if (!actualIndexMap.has(name)) {
154
+ plan.changes.push({
155
+ kind: 'addIndex',
156
+ table: key,
157
+ description: `Create index ${name} on ${key}`,
158
+ statements: [dialect.renderIndex(table, { ...idx, name })],
159
+ safe: true
160
+ });
161
+ }
162
+ }
163
+
164
+ for (const idx of actualIndexes) {
165
+ if (idx.name && !expectedIndexes.find(expected => (expected.name || deriveIndexName(table, expected)) === idx.name)) {
166
+ plan.changes.push({
167
+ kind: 'dropIndex',
168
+ table: key,
169
+ description: `Drop index ${idx.name} on ${key}`,
170
+ statements: allowDestructive ? dialect.dropIndexSql(actual, idx.name) : [],
171
+ safe: false
172
+ });
173
+ }
174
+ }
175
+ }
176
+
177
+ // Extra tables
178
+ for (const actual of actualSchema.tables) {
179
+ const key = tableKey(actual.name, actual.schema);
180
+ if (!expectedTables.find(t => tableKey(t.name, t.schema) === key)) {
181
+ plan.changes.push({
182
+ kind: 'dropTable',
183
+ table: key,
184
+ description: `Drop table ${key}`,
185
+ statements: allowDestructive ? dialect.dropTableSql(actual) : [],
186
+ safe: false
187
+ });
188
+ }
189
+ }
190
+
191
+ return plan;
192
+ };
193
+
194
+ export interface SynchronizeOptions extends SchemaDiffOptions {
195
+ dryRun?: boolean;
196
+ }
197
+
198
+ export const synchronizeSchema = async (
199
+ expectedTables: TableDef[],
200
+ actualSchema: DatabaseSchema,
201
+ dialect: SchemaDialect,
202
+ executor: DbExecutor,
203
+ options: SynchronizeOptions = {}
204
+ ): Promise<SchemaPlan> => {
205
+ const plan = diffSchema(expectedTables, actualSchema, dialect, options);
206
+ if (!options.dryRun) {
207
+ const { executeSchemaPlan } = await import('./schema-plan-executor.js');
208
+ await executeSchemaPlan(plan, executor, options);
209
+ }
210
+ return plan;
211
+ };
@@ -1,98 +1,21 @@
1
- import { ColumnDef, ForeignKeyReference, RawDefaultValue } from '../../schema/column.js';
2
- import { IndexDef, IndexColumn, TableDef } from '../../schema/table.js';
3
- import { DatabaseTable } from './schema-types.js';
4
- export { BaseSchemaDialect } from './dialects/base-schema-dialect.js';
5
- export {
6
- PostgresSchemaDialect,
7
- MySqlSchemaDialect,
8
- SQLiteSchemaDialect,
9
- MSSqlSchemaDialect
10
- } from './dialects/index.js';
11
-
12
- export type DialectName = 'postgres' | 'mysql' | 'sqlite' | 'mssql';
13
-
14
- export interface SchemaDialect {
15
- name: DialectName;
16
- quoteIdentifier(id: string): string;
17
- formatTableName(table: TableDef | DatabaseTable): string;
18
- renderColumnType(column: ColumnDef): string;
19
- renderDefault(value: unknown, column: ColumnDef): string;
20
- renderAutoIncrement(column: ColumnDef, table: TableDef): string | undefined;
21
- renderReference(ref: ForeignKeyReference, table: TableDef): string;
22
- renderIndex(table: TableDef, index: IndexDef): string;
23
- renderTableOptions(table: TableDef): string | undefined;
24
- supportsPartialIndexes(): boolean;
25
- preferInlinePkAutoincrement?(column: ColumnDef, table: TableDef, pk: string[]): boolean;
26
- dropColumnSql(table: DatabaseTable, column: string): string[];
27
- dropIndexSql(table: DatabaseTable, index: string): string[];
28
- dropTableSql(table: DatabaseTable): string[];
29
- warnDropColumn?(table: DatabaseTable, column: string): string | undefined;
30
- }
1
+ import type { TableDef, IndexDef, IndexColumn } from '../../schema/table.js';
2
+ import type { ColumnDef, ForeignKeyReference } from '../../schema/column.js';
3
+ import type { SchemaDialect, DialectName } from './schema-dialect.js';
4
+ import { deriveIndexName } from './naming-strategy.js';
5
+ import {
6
+ formatLiteral,
7
+ renderIndexColumns,
8
+ quoteQualified,
9
+ resolvePrimaryKey,
10
+ Quoter
11
+ } from './sql-writing.js';
12
+ import { DatabaseTable, DatabaseColumn, ColumnDiff } from './schema-types.js';
31
13
 
32
14
  export interface SchemaGenerateResult {
33
15
  tableSql: string;
34
16
  indexSql: string[];
35
17
  }
36
18
 
37
- export const escapeLiteral = (value: string): string => value.replace(/'/g, "''");
38
-
39
- const isRawDefault = (value: unknown): value is RawDefaultValue => {
40
- return !!value && typeof value === 'object' && 'raw' in (value as any) && typeof (value as any).raw === 'string';
41
- };
42
-
43
- export const formatLiteral = (value: unknown, dialect: DialectName): string => {
44
- if (isRawDefault(value)) return value.raw;
45
- if (value === null) return 'NULL';
46
- if (typeof value === 'number') return Number.isFinite(value) ? String(value) : 'NULL';
47
- if (typeof value === 'boolean') {
48
- if (dialect === 'mysql' || dialect === 'sqlite' || dialect === 'mssql') {
49
- return value ? '1' : '0';
50
- }
51
- return value ? 'TRUE' : 'FALSE';
52
- }
53
- if (value instanceof Date) return `'${escapeLiteral(value.toISOString())}'`;
54
- if (typeof value === 'string') return `'${escapeLiteral(value)}'`;
55
- return `'${escapeLiteral(JSON.stringify(value))}'`;
56
- };
57
-
58
- export const resolvePrimaryKey = (table: TableDef): string[] => {
59
- if (table.primaryKey && table.primaryKey.length > 0) {
60
- return table.primaryKey;
61
- }
62
- const cols = Object.values(table.columns);
63
- return cols.filter(c => c.primary).map(c => c.name);
64
- };
65
-
66
- export const quoteQualified = (dialect: SchemaDialect, identifier: string): string => {
67
- if (identifier.includes('.')) {
68
- return identifier
69
- .split('.')
70
- .map(part => dialect.quoteIdentifier(part))
71
- .join('.');
72
- }
73
- return dialect.quoteIdentifier(identifier);
74
- };
75
-
76
- export const renderIndexColumns = (dialect: SchemaDialect, columns: (string | IndexColumn)[]) => {
77
- return columns
78
- .map(col => {
79
- if (typeof col === 'string') return dialect.quoteIdentifier(col);
80
- const parts = [dialect.quoteIdentifier(col.column)];
81
- if (col.order) parts.push(col.order);
82
- if (col.nulls) parts.push(`NULLS ${col.nulls}`);
83
- return parts.join(' ');
84
- })
85
- .join(', ');
86
- };
87
-
88
- export const deriveIndexName = (table: TableDef, index: IndexDef): string => {
89
- const base = (index.columns || [])
90
- .map(col => (typeof col === 'string' ? col : col.column))
91
- .join('_');
92
- const suffix = index.unique ? 'uniq' : 'idx';
93
- return `${table.name}_${base}_${suffix}`;
94
- };
95
-
96
19
  export interface RenderColumnOptions {
97
20
  includePrimary?: boolean;
98
21
  }
@@ -136,7 +59,7 @@ export const generateCreateTableSql = (
136
59
  const inlinePkColumns = new Set<string>();
137
60
 
138
61
  const columnLines = Object.values(table.columns).map(col => {
139
- const includePk = dialect.preferInlinePkAutoincrement?.(col, table, pk) && pk.includes(col.name);
62
+ const includePk = (dialect as any).preferInlinePkAutoincrement?.(col, table, pk) && pk.includes(col.name);
140
63
  if (includePk) {
141
64
  inlinePkColumns.add(col.name);
142
65
  }
@@ -227,3 +150,6 @@ const orderTablesByDependencies = (tables: TableDef[]): TableDef[] => {
227
150
  tables.forEach(t => visit(t.name, new Set()));
228
151
  return ordered;
229
152
  };
153
+
154
+ // Re-export DialectName for backward compatibility
155
+ export { DialectName };
@@ -1,32 +1,25 @@
1
- import { DialectName } from './schema-generator.js';
2
- import { DatabaseSchema } from './schema-types.js';
3
- import { DbExecutor } from '../../orm/db-executor.js';
4
- import type { IntrospectOptions, SchemaIntrospector } from './introspect/types.js';
5
- import { postgresIntrospector } from './introspect/postgres.js';
6
- import { mysqlIntrospector } from './introspect/mysql.js';
7
- import { sqliteIntrospector } from './introspect/sqlite.js';
8
- import { mssqlIntrospector } from './introspect/mssql.js';
9
-
10
- const INTROSPECTORS: Record<DialectName, SchemaIntrospector> = {
11
- postgres: postgresIntrospector,
12
- mysql: mysqlIntrospector,
13
- sqlite: sqliteIntrospector,
14
- mssql: mssqlIntrospector
15
- };
16
-
17
- /**
18
- * Introspects an existing database schema using the dialect-specific strategy.
19
- */
20
- export const introspectSchema = async (
21
- executor: DbExecutor,
22
- dialect: DialectName,
23
- options: IntrospectOptions = {}
24
- ): Promise<DatabaseSchema> => {
25
- const handler = INTROSPECTORS[dialect];
26
- if (!handler) {
27
- throw new Error(`Unsupported dialect for introspection: ${dialect}`);
28
- }
29
- return handler.introspect(executor, options);
30
- };
31
-
32
- export type { IntrospectOptions, SchemaIntrospector };
1
+ import { DialectName } from './schema-generator.js';
2
+ import { DatabaseSchema } from './schema-types.js';
3
+ import { DbExecutor } from '../execution/db-executor.js';
4
+ import type { IntrospectOptions, SchemaIntrospector, IntrospectContext } from './introspect/types.js';
5
+ import { getSchemaIntrospector } from './introspect/registry.js';
6
+ import { DialectFactory } from '../dialect/dialect-factory.js';
7
+
8
+ /**
9
+ * Introspects an existing database schema using the dialect-specific strategy.
10
+ */
11
+ export const introspectSchema = async (
12
+ executor: DbExecutor,
13
+ dialect: DialectName,
14
+ options: IntrospectOptions = {}
15
+ ): Promise<DatabaseSchema> => {
16
+ const handler = getSchemaIntrospector(dialect);
17
+ if (!handler) {
18
+ throw new Error(`Unsupported dialect for introspection: ${dialect}`);
19
+ }
20
+ const dialectInstance = DialectFactory.create(dialect);
21
+ const ctx: IntrospectContext = { executor, dialect: dialectInstance };
22
+ return handler.introspect(ctx, options);
23
+ };
24
+
25
+ export type { IntrospectOptions, SchemaIntrospector };
@@ -0,0 +1,17 @@
1
+ import { DbExecutor } from '../execution/db-executor.js';
2
+ import type { SchemaPlan, SynchronizeOptions } from './schema-diff.js';
3
+
4
+ export const executeSchemaPlan = async (
5
+ plan: SchemaPlan,
6
+ executor: DbExecutor,
7
+ options: SynchronizeOptions = {}
8
+ ): Promise<void> => {
9
+ for (const change of plan.changes) {
10
+ if (!change.statements.length) continue;
11
+ if (!change.safe && !options.allowDestructive) continue;
12
+ for (const stmt of change.statements) {
13
+ if (!stmt.trim()) continue;
14
+ await executor.executeSql(stmt);
15
+ }
16
+ }
17
+ };