metal-orm 1.0.14 → 1.0.16

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 (129) hide show
  1. package/README.md +69 -67
  2. package/dist/decorators/index.cjs +1983 -224
  3. package/dist/decorators/index.cjs.map +1 -1
  4. package/dist/decorators/index.d.cts +6 -6
  5. package/dist/decorators/index.d.ts +6 -6
  6. package/dist/decorators/index.js +1982 -224
  7. package/dist/decorators/index.js.map +1 -1
  8. package/dist/index.cjs +5284 -3751
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +524 -169
  11. package/dist/index.d.ts +524 -169
  12. package/dist/index.js +5197 -3736
  13. package/dist/index.js.map +1 -1
  14. package/dist/{select-CCp1oz9p.d.cts → select-BKZrMRCQ.d.cts} +555 -94
  15. package/dist/{select-CCp1oz9p.d.ts → select-BKZrMRCQ.d.ts} +555 -94
  16. package/package.json +1 -1
  17. package/src/codegen/naming-strategy.ts +64 -0
  18. package/src/codegen/typescript.ts +19 -21
  19. package/src/core/ast/adapters.ts +21 -0
  20. package/src/core/ast/aggregate-functions.ts +13 -13
  21. package/src/core/ast/builders.ts +56 -43
  22. package/src/core/ast/expression-builders.ts +34 -34
  23. package/src/core/ast/expression-nodes.ts +18 -16
  24. package/src/core/ast/expression-visitor.ts +122 -69
  25. package/src/core/ast/expression.ts +6 -4
  26. package/src/core/ast/join-metadata.ts +15 -0
  27. package/src/core/ast/join-node.ts +22 -20
  28. package/src/core/ast/join.ts +5 -5
  29. package/src/core/ast/query.ts +52 -88
  30. package/src/core/ast/types.ts +20 -0
  31. package/src/core/ast/window-functions.ts +55 -55
  32. package/src/core/ddl/dialects/base-schema-dialect.ts +20 -6
  33. package/src/core/ddl/dialects/mssql-schema-dialect.ts +32 -8
  34. package/src/core/ddl/dialects/mysql-schema-dialect.ts +21 -10
  35. package/src/core/ddl/dialects/postgres-schema-dialect.ts +52 -7
  36. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +23 -9
  37. package/src/core/ddl/introspect/catalogs/index.ts +1 -0
  38. package/src/core/ddl/introspect/catalogs/postgres.ts +143 -0
  39. package/src/core/ddl/introspect/context.ts +9 -0
  40. package/src/core/ddl/introspect/functions/postgres.ts +26 -0
  41. package/src/core/ddl/introspect/mssql.ts +149 -149
  42. package/src/core/ddl/introspect/mysql.ts +99 -99
  43. package/src/core/ddl/introspect/postgres.ts +245 -154
  44. package/src/core/ddl/introspect/registry.ts +26 -0
  45. package/src/core/ddl/introspect/run-select.ts +25 -0
  46. package/src/core/ddl/introspect/sqlite.ts +7 -7
  47. package/src/core/ddl/introspect/types.ts +23 -19
  48. package/src/core/ddl/introspect/utils.ts +1 -1
  49. package/src/core/ddl/naming-strategy.ts +10 -0
  50. package/src/core/ddl/schema-dialect.ts +41 -0
  51. package/src/core/ddl/schema-diff.ts +211 -179
  52. package/src/core/ddl/schema-generator.ts +17 -90
  53. package/src/core/ddl/schema-introspect.ts +25 -32
  54. package/src/core/ddl/schema-plan-executor.ts +17 -0
  55. package/src/core/ddl/schema-types.ts +46 -39
  56. package/src/core/ddl/sql-writing.ts +170 -0
  57. package/src/core/dialect/abstract.ts +172 -126
  58. package/src/core/dialect/base/cte-compiler.ts +33 -0
  59. package/src/core/dialect/base/function-table-formatter.ts +132 -0
  60. package/src/core/dialect/base/groupby-compiler.ts +21 -0
  61. package/src/core/dialect/base/join-compiler.ts +26 -0
  62. package/src/core/dialect/base/orderby-compiler.ts +21 -0
  63. package/src/core/dialect/base/pagination-strategy.ts +32 -0
  64. package/src/core/dialect/base/returning-strategy.ts +56 -0
  65. package/src/core/dialect/base/sql-dialect.ts +181 -204
  66. package/src/core/dialect/dialect-factory.ts +91 -0
  67. package/src/core/dialect/mssql/functions.ts +101 -0
  68. package/src/core/dialect/mssql/index.ts +128 -126
  69. package/src/core/dialect/mysql/functions.ts +101 -0
  70. package/src/core/dialect/mysql/index.ts +20 -18
  71. package/src/core/dialect/postgres/functions.ts +95 -0
  72. package/src/core/dialect/postgres/index.ts +30 -28
  73. package/src/core/dialect/sqlite/functions.ts +115 -0
  74. package/src/core/dialect/sqlite/index.ts +30 -28
  75. package/src/core/driver/database-driver.ts +11 -0
  76. package/src/core/driver/mssql-driver.ts +20 -0
  77. package/src/core/driver/mysql-driver.ts +20 -0
  78. package/src/core/driver/postgres-driver.ts +20 -0
  79. package/src/core/driver/sqlite-driver.ts +20 -0
  80. package/src/core/execution/db-executor.ts +63 -0
  81. package/src/core/execution/executors/mssql-executor.ts +39 -0
  82. package/src/core/execution/executors/mysql-executor.ts +47 -0
  83. package/src/core/execution/executors/postgres-executor.ts +32 -0
  84. package/src/core/execution/executors/sqlite-executor.ts +31 -0
  85. package/src/core/functions/datetime.ts +132 -0
  86. package/src/core/functions/numeric.ts +179 -0
  87. package/src/core/functions/standard-strategy.ts +47 -0
  88. package/src/core/functions/text.ts +147 -0
  89. package/src/core/functions/types.ts +18 -0
  90. package/src/core/hydration/types.ts +57 -0
  91. package/src/decorators/bootstrap.ts +10 -0
  92. package/src/decorators/column.ts +13 -4
  93. package/src/decorators/relations.ts +15 -0
  94. package/src/index.ts +37 -19
  95. package/src/orm/entity-context.ts +30 -0
  96. package/src/orm/entity-meta.ts +2 -2
  97. package/src/orm/entity-metadata.ts +8 -6
  98. package/src/orm/entity.ts +72 -41
  99. package/src/orm/execute.ts +42 -25
  100. package/src/orm/execution-context.ts +12 -0
  101. package/src/orm/hydration-context.ts +14 -0
  102. package/src/orm/hydration.ts +25 -17
  103. package/src/orm/identity-map.ts +4 -0
  104. package/src/orm/interceptor-pipeline.ts +29 -0
  105. package/src/orm/lazy-batch.ts +50 -6
  106. package/src/orm/orm-session.ts +234 -0
  107. package/src/orm/orm.ts +58 -0
  108. package/src/orm/query-logger.ts +1 -1
  109. package/src/orm/relation-change-processor.ts +48 -3
  110. package/src/orm/relations/belongs-to.ts +45 -44
  111. package/src/orm/relations/has-many.ts +44 -43
  112. package/src/orm/relations/has-one.ts +140 -0
  113. package/src/orm/relations/many-to-many.ts +46 -45
  114. package/src/orm/transaction-runner.ts +1 -1
  115. package/src/orm/unit-of-work.ts +66 -61
  116. package/src/query-builder/delete.ts +22 -5
  117. package/src/query-builder/hydration-manager.ts +2 -1
  118. package/src/query-builder/hydration-planner.ts +8 -7
  119. package/src/query-builder/insert.ts +22 -5
  120. package/src/query-builder/relation-conditions.ts +9 -8
  121. package/src/query-builder/relation-service.ts +3 -2
  122. package/src/query-builder/select.ts +575 -64
  123. package/src/query-builder/update.ts +22 -5
  124. package/src/schema/column.ts +246 -246
  125. package/src/schema/relation.ts +35 -1
  126. package/src/schema/table.ts +28 -28
  127. package/src/schema/types.ts +41 -31
  128. package/src/orm/db-executor.ts +0 -11
  129. package/src/orm/orm-context.ts +0 -159
@@ -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,22 @@
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 } 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';
13
+ import { DialectName } from './schema-dialect.js';
31
14
 
32
15
  export interface SchemaGenerateResult {
33
16
  tableSql: string;
34
17
  indexSql: string[];
35
18
  }
36
19
 
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
20
  export interface RenderColumnOptions {
97
21
  includePrimary?: boolean;
98
22
  }
@@ -136,7 +60,7 @@ export const generateCreateTableSql = (
136
60
  const inlinePkColumns = new Set<string>();
137
61
 
138
62
  const columnLines = Object.values(table.columns).map(col => {
139
- const includePk = dialect.preferInlinePkAutoincrement?.(col, table, pk) && pk.includes(col.name);
63
+ const includePk = (dialect as any).preferInlinePkAutoincrement?.(col, table, pk) && pk.includes(col.name);
140
64
  if (includePk) {
141
65
  inlinePkColumns.add(col.name);
142
66
  }
@@ -227,3 +151,6 @@ const orderTablesByDependencies = (tables: TableDef[]): TableDef[] => {
227
151
  tables.forEach(t => visit(t.name, new Set()));
228
152
  return ordered;
229
153
  };
154
+
155
+ // Re-export DialectName for backward compatibility
156
+ export type { 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 type { 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
+ };