linkgress-orm 0.2.17 → 0.3.1
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/README.md +2 -0
- package/dist/entity/db-context.d.ts +14 -0
- package/dist/entity/db-context.d.ts.map +1 -1
- package/dist/entity/db-context.js +16 -0
- package/dist/entity/db-context.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/migration/db-schema-manager.d.ts +2 -2
- package/dist/migration/db-schema-manager.d.ts.map +1 -1
- package/dist/migration/migration-journal.d.ts +52 -0
- package/dist/migration/migration-journal.d.ts.map +1 -0
- package/dist/migration/migration-journal.js +84 -0
- package/dist/migration/migration-journal.js.map +1 -0
- package/dist/migration/migration-loader.d.ts +70 -0
- package/dist/migration/migration-loader.d.ts.map +1 -0
- package/dist/migration/migration-loader.js +199 -0
- package/dist/migration/migration-loader.js.map +1 -0
- package/dist/migration/migration-runner.d.ts +84 -0
- package/dist/migration/migration-runner.d.ts.map +1 -0
- package/dist/migration/migration-runner.js +197 -0
- package/dist/migration/migration-runner.js.map +1 -0
- package/dist/migration/migration-scaffold.d.ts +100 -0
- package/dist/migration/migration-scaffold.d.ts.map +1 -0
- package/dist/migration/migration-scaffold.js +434 -0
- package/dist/migration/migration-scaffold.js.map +1 -0
- package/dist/migration/migration.interface.d.ts +108 -0
- package/dist/migration/migration.interface.d.ts.map +1 -0
- package/dist/migration/migration.interface.js +3 -0
- package/dist/migration/migration.interface.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { DatabaseContext } from '../entity/db-context';
|
|
2
|
+
import { MigrationConfig } from './migration.interface';
|
|
3
|
+
/**
|
|
4
|
+
* Generates migration scaffold files from schema differences.
|
|
5
|
+
*
|
|
6
|
+
* The scaffold generator:
|
|
7
|
+
* - Uses DbSchemaManager.analyze() to detect schema differences
|
|
8
|
+
* - Generates TypeScript migration files with up() and down() methods
|
|
9
|
+
* - Creates SQL statements for each detected change
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const scaffold = new MigrationScaffold(db, {
|
|
14
|
+
* migrationsDirectory: './migrations',
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // Generate migration from schema diff
|
|
18
|
+
* const result = await scaffold.scaffold('../schema/appDatabase');
|
|
19
|
+
* console.log(`Created: ${result.filename} with ${result.operations} operations`);
|
|
20
|
+
*
|
|
21
|
+
* // Generate empty migration template
|
|
22
|
+
* const empty = await scaffold.scaffoldEmpty();
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare class MigrationScaffold {
|
|
26
|
+
private db;
|
|
27
|
+
private config;
|
|
28
|
+
private loader;
|
|
29
|
+
constructor(db: DatabaseContext, config: MigrationConfig);
|
|
30
|
+
/**
|
|
31
|
+
* Generate SQL for a migration operation (UP direction).
|
|
32
|
+
*/
|
|
33
|
+
private generateUpSql;
|
|
34
|
+
/**
|
|
35
|
+
* Generate SQL for a migration operation (DOWN direction - reverse).
|
|
36
|
+
*/
|
|
37
|
+
private generateDownSql;
|
|
38
|
+
/**
|
|
39
|
+
* Build CREATE SEQUENCE SQL.
|
|
40
|
+
*/
|
|
41
|
+
private buildCreateSequenceSql;
|
|
42
|
+
/**
|
|
43
|
+
* Build CREATE TABLE SQL from schema.
|
|
44
|
+
*/
|
|
45
|
+
private buildCreateTableSql;
|
|
46
|
+
/**
|
|
47
|
+
* Build ADD COLUMN SQL.
|
|
48
|
+
*/
|
|
49
|
+
private buildAddColumnSql;
|
|
50
|
+
/**
|
|
51
|
+
* Build ALTER COLUMN SQL statements.
|
|
52
|
+
*/
|
|
53
|
+
private buildAlterColumnSql;
|
|
54
|
+
/**
|
|
55
|
+
* Build CREATE INDEX SQL.
|
|
56
|
+
*/
|
|
57
|
+
private buildCreateIndexSql;
|
|
58
|
+
/**
|
|
59
|
+
* Build CREATE FOREIGN KEY SQL.
|
|
60
|
+
*/
|
|
61
|
+
private buildCreateForeignKeySql;
|
|
62
|
+
/**
|
|
63
|
+
* Format a default value for SQL.
|
|
64
|
+
*/
|
|
65
|
+
private formatDefault;
|
|
66
|
+
/**
|
|
67
|
+
* Generate a migration file from schema differences.
|
|
68
|
+
*
|
|
69
|
+
* Compares the current database state to the DataContext model
|
|
70
|
+
* and generates a migration file with the necessary SQL statements.
|
|
71
|
+
*
|
|
72
|
+
* @param contextImportPath - Optional import path for the DataContext class
|
|
73
|
+
* @returns Information about the generated migration file
|
|
74
|
+
* @throws Error if no schema differences are detected
|
|
75
|
+
*/
|
|
76
|
+
scaffold(contextImportPath?: string): Promise<{
|
|
77
|
+
filename: string;
|
|
78
|
+
path: string;
|
|
79
|
+
operations: number;
|
|
80
|
+
}>;
|
|
81
|
+
/**
|
|
82
|
+
* Generate an empty migration file template.
|
|
83
|
+
*
|
|
84
|
+
* @param contextImportPath - Optional import path for the DataContext class
|
|
85
|
+
* @returns Information about the generated migration file
|
|
86
|
+
*/
|
|
87
|
+
scaffoldEmpty(contextImportPath?: string): Promise<{
|
|
88
|
+
filename: string;
|
|
89
|
+
path: string;
|
|
90
|
+
}>;
|
|
91
|
+
/**
|
|
92
|
+
* Generate migration file content with SQL statements.
|
|
93
|
+
*/
|
|
94
|
+
private generateMigrationFile;
|
|
95
|
+
/**
|
|
96
|
+
* Generate an empty migration file template.
|
|
97
|
+
*/
|
|
98
|
+
private generateEmptyMigrationFile;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=migration-scaffold.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration-scaffold.d.ts","sourceRoot":"","sources":["../../src/migration/migration-scaffold.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAQxD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,iBAAiB;IAI1B,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,MAAM;IAJhB,OAAO,CAAC,MAAM,CAAkB;gBAGtB,EAAE,EAAE,eAAe,EACnB,MAAM,EAAE,eAAe;IAKjC;;OAEG;IACH,OAAO,CAAC,aAAa;IA+DrB;;OAEG;IACH,OAAO,CAAC,eAAe;IA+DvB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAmB9B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAiD3B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAsBzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAqC3B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAqBhC;;OAEG;IACH,OAAO,CAAC,aAAa;IASrB;;;;;;;;;OASG;IACG,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAClD,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IA8BF;;;;;OAKG;IACG,aAAa,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QACvD,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IAWF;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA4B7B;;OAEG;IACH,OAAO,CAAC,0BAA0B;CA2BnC"}
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.MigrationScaffold = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const migration_loader_1 = require("./migration-loader");
|
|
40
|
+
const conditions_1 = require("../query/conditions");
|
|
41
|
+
/**
|
|
42
|
+
* Generates migration scaffold files from schema differences.
|
|
43
|
+
*
|
|
44
|
+
* The scaffold generator:
|
|
45
|
+
* - Uses DbSchemaManager.analyze() to detect schema differences
|
|
46
|
+
* - Generates TypeScript migration files with up() and down() methods
|
|
47
|
+
* - Creates SQL statements for each detected change
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const scaffold = new MigrationScaffold(db, {
|
|
52
|
+
* migrationsDirectory: './migrations',
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* // Generate migration from schema diff
|
|
56
|
+
* const result = await scaffold.scaffold('../schema/appDatabase');
|
|
57
|
+
* console.log(`Created: ${result.filename} with ${result.operations} operations`);
|
|
58
|
+
*
|
|
59
|
+
* // Generate empty migration template
|
|
60
|
+
* const empty = await scaffold.scaffoldEmpty();
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
class MigrationScaffold {
|
|
64
|
+
constructor(db, config) {
|
|
65
|
+
this.db = db;
|
|
66
|
+
this.config = config;
|
|
67
|
+
this.loader = new migration_loader_1.MigrationLoader(config.migrationsDirectory);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Generate SQL for a migration operation (UP direction).
|
|
71
|
+
*/
|
|
72
|
+
generateUpSql(op) {
|
|
73
|
+
switch (op.type) {
|
|
74
|
+
case 'create_schema':
|
|
75
|
+
return `CREATE SCHEMA IF NOT EXISTS "${op.schemaName}"`;
|
|
76
|
+
case 'create_enum': {
|
|
77
|
+
const enumValues = op.values.map((v) => `'${v}'`).join(', ');
|
|
78
|
+
return `CREATE TYPE "${op.enumName}" AS ENUM (${enumValues})`;
|
|
79
|
+
}
|
|
80
|
+
case 'create_sequence':
|
|
81
|
+
return this.buildCreateSequenceSql(op.config);
|
|
82
|
+
case 'create_table':
|
|
83
|
+
return this.buildCreateTableSql(op.tableName, op.schema);
|
|
84
|
+
case 'drop_table':
|
|
85
|
+
return `DROP TABLE IF EXISTS "${op.tableName}" CASCADE`;
|
|
86
|
+
case 'add_column':
|
|
87
|
+
return this.buildAddColumnSql(op.tableName, op.columnName, op.config, op.schema);
|
|
88
|
+
case 'drop_column': {
|
|
89
|
+
const qualifiedTable = op.schema
|
|
90
|
+
? `"${op.schema}"."${op.tableName}"`
|
|
91
|
+
: `"${op.tableName}"`;
|
|
92
|
+
return `ALTER TABLE ${qualifiedTable} DROP COLUMN "${op.columnName}"`;
|
|
93
|
+
}
|
|
94
|
+
case 'alter_column':
|
|
95
|
+
return this.buildAlterColumnSql(op.tableName, op.columnName, op.from, op.to, op.schema);
|
|
96
|
+
case 'create_index':
|
|
97
|
+
return this.buildCreateIndexSql(op.tableName, op.indexName, op.columns, op.isUnique, op.schema);
|
|
98
|
+
case 'drop_index': {
|
|
99
|
+
const qualifiedIndex = op.schema
|
|
100
|
+
? `"${op.schema}"."${op.indexName}"`
|
|
101
|
+
: `"${op.indexName}"`;
|
|
102
|
+
return `DROP INDEX IF EXISTS ${qualifiedIndex}`;
|
|
103
|
+
}
|
|
104
|
+
case 'create_foreign_key':
|
|
105
|
+
return this.buildCreateForeignKeySql(op.tableName, op.constraint, op.schema);
|
|
106
|
+
case 'drop_foreign_key': {
|
|
107
|
+
const fkTable = op.schema
|
|
108
|
+
? `"${op.schema}"."${op.tableName}"`
|
|
109
|
+
: `"${op.tableName}"`;
|
|
110
|
+
return `ALTER TABLE ${fkTable} DROP CONSTRAINT "${op.constraintName}"`;
|
|
111
|
+
}
|
|
112
|
+
default:
|
|
113
|
+
return `-- Unknown operation: ${op.type}`;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Generate SQL for a migration operation (DOWN direction - reverse).
|
|
118
|
+
*/
|
|
119
|
+
generateDownSql(op) {
|
|
120
|
+
switch (op.type) {
|
|
121
|
+
case 'create_schema':
|
|
122
|
+
return `DROP SCHEMA IF EXISTS "${op.schemaName}" CASCADE`;
|
|
123
|
+
case 'create_enum':
|
|
124
|
+
return `DROP TYPE IF EXISTS "${op.enumName}" CASCADE`;
|
|
125
|
+
case 'create_sequence': {
|
|
126
|
+
const seqName = op.config.schema
|
|
127
|
+
? `"${op.config.schema}"."${op.config.name}"`
|
|
128
|
+
: `"${op.config.name}"`;
|
|
129
|
+
return `DROP SEQUENCE IF EXISTS ${seqName} CASCADE`;
|
|
130
|
+
}
|
|
131
|
+
case 'create_table': {
|
|
132
|
+
const tableName = op.schema?.schema
|
|
133
|
+
? `"${op.schema.schema}"."${op.tableName}"`
|
|
134
|
+
: `"${op.tableName}"`;
|
|
135
|
+
return `DROP TABLE IF EXISTS ${tableName} CASCADE`;
|
|
136
|
+
}
|
|
137
|
+
case 'drop_table':
|
|
138
|
+
return `-- Cannot auto-generate: recreate table "${op.tableName}"`;
|
|
139
|
+
case 'add_column': {
|
|
140
|
+
const addColTable = op.schema
|
|
141
|
+
? `"${op.schema}"."${op.tableName}"`
|
|
142
|
+
: `"${op.tableName}"`;
|
|
143
|
+
return `ALTER TABLE ${addColTable} DROP COLUMN "${op.columnName}"`;
|
|
144
|
+
}
|
|
145
|
+
case 'drop_column':
|
|
146
|
+
return `-- Cannot auto-generate: recreate column "${op.columnName}" on table "${op.tableName}"`;
|
|
147
|
+
case 'alter_column':
|
|
148
|
+
return `-- Cannot auto-generate: revert column "${op.columnName}" changes on table "${op.tableName}"`;
|
|
149
|
+
case 'create_index': {
|
|
150
|
+
const idxName = op.schema
|
|
151
|
+
? `"${op.schema}"."${op.indexName}"`
|
|
152
|
+
: `"${op.indexName}"`;
|
|
153
|
+
return `DROP INDEX IF EXISTS ${idxName}`;
|
|
154
|
+
}
|
|
155
|
+
case 'drop_index':
|
|
156
|
+
return `-- Cannot auto-generate: recreate index "${op.indexName}"`;
|
|
157
|
+
case 'create_foreign_key': {
|
|
158
|
+
const fkTable = op.schema
|
|
159
|
+
? `"${op.schema}"."${op.tableName}"`
|
|
160
|
+
: `"${op.tableName}"`;
|
|
161
|
+
return `ALTER TABLE ${fkTable} DROP CONSTRAINT "${op.constraint.name}"`;
|
|
162
|
+
}
|
|
163
|
+
case 'drop_foreign_key':
|
|
164
|
+
return `-- Cannot auto-generate: recreate foreign key "${op.constraintName}"`;
|
|
165
|
+
default:
|
|
166
|
+
return `-- Unknown operation reversal: ${op.type}`;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Build CREATE SEQUENCE SQL.
|
|
171
|
+
*/
|
|
172
|
+
buildCreateSequenceSql(config) {
|
|
173
|
+
const name = config.schema
|
|
174
|
+
? `"${config.schema}"."${config.name}"`
|
|
175
|
+
: `"${config.name}"`;
|
|
176
|
+
let sql = `CREATE SEQUENCE ${name}`;
|
|
177
|
+
const options = [];
|
|
178
|
+
if (config.startWith !== undefined)
|
|
179
|
+
options.push(`START WITH ${config.startWith}`);
|
|
180
|
+
if (config.incrementBy !== undefined)
|
|
181
|
+
options.push(`INCREMENT BY ${config.incrementBy}`);
|
|
182
|
+
if (config.minValue !== undefined)
|
|
183
|
+
options.push(`MINVALUE ${config.minValue}`);
|
|
184
|
+
if (config.maxValue !== undefined)
|
|
185
|
+
options.push(`MAXVALUE ${config.maxValue}`);
|
|
186
|
+
if (config.cache !== undefined)
|
|
187
|
+
options.push(`CACHE ${config.cache}`);
|
|
188
|
+
if (config.cycle)
|
|
189
|
+
options.push(`CYCLE`);
|
|
190
|
+
if (options.length > 0)
|
|
191
|
+
sql += ` ${options.join(' ')}`;
|
|
192
|
+
return sql;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Build CREATE TABLE SQL from schema.
|
|
196
|
+
*/
|
|
197
|
+
buildCreateTableSql(tableName, schema) {
|
|
198
|
+
const qualifiedName = schema.schema
|
|
199
|
+
? `"${schema.schema}"."${tableName}"`
|
|
200
|
+
: `"${tableName}"`;
|
|
201
|
+
const columnDefs = [];
|
|
202
|
+
const primaryKeys = [];
|
|
203
|
+
for (const [colKey, colBuilder] of Object.entries(schema.columns)) {
|
|
204
|
+
const config = colBuilder.build();
|
|
205
|
+
let def = `"${config.name}" ${config.type}`;
|
|
206
|
+
if (config.length) {
|
|
207
|
+
def += `(${config.length})`;
|
|
208
|
+
}
|
|
209
|
+
else if (config.precision && config.scale) {
|
|
210
|
+
def += `(${config.precision}, ${config.scale})`;
|
|
211
|
+
}
|
|
212
|
+
else if (config.precision) {
|
|
213
|
+
def += `(${config.precision})`;
|
|
214
|
+
}
|
|
215
|
+
if (config.identity) {
|
|
216
|
+
def += ' GENERATED ALWAYS AS IDENTITY';
|
|
217
|
+
const seqOptions = [];
|
|
218
|
+
if (config.identity.startWith !== undefined) {
|
|
219
|
+
seqOptions.push(`START WITH ${config.identity.startWith}`);
|
|
220
|
+
}
|
|
221
|
+
if (config.identity.incrementBy !== undefined) {
|
|
222
|
+
seqOptions.push(`INCREMENT BY ${config.identity.incrementBy}`);
|
|
223
|
+
}
|
|
224
|
+
if (seqOptions.length > 0)
|
|
225
|
+
def += ` (${seqOptions.join(' ')})`;
|
|
226
|
+
}
|
|
227
|
+
if (!config.nullable)
|
|
228
|
+
def += ' NOT NULL';
|
|
229
|
+
if (config.unique && !config.primaryKey)
|
|
230
|
+
def += ' UNIQUE';
|
|
231
|
+
if (config.default !== undefined && !config.identity) {
|
|
232
|
+
def += ` DEFAULT ${this.formatDefault(config.default)}`;
|
|
233
|
+
}
|
|
234
|
+
columnDefs.push(def);
|
|
235
|
+
if (config.primaryKey)
|
|
236
|
+
primaryKeys.push(`"${config.name}"`);
|
|
237
|
+
}
|
|
238
|
+
if (primaryKeys.length > 0) {
|
|
239
|
+
columnDefs.push(`PRIMARY KEY (${primaryKeys.join(', ')})`);
|
|
240
|
+
}
|
|
241
|
+
return `CREATE TABLE ${qualifiedName} (\n ${columnDefs.join(',\n ')}\n )`;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Build ADD COLUMN SQL.
|
|
245
|
+
*/
|
|
246
|
+
buildAddColumnSql(tableName, columnName, config, schema) {
|
|
247
|
+
const qualifiedTable = schema
|
|
248
|
+
? `"${schema}"."${tableName}"`
|
|
249
|
+
: `"${tableName}"`;
|
|
250
|
+
let def = config.type;
|
|
251
|
+
if (config.length)
|
|
252
|
+
def += `(${config.length})`;
|
|
253
|
+
else if (config.precision && config.scale)
|
|
254
|
+
def += `(${config.precision}, ${config.scale})`;
|
|
255
|
+
else if (config.precision)
|
|
256
|
+
def += `(${config.precision})`;
|
|
257
|
+
if (!config.nullable)
|
|
258
|
+
def += ' NOT NULL';
|
|
259
|
+
if (config.unique)
|
|
260
|
+
def += ' UNIQUE';
|
|
261
|
+
if (config.default !== undefined)
|
|
262
|
+
def += ` DEFAULT ${this.formatDefault(config.default)}`;
|
|
263
|
+
return `ALTER TABLE ${qualifiedTable} ADD COLUMN "${columnName}" ${def}`;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Build ALTER COLUMN SQL statements.
|
|
267
|
+
*/
|
|
268
|
+
buildAlterColumnSql(tableName, columnName, from, to, schema) {
|
|
269
|
+
const qualifiedTable = schema
|
|
270
|
+
? `"${schema}"."${tableName}"`
|
|
271
|
+
: `"${tableName}"`;
|
|
272
|
+
const statements = [];
|
|
273
|
+
// Type change
|
|
274
|
+
if (from.data_type !== to.type) {
|
|
275
|
+
statements.push(`ALTER TABLE ${qualifiedTable} ALTER COLUMN "${columnName}" TYPE ${to.type}`);
|
|
276
|
+
}
|
|
277
|
+
// Nullability change
|
|
278
|
+
const fromNullable = from.is_nullable === 'YES';
|
|
279
|
+
if (fromNullable !== to.nullable) {
|
|
280
|
+
if (to.nullable) {
|
|
281
|
+
statements.push(`ALTER TABLE ${qualifiedTable} ALTER COLUMN "${columnName}" DROP NOT NULL`);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
statements.push(`ALTER TABLE ${qualifiedTable} ALTER COLUMN "${columnName}" SET NOT NULL`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return statements.length > 0 ? statements.join(';\n ') : `-- No changes for column "${columnName}"`;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Build CREATE INDEX SQL.
|
|
291
|
+
*/
|
|
292
|
+
buildCreateIndexSql(tableName, indexName, columns, isUnique, schema) {
|
|
293
|
+
const qualifiedTable = schema
|
|
294
|
+
? `"${schema}"."${tableName}"`
|
|
295
|
+
: `"${tableName}"`;
|
|
296
|
+
const uniqueStr = isUnique ? 'UNIQUE ' : '';
|
|
297
|
+
const columnList = columns.map(c => `"${c}"`).join(', ');
|
|
298
|
+
return `CREATE ${uniqueStr}INDEX "${indexName}" ON ${qualifiedTable} (${columnList})`;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Build CREATE FOREIGN KEY SQL.
|
|
302
|
+
*/
|
|
303
|
+
buildCreateForeignKeySql(tableName, constraint, schema) {
|
|
304
|
+
const qualifiedTable = schema
|
|
305
|
+
? `"${schema}"."${tableName}"`
|
|
306
|
+
: `"${tableName}"`;
|
|
307
|
+
const columnList = constraint.columns.map((c) => `"${c}"`).join(', ');
|
|
308
|
+
const refColumnList = constraint.referencedColumns.map((c) => `"${c}"`).join(', ');
|
|
309
|
+
let sql = `ALTER TABLE ${qualifiedTable} ADD CONSTRAINT "${constraint.name}" `;
|
|
310
|
+
sql += `FOREIGN KEY (${columnList}) REFERENCES "${constraint.referencedTable}" (${refColumnList})`;
|
|
311
|
+
if (constraint.onDelete)
|
|
312
|
+
sql += ` ON DELETE ${constraint.onDelete.toUpperCase()}`;
|
|
313
|
+
if (constraint.onUpdate)
|
|
314
|
+
sql += ` ON UPDATE ${constraint.onUpdate.toUpperCase()}`;
|
|
315
|
+
return sql;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Format a default value for SQL.
|
|
319
|
+
*/
|
|
320
|
+
formatDefault(value) {
|
|
321
|
+
if (value === null)
|
|
322
|
+
return 'NULL';
|
|
323
|
+
if (value instanceof conditions_1.RawSql)
|
|
324
|
+
return value.value;
|
|
325
|
+
if (typeof value === 'string')
|
|
326
|
+
return value;
|
|
327
|
+
if (typeof value === 'boolean')
|
|
328
|
+
return value ? 'TRUE' : 'FALSE';
|
|
329
|
+
if (value instanceof Date)
|
|
330
|
+
return `'${value.toISOString()}'`;
|
|
331
|
+
return String(value);
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Generate a migration file from schema differences.
|
|
335
|
+
*
|
|
336
|
+
* Compares the current database state to the DataContext model
|
|
337
|
+
* and generates a migration file with the necessary SQL statements.
|
|
338
|
+
*
|
|
339
|
+
* @param contextImportPath - Optional import path for the DataContext class
|
|
340
|
+
* @returns Information about the generated migration file
|
|
341
|
+
* @throws Error if no schema differences are detected
|
|
342
|
+
*/
|
|
343
|
+
async scaffold(contextImportPath) {
|
|
344
|
+
// Use DbSchemaManager.analyze() to get differences
|
|
345
|
+
const schemaManager = this.db.getSchemaManager();
|
|
346
|
+
const operations = await schemaManager.analyze();
|
|
347
|
+
if (operations.length === 0) {
|
|
348
|
+
throw new Error('No schema differences detected. Database is in sync with model.');
|
|
349
|
+
}
|
|
350
|
+
// Generate filename
|
|
351
|
+
const filename = this.loader.generateFilename();
|
|
352
|
+
// Build migration file content
|
|
353
|
+
const upStatements = operations.map(op => this.generateUpSql(op));
|
|
354
|
+
const downStatements = operations.map(op => this.generateDownSql(op)).reverse();
|
|
355
|
+
const content = this.generateMigrationFile(upStatements, downStatements, contextImportPath);
|
|
356
|
+
// Write file
|
|
357
|
+
this.loader.ensureDirectory();
|
|
358
|
+
const filePath = path.join(this.loader.getAbsoluteDirectory(), filename);
|
|
359
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
360
|
+
return {
|
|
361
|
+
filename,
|
|
362
|
+
path: filePath,
|
|
363
|
+
operations: operations.length,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Generate an empty migration file template.
|
|
368
|
+
*
|
|
369
|
+
* @param contextImportPath - Optional import path for the DataContext class
|
|
370
|
+
* @returns Information about the generated migration file
|
|
371
|
+
*/
|
|
372
|
+
async scaffoldEmpty(contextImportPath) {
|
|
373
|
+
const filename = this.loader.generateFilename();
|
|
374
|
+
const content = this.generateEmptyMigrationFile(contextImportPath);
|
|
375
|
+
this.loader.ensureDirectory();
|
|
376
|
+
const filePath = path.join(this.loader.getAbsoluteDirectory(), filename);
|
|
377
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
378
|
+
return { filename, path: filePath };
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Generate migration file content with SQL statements.
|
|
382
|
+
*/
|
|
383
|
+
generateMigrationFile(upStatements, downStatements, contextImportPath) {
|
|
384
|
+
const contextImport = contextImportPath
|
|
385
|
+
? `import type { AppDatabase } from '${contextImportPath}';`
|
|
386
|
+
: `import type { DbContext } from 'linkgress-orm';`;
|
|
387
|
+
const contextType = contextImportPath ? 'AppDatabase' : 'DbContext';
|
|
388
|
+
return `import type { Migration } from 'linkgress-orm';
|
|
389
|
+
${contextImport}
|
|
390
|
+
|
|
391
|
+
export default class implements Migration {
|
|
392
|
+
async up(db: ${contextType}): Promise<void> {
|
|
393
|
+
// Execute each statement separately for compatibility with all database clients
|
|
394
|
+
${upStatements.map(s => ` await db.query(\`${s}\`);`).join('\n')}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
async down(db: ${contextType}): Promise<void> {
|
|
398
|
+
// Execute each statement separately for compatibility with all database clients
|
|
399
|
+
${downStatements.map(s => ` await db.query(\`${s}\`);`).join('\n')}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
`;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Generate an empty migration file template.
|
|
406
|
+
*/
|
|
407
|
+
generateEmptyMigrationFile(contextImportPath) {
|
|
408
|
+
const contextImport = contextImportPath
|
|
409
|
+
? `import type { AppDatabase } from '${contextImportPath}';`
|
|
410
|
+
: `import type { DbContext } from 'linkgress-orm';`;
|
|
411
|
+
const contextType = contextImportPath ? 'AppDatabase' : 'DbContext';
|
|
412
|
+
return `import type { Migration } from 'linkgress-orm';
|
|
413
|
+
${contextImport}
|
|
414
|
+
|
|
415
|
+
export default class implements Migration {
|
|
416
|
+
async up(db: ${contextType}): Promise<void> {
|
|
417
|
+
// Add your migration SQL here
|
|
418
|
+
await db.query(\`
|
|
419
|
+
-- Your UP migration SQL
|
|
420
|
+
\`);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
async down(db: ${contextType}): Promise<void> {
|
|
424
|
+
// Add your rollback SQL here
|
|
425
|
+
await db.query(\`
|
|
426
|
+
-- Your DOWN migration SQL
|
|
427
|
+
\`);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
`;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
exports.MigrationScaffold = MigrationScaffold;
|
|
434
|
+
//# sourceMappingURL=migration-scaffold.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration-scaffold.js","sourceRoot":"","sources":["../../src/migration/migration-scaffold.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { DatabaseContext } from '../entity/db-context';
|
|
2
|
+
/**
|
|
3
|
+
* Migration interface that all migration files must implement.
|
|
4
|
+
*
|
|
5
|
+
* Each migration has an up() method to apply changes and a down() method to revert them.
|
|
6
|
+
* The db parameter provides full access to the DataContext for raw SQL execution.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* export default class implements Migration {
|
|
11
|
+
* async up(db: AppDatabase): Promise<void> {
|
|
12
|
+
* await db.client.querySimple(`
|
|
13
|
+
* ALTER TABLE users ADD COLUMN new_field TEXT;
|
|
14
|
+
* `);
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* async down(db: AppDatabase): Promise<void> {
|
|
18
|
+
* await db.client.querySimple(`
|
|
19
|
+
* ALTER TABLE users DROP COLUMN new_field;
|
|
20
|
+
* `);
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export interface Migration {
|
|
26
|
+
/**
|
|
27
|
+
* Apply the migration (upgrade)
|
|
28
|
+
* @param db - The DataContext instance for executing queries
|
|
29
|
+
*/
|
|
30
|
+
up(db: DatabaseContext): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Revert the migration (downgrade)
|
|
33
|
+
* @param db - The DataContext instance for executing queries
|
|
34
|
+
*/
|
|
35
|
+
down(db: DatabaseContext): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Configuration for the migration system
|
|
39
|
+
*/
|
|
40
|
+
export interface MigrationConfig {
|
|
41
|
+
/**
|
|
42
|
+
* Directory containing migration files.
|
|
43
|
+
* Can be relative to process.cwd() or absolute.
|
|
44
|
+
*/
|
|
45
|
+
migrationsDirectory: string;
|
|
46
|
+
/**
|
|
47
|
+
* Name of the journal table that tracks applied migrations.
|
|
48
|
+
* @default '__migrations'
|
|
49
|
+
*/
|
|
50
|
+
journalTable?: string;
|
|
51
|
+
/**
|
|
52
|
+
* PostgreSQL schema for the journal table.
|
|
53
|
+
* @default 'public'
|
|
54
|
+
*/
|
|
55
|
+
journalSchema?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Enable verbose logging of migration progress.
|
|
58
|
+
* @default false
|
|
59
|
+
*/
|
|
60
|
+
verbose?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Custom logger function. If not provided, uses console.log.
|
|
63
|
+
*/
|
|
64
|
+
logger?: (message: string) => void;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Journal entry representing an applied migration stored in the database
|
|
68
|
+
*/
|
|
69
|
+
export interface MigrationJournalEntry {
|
|
70
|
+
/** Auto-generated ID */
|
|
71
|
+
id: number;
|
|
72
|
+
/** Migration filename (e.g., '20260204-143052.ts') */
|
|
73
|
+
filename: string;
|
|
74
|
+
/** Timestamp when the migration was applied */
|
|
75
|
+
applied_at: Date;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Loaded migration with metadata from the filesystem
|
|
79
|
+
*/
|
|
80
|
+
export interface LoadedMigration {
|
|
81
|
+
/** Migration filename */
|
|
82
|
+
filename: string;
|
|
83
|
+
/** Parsed timestamp from filename (YYYYMMDD-HHMMSS) */
|
|
84
|
+
timestamp: string;
|
|
85
|
+
/** The migration instance */
|
|
86
|
+
migration: Migration;
|
|
87
|
+
/** Absolute path to the migration file */
|
|
88
|
+
filePath: string;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Result of running migrations
|
|
92
|
+
*/
|
|
93
|
+
export interface MigrationRunResult {
|
|
94
|
+
/** List of successfully applied migration filenames */
|
|
95
|
+
applied: string[];
|
|
96
|
+
/** List of skipped migration filenames (already applied) */
|
|
97
|
+
skipped: string[];
|
|
98
|
+
/** If a migration failed, contains the filename and error */
|
|
99
|
+
failed?: {
|
|
100
|
+
filename: string;
|
|
101
|
+
error: Error;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Direction for migration execution
|
|
106
|
+
*/
|
|
107
|
+
export type MigrationDirection = 'up' | 'down';
|
|
108
|
+
//# sourceMappingURL=migration.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration.interface.d.ts","sourceRoot":"","sources":["../../src/migration/migration.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,SAAS;IACxB;;;OAGG;IACH,EAAE,CAAC,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvC;;;OAGG;IACH,IAAI,CAAC,EAAE,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAE5B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,wBAAwB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,UAAU,EAAE,IAAI,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,SAAS,EAAE,SAAS,CAAC;IACrB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uDAAuD;IACvD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,6DAA6D;IAC7D,MAAM,CAAC,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,KAAK,CAAC;KACd,CAAC;CACH;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,MAAM,CAAC"}
|