@loomcore/api 0.1.48 → 0.1.50
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.
|
@@ -4,13 +4,13 @@ export declare class MigrationRunner {
|
|
|
4
4
|
private dbUrl;
|
|
5
5
|
private migrationsDir;
|
|
6
6
|
private primaryTimezone;
|
|
7
|
-
private
|
|
7
|
+
private dbConnection;
|
|
8
8
|
constructor(config: IBaseApiConfig);
|
|
9
9
|
private getTimestamp;
|
|
10
10
|
private parseSql;
|
|
11
11
|
private getMigrator;
|
|
12
12
|
private wipeDatabase;
|
|
13
|
-
run(command: 'up' | 'down' | 'reset'): Promise<void>;
|
|
13
|
+
run(command: 'up' | 'down' | 'reset', target?: string): Promise<void>;
|
|
14
14
|
private closeConnection;
|
|
15
15
|
create(name: string): Promise<void>;
|
|
16
16
|
}
|
|
@@ -10,7 +10,7 @@ export class MigrationRunner {
|
|
|
10
10
|
dbUrl;
|
|
11
11
|
migrationsDir;
|
|
12
12
|
primaryTimezone;
|
|
13
|
-
|
|
13
|
+
dbConnection;
|
|
14
14
|
constructor(config) {
|
|
15
15
|
this.dbType = config.app.dbType || 'mongodb';
|
|
16
16
|
this.dbUrl = this.dbType === 'postgres' ? buildPostgresUrl(config) : buildMongoUrl(config);
|
|
@@ -33,27 +33,41 @@ export class MigrationRunner {
|
|
|
33
33
|
const getPart = (type) => parts.find(p => p.type === type)?.value || '00';
|
|
34
34
|
return `${getPart('year')}${getPart('month')}${getPart('day')}${getPart('hour')}${getPart('minute')}${getPart('second')}`;
|
|
35
35
|
}
|
|
36
|
-
parseSql(content) {
|
|
37
|
-
const upMatch = content.match(/--\s*up\s([\s\S]+?)(?=--\s*down|$)/i);
|
|
38
|
-
const downMatch = content.match(/--\s*down\s([\s\S]+)/i);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
parseSql(filename, content) {
|
|
37
|
+
const upMatch = content.match(/--\s*up\s+([\s\S]+?)(?=--\s*down|$)/i);
|
|
38
|
+
const downMatch = content.match(/--\s*down\s+([\s\S]+)/i);
|
|
39
|
+
const upSql = upMatch ? upMatch[1].trim() : '';
|
|
40
|
+
const downSql = downMatch ? downMatch[1].trim() : '';
|
|
41
|
+
if (!upSql && this.dbType === 'postgres') {
|
|
42
|
+
throw new Error(`❌ Parsing Error in ${filename}: Could not find '-- up' section or it was empty.`);
|
|
43
|
+
}
|
|
44
|
+
return { up: upSql, down: downSql };
|
|
43
45
|
}
|
|
44
46
|
async getMigrator() {
|
|
47
|
+
if (!fs.existsSync(this.migrationsDir)) {
|
|
48
|
+
throw new Error(`❌ Migrations directory not found at: ${this.migrationsDir}`);
|
|
49
|
+
}
|
|
45
50
|
if (this.dbType === 'postgres') {
|
|
46
51
|
const pool = new Pool({ connectionString: this.dbUrl });
|
|
52
|
+
this.dbConnection = pool;
|
|
53
|
+
const globPattern = path.join(this.migrationsDir, '*.sql').replace(/\\/g, '/');
|
|
54
|
+
console.log(`🔎 Looking for migrations in: ${globPattern}`);
|
|
47
55
|
return new Umzug({
|
|
48
56
|
migrations: {
|
|
49
|
-
glob:
|
|
57
|
+
glob: globPattern,
|
|
50
58
|
resolve: ({ name, path: filePath, context }) => {
|
|
51
59
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
52
|
-
const { up, down } = this.parseSql(content);
|
|
60
|
+
const { up, down } = this.parseSql(name, content);
|
|
53
61
|
return {
|
|
54
62
|
name,
|
|
55
|
-
up: async () =>
|
|
56
|
-
|
|
63
|
+
up: async () => {
|
|
64
|
+
console.log(` Running SQL for ${name}...`);
|
|
65
|
+
await context.query(up);
|
|
66
|
+
},
|
|
67
|
+
down: async () => {
|
|
68
|
+
console.log(` Running Undo SQL for ${name}...`);
|
|
69
|
+
await context.query(down);
|
|
70
|
+
}
|
|
57
71
|
};
|
|
58
72
|
}
|
|
59
73
|
},
|
|
@@ -71,15 +85,17 @@ export class MigrationRunner {
|
|
|
71
85
|
await context.query(`DELETE FROM migrations WHERE name = $1`, [name]);
|
|
72
86
|
}
|
|
73
87
|
},
|
|
74
|
-
logger:
|
|
88
|
+
logger: undefined,
|
|
75
89
|
});
|
|
76
90
|
}
|
|
77
91
|
else if (this.dbType === 'mongodb') {
|
|
78
92
|
const client = await MongoClient.connect(this.dbUrl);
|
|
79
|
-
this.
|
|
93
|
+
this.dbConnection = client;
|
|
80
94
|
const db = client.db();
|
|
95
|
+
const globPattern = path.join(this.migrationsDir, '*.ts').replace(/\\/g, '/');
|
|
96
|
+
console.log(`🔎 Looking for migrations in: ${globPattern}`);
|
|
81
97
|
return new Umzug({
|
|
82
|
-
migrations: { glob:
|
|
98
|
+
migrations: { glob: globPattern },
|
|
83
99
|
context: db,
|
|
84
100
|
storage: new MongoDBStorage({ collection: db.collection('migrations') }),
|
|
85
101
|
logger: console,
|
|
@@ -105,42 +121,62 @@ export class MigrationRunner {
|
|
|
105
121
|
}
|
|
106
122
|
console.log('✅ Database wiped.');
|
|
107
123
|
}
|
|
108
|
-
async run(command) {
|
|
124
|
+
async run(command, target) {
|
|
109
125
|
try {
|
|
110
126
|
if (command === 'reset') {
|
|
111
127
|
await this.wipeDatabase();
|
|
112
128
|
console.log('🚀 Restarting migrations...');
|
|
113
129
|
const migrator = await this.getMigrator();
|
|
114
|
-
await migrator.up();
|
|
115
|
-
await this.closeConnection(
|
|
130
|
+
await migrator.up(target ? { to: target } : undefined);
|
|
131
|
+
await this.closeConnection();
|
|
116
132
|
console.log('✅ Reset complete.');
|
|
117
133
|
return;
|
|
118
134
|
}
|
|
119
135
|
const migrator = await this.getMigrator();
|
|
136
|
+
migrator.on('migrating', ({ name }) => console.log(`🚀 Migrating: ${name}`));
|
|
137
|
+
migrator.on('migrated', ({ name }) => console.log(`✅ Completed: ${name}`));
|
|
138
|
+
const pending = await migrator.pending();
|
|
139
|
+
console.log(`ℹ️ Found ${pending.length} pending migrations.`);
|
|
140
|
+
if (pending.length === 0 && command === 'up') {
|
|
141
|
+
console.log('⚠️ No pending migrations. (Check the path/glob if this is unexpected)');
|
|
142
|
+
}
|
|
120
143
|
switch (command) {
|
|
121
144
|
case 'up':
|
|
122
|
-
await migrator.up();
|
|
123
|
-
console.log('✅ Migrations up to date.');
|
|
145
|
+
await migrator.up(target ? { to: target } : undefined);
|
|
146
|
+
console.log(target ? `✅ Migrated up to ${target}` : '✅ Migrations up to date.');
|
|
124
147
|
break;
|
|
125
148
|
case 'down':
|
|
126
|
-
|
|
127
|
-
|
|
149
|
+
if (target) {
|
|
150
|
+
await migrator.down({ to: target });
|
|
151
|
+
console.log(`✅ Reverted down to ${target}`);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
await migrator.down();
|
|
155
|
+
console.log('✅ Reverted last migration.');
|
|
156
|
+
}
|
|
128
157
|
break;
|
|
129
158
|
}
|
|
130
|
-
await this.closeConnection(
|
|
159
|
+
await this.closeConnection();
|
|
131
160
|
}
|
|
132
161
|
catch (err) {
|
|
133
162
|
console.error('❌ Migration failed:', err);
|
|
163
|
+
await this.closeConnection();
|
|
134
164
|
process.exit(1);
|
|
135
165
|
}
|
|
136
166
|
}
|
|
137
|
-
async closeConnection(
|
|
138
|
-
if (this.
|
|
139
|
-
|
|
167
|
+
async closeConnection() {
|
|
168
|
+
if (!this.dbConnection)
|
|
169
|
+
return;
|
|
170
|
+
try {
|
|
171
|
+
if (this.dbType === 'postgres') {
|
|
172
|
+
await this.dbConnection.end();
|
|
173
|
+
}
|
|
174
|
+
else if (this.dbType === 'mongo') {
|
|
175
|
+
await this.dbConnection.close();
|
|
176
|
+
}
|
|
140
177
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
this.mongoClient = null;
|
|
178
|
+
catch (e) {
|
|
179
|
+
console.warn('Warning: Error closing connection', e);
|
|
144
180
|
}
|
|
145
181
|
}
|
|
146
182
|
async create(name) {
|