@flusys/nestjs-core 6.0.0 ā 6.0.2
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/cjs/migration/datasource.factory.js +1 -11
- package/cjs/migration/index.js +3 -0
- package/cjs/migration/migration.cli.js +22 -2
- package/cjs/migration/migration.runner.js +69 -0
- package/cjs/utils/datasource-config.builder.js +17 -0
- package/fesm/migration/datasource.factory.js +2 -12
- package/fesm/migration/index.js +1 -1
- package/fesm/migration/migration.cli.js +23 -3
- package/fesm/migration/migration.runner.js +67 -1
- package/fesm/utils/datasource-config.builder.js +16 -0
- package/migration/index.d.ts +1 -1
- package/migration/migration.runner.d.ts +1 -0
- package/package.json +1 -1
- package/utils/datasource-config.builder.d.ts +1 -0
|
@@ -28,17 +28,7 @@ function createMigrationDataSource(options) {
|
|
|
28
28
|
console.log(`\nš” Multi-tenant mode. Available tenants:`);
|
|
29
29
|
config.tenants.forEach((t)=>console.log(` - TENANT_ID=${t.id} ā ${t.database}`));
|
|
30
30
|
}
|
|
31
|
-
const dbConfig =
|
|
32
|
-
...config.defaultDatabaseConfig,
|
|
33
|
-
host: tenant.host ?? config.defaultDatabaseConfig.host,
|
|
34
|
-
port: tenant.port ?? config.defaultDatabaseConfig.port,
|
|
35
|
-
username: tenant.username ?? config.defaultDatabaseConfig.username,
|
|
36
|
-
password: tenant.password ?? config.defaultDatabaseConfig.password,
|
|
37
|
-
database: tenant.database
|
|
38
|
-
} : {
|
|
39
|
-
...config.defaultDatabaseConfig,
|
|
40
|
-
database
|
|
41
|
-
};
|
|
31
|
+
const dbConfig = (0, _datasourceconfigbuilder.resolveDatabaseConnection)(config, tenantId);
|
|
42
32
|
const entities = (0, _datasourceconfigbuilder.resolveEntities)(config, tenantConfig);
|
|
43
33
|
const dsOptions = (0, _datasourceconfigbuilder.buildDataSourceOptions)(dbConfig, entities, (0, _datasourceconfigbuilder.getMigrationsGlobPattern)(config.migrationsPath, tenantId), config.migrationsTableName);
|
|
44
34
|
return new _typeorm.DataSource({
|
package/cjs/migration/index.js
CHANGED
|
@@ -64,6 +64,7 @@ Commands:
|
|
|
64
64
|
generate --name=<Name> Generate migration
|
|
65
65
|
run Run pending migrations
|
|
66
66
|
revert Revert last migration
|
|
67
|
+
reset Drop db, wipe migration files, recreate db, generate + run initial migration (dev only)
|
|
67
68
|
status Show migration status
|
|
68
69
|
run:all Run for all tenants
|
|
69
70
|
revert:all Revert for all tenants
|
|
@@ -72,6 +73,7 @@ Commands:
|
|
|
72
73
|
Options:
|
|
73
74
|
--config=<path> Migration config file (default: src/persistence/migration.config.ts)
|
|
74
75
|
--name=<Name> Migration name (for generate command)
|
|
76
|
+
--force Required to run 'reset' when MODE is not 'dev'
|
|
75
77
|
|
|
76
78
|
Environment:
|
|
77
79
|
TENANT_ID Target tenant (default: uses default database)
|
|
@@ -82,6 +84,7 @@ Examples:
|
|
|
82
84
|
npm run migration -- generate --name=CreateUsers --config=src/persistence/migration.config.ts
|
|
83
85
|
TENANT_ID=tenant1 npm run migration run
|
|
84
86
|
npm run migration run:all
|
|
87
|
+
npm run migration reset
|
|
85
88
|
`);
|
|
86
89
|
}
|
|
87
90
|
function parseArgs() {
|
|
@@ -90,6 +93,7 @@ function parseArgs() {
|
|
|
90
93
|
let name;
|
|
91
94
|
let configPath;
|
|
92
95
|
let datasourcePath;
|
|
96
|
+
let force = false;
|
|
93
97
|
for(let i = 0; i < args.length; i++){
|
|
94
98
|
const arg = args[i];
|
|
95
99
|
if (arg.startsWith('--name=')) {
|
|
@@ -98,6 +102,8 @@ function parseArgs() {
|
|
|
98
102
|
configPath = arg.split('=')[1];
|
|
99
103
|
} else if (arg.startsWith('--datasource=')) {
|
|
100
104
|
datasourcePath = arg.split('=')[1];
|
|
105
|
+
} else if (arg === '--force') {
|
|
106
|
+
force = true;
|
|
101
107
|
} else if (!arg.startsWith('-') && !command) {
|
|
102
108
|
command = arg;
|
|
103
109
|
}
|
|
@@ -106,7 +112,8 @@ function parseArgs() {
|
|
|
106
112
|
command,
|
|
107
113
|
name,
|
|
108
114
|
configPath,
|
|
109
|
-
datasourcePath
|
|
115
|
+
datasourcePath,
|
|
116
|
+
force
|
|
110
117
|
};
|
|
111
118
|
}
|
|
112
119
|
async function loadConfig(configPath) {
|
|
@@ -117,7 +124,7 @@ async function loadConfig(configPath) {
|
|
|
117
124
|
return module.migrationConfig || module.default?.migrationConfig || module;
|
|
118
125
|
}
|
|
119
126
|
async function runMigrationCli(configOrPath) {
|
|
120
|
-
const { command, name, configPath: argConfigPath, datasourcePath } = parseArgs();
|
|
127
|
+
const { command, name, configPath: argConfigPath, datasourcePath, force } = parseArgs();
|
|
121
128
|
const tenantId = _config.envConfig.getTenantId() ?? undefined;
|
|
122
129
|
// npm passes --name=X as npm_config_name
|
|
123
130
|
const migrationName = _config.envConfig.tryGetValue('npm_config_name') || _config.envConfig.tryGetValue('MIGRATION_NAME') || name;
|
|
@@ -200,6 +207,19 @@ async function runMigrationCli(configOrPath) {
|
|
|
200
207
|
if (!result.success) process.exit(1);
|
|
201
208
|
break;
|
|
202
209
|
}
|
|
210
|
+
case 'reset':
|
|
211
|
+
{
|
|
212
|
+
if (_config.envConfig.isProduction() && !force) {
|
|
213
|
+
console.error('ā Refusing to reset database outside dev mode. Pass --force to override.');
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
const result = await (0, _migrationrunner.resetDatabase)(config, tenantId);
|
|
217
|
+
if (!result.success) process.exit(1);
|
|
218
|
+
await (0, _migrationrunner.generateMigration)(config, migrationName || 'Init', tenantId, dsPath);
|
|
219
|
+
const runResult = await (0, _migrationrunner.runMigrations)(config, tenantId);
|
|
220
|
+
if (!runResult.success) process.exit(1);
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
203
223
|
case 'status':
|
|
204
224
|
await (0, _migrationrunner.migrationStatus)(config, tenantId);
|
|
205
225
|
break;
|
|
@@ -18,6 +18,9 @@ _export(exports, {
|
|
|
18
18
|
get migrationStatus () {
|
|
19
19
|
return migrationStatus;
|
|
20
20
|
},
|
|
21
|
+
get resetDatabase () {
|
|
22
|
+
return resetDatabase;
|
|
23
|
+
},
|
|
21
24
|
get revertMigration () {
|
|
22
25
|
return revertMigration;
|
|
23
26
|
},
|
|
@@ -31,6 +34,7 @@ _export(exports, {
|
|
|
31
34
|
const _child_process = require("child_process");
|
|
32
35
|
const _fs = /*#__PURE__*/ _interop_require_wildcard(require("fs"));
|
|
33
36
|
const _path = /*#__PURE__*/ _interop_require_wildcard(require("path"));
|
|
37
|
+
const _typeorm = require("typeorm");
|
|
34
38
|
const _config = require("../config");
|
|
35
39
|
const _utils = require("../utils");
|
|
36
40
|
const _datasourcefactory = require("./datasource.factory");
|
|
@@ -166,6 +170,71 @@ async function revertMigration(config, tenantId) {
|
|
|
166
170
|
return {};
|
|
167
171
|
});
|
|
168
172
|
}
|
|
173
|
+
function clearMigrationFiles(basePath, tenantId, label) {
|
|
174
|
+
const folder = (0, _utils.getMigrationsFolderPath)(basePath, tenantId);
|
|
175
|
+
if (!_fs.existsSync(folder)) return;
|
|
176
|
+
const files = _fs.readdirSync(folder).filter((f)=>f.endsWith('.ts') || f.endsWith('.js'));
|
|
177
|
+
files.forEach((file)=>_fs.rmSync(_path.join(folder, file)));
|
|
178
|
+
console.log(`${label} ā Removed ${files.length} migration file(s) from ${folder}`);
|
|
179
|
+
}
|
|
180
|
+
async function dropAndRecreateDatabase(dbConfig, label) {
|
|
181
|
+
const { type, database } = dbConfig;
|
|
182
|
+
if (type === 'sqlite') {
|
|
183
|
+
if (database && _fs.existsSync(database)) _fs.rmSync(database);
|
|
184
|
+
console.log(`${label} ā Deleted sqlite file`);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (type !== 'mysql' && type !== 'mariadb' && type !== 'postgres') {
|
|
188
|
+
throw new Error(`Database reset is not supported for type '${type}'`);
|
|
189
|
+
}
|
|
190
|
+
const adminDs = new _typeorm.DataSource({
|
|
191
|
+
type,
|
|
192
|
+
host: dbConfig.host,
|
|
193
|
+
port: dbConfig.port,
|
|
194
|
+
username: dbConfig.username,
|
|
195
|
+
password: dbConfig.password,
|
|
196
|
+
database: type === 'postgres' ? 'postgres' : undefined
|
|
197
|
+
});
|
|
198
|
+
await adminDs.initialize();
|
|
199
|
+
try {
|
|
200
|
+
if (type === 'postgres') {
|
|
201
|
+
await adminDs.query(`SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = $1 AND pid <> pg_backend_pid()`, [
|
|
202
|
+
database
|
|
203
|
+
]);
|
|
204
|
+
await adminDs.query(`DROP DATABASE IF EXISTS "${database}"`);
|
|
205
|
+
await adminDs.query(`CREATE DATABASE "${database}"`);
|
|
206
|
+
} else {
|
|
207
|
+
await adminDs.query(`DROP DATABASE IF EXISTS \`${database}\``);
|
|
208
|
+
await adminDs.query(`CREATE DATABASE \`${database}\` CHARACTER SET utf8mb4`);
|
|
209
|
+
}
|
|
210
|
+
console.log(`${label} ā Database '${database}' dropped and recreated`);
|
|
211
|
+
} finally{
|
|
212
|
+
await adminDs.destroy();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
async function resetDatabase(config, tenantId) {
|
|
216
|
+
const { database } = (0, _utils.getDatabaseForTenant)(config, tenantId);
|
|
217
|
+
const label = getLabel(tenantId);
|
|
218
|
+
try {
|
|
219
|
+
clearMigrationFiles(config.migrationsPath, tenantId, label);
|
|
220
|
+
const dbConfig = (0, _utils.resolveDatabaseConnection)(config, tenantId);
|
|
221
|
+
await dropAndRecreateDatabase(dbConfig, label);
|
|
222
|
+
return {
|
|
223
|
+
tenantId,
|
|
224
|
+
database,
|
|
225
|
+
success: true
|
|
226
|
+
};
|
|
227
|
+
} catch (error) {
|
|
228
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
229
|
+
console.error(`${label} ā Failed: ${errorMessage}`);
|
|
230
|
+
return {
|
|
231
|
+
tenantId,
|
|
232
|
+
database,
|
|
233
|
+
success: false,
|
|
234
|
+
error: errorMessage
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
169
238
|
async function migrationStatus(config, tenantId) {
|
|
170
239
|
return withDataSource(config, tenantId, async (ds, label)=>{
|
|
171
240
|
const hasPending = await ds.showMigrations();
|
|
@@ -24,6 +24,9 @@ _export(exports, {
|
|
|
24
24
|
get getMigrationsGlobPattern () {
|
|
25
25
|
return getMigrationsGlobPattern;
|
|
26
26
|
},
|
|
27
|
+
get resolveDatabaseConnection () {
|
|
28
|
+
return resolveDatabaseConnection;
|
|
29
|
+
},
|
|
27
30
|
get resolveEntities () {
|
|
28
31
|
return resolveEntities;
|
|
29
32
|
}
|
|
@@ -75,6 +78,20 @@ function getDatabaseForTenant(config, tenantId) {
|
|
|
75
78
|
tenantConfig: defaultTenantConfig
|
|
76
79
|
};
|
|
77
80
|
}
|
|
81
|
+
function resolveDatabaseConnection(config, tenantId) {
|
|
82
|
+
const { database, tenant } = getDatabaseForTenant(config, tenantId);
|
|
83
|
+
return tenant ? {
|
|
84
|
+
...config.defaultDatabaseConfig,
|
|
85
|
+
host: tenant.host ?? config.defaultDatabaseConfig.host,
|
|
86
|
+
port: tenant.port ?? config.defaultDatabaseConfig.port,
|
|
87
|
+
username: tenant.username ?? config.defaultDatabaseConfig.username,
|
|
88
|
+
password: tenant.password ?? config.defaultDatabaseConfig.password,
|
|
89
|
+
database: tenant.database
|
|
90
|
+
} : {
|
|
91
|
+
...config.defaultDatabaseConfig,
|
|
92
|
+
database
|
|
93
|
+
};
|
|
94
|
+
}
|
|
78
95
|
function resolveEntities(config, tenantConfig) {
|
|
79
96
|
if (typeof config.entities === 'function') {
|
|
80
97
|
return config.entities(tenantConfig);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DataSource } from 'typeorm';
|
|
2
2
|
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
|
|
3
|
-
import { buildDataSourceOptions, getDatabaseForTenant, getMigrationsGlobPattern, resolveEntities } from '../utils/datasource-config.builder';
|
|
3
|
+
import { buildDataSourceOptions, getDatabaseForTenant, getMigrationsGlobPattern, resolveDatabaseConnection, resolveEntities } from '../utils/datasource-config.builder';
|
|
4
4
|
export function createMigrationDataSource(options) {
|
|
5
5
|
const { config, tenantId } = options;
|
|
6
6
|
const { database, tenant, tenantConfig } = getDatabaseForTenant(config, tenantId);
|
|
@@ -10,17 +10,7 @@ export function createMigrationDataSource(options) {
|
|
|
10
10
|
console.log(`\nš” Multi-tenant mode. Available tenants:`);
|
|
11
11
|
config.tenants.forEach((t)=>console.log(` - TENANT_ID=${t.id} ā ${t.database}`));
|
|
12
12
|
}
|
|
13
|
-
const dbConfig =
|
|
14
|
-
...config.defaultDatabaseConfig,
|
|
15
|
-
host: tenant.host ?? config.defaultDatabaseConfig.host,
|
|
16
|
-
port: tenant.port ?? config.defaultDatabaseConfig.port,
|
|
17
|
-
username: tenant.username ?? config.defaultDatabaseConfig.username,
|
|
18
|
-
password: tenant.password ?? config.defaultDatabaseConfig.password,
|
|
19
|
-
database: tenant.database
|
|
20
|
-
} : {
|
|
21
|
-
...config.defaultDatabaseConfig,
|
|
22
|
-
database
|
|
23
|
-
};
|
|
13
|
+
const dbConfig = resolveDatabaseConnection(config, tenantId);
|
|
24
14
|
const entities = resolveEntities(config, tenantConfig);
|
|
25
15
|
const dsOptions = buildDataSourceOptions(dbConfig, entities, getMigrationsGlobPattern(config.migrationsPath, tenantId), config.migrationsTableName);
|
|
26
16
|
return new DataSource({
|
package/fesm/migration/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { createMigrationDataSource, initializeDataSource } from './datasource.factory';
|
|
2
2
|
export { runMigrationCli } from './migration.cli';
|
|
3
|
-
export { generateMigration, runMigrations, revertMigration, migrationStatus, runForAllTenants, ensureMigrationsFolder } from './migration.runner';
|
|
3
|
+
export { generateMigration, runMigrations, revertMigration, resetDatabase, migrationStatus, runForAllTenants, ensureMigrationsFolder } from './migration.runner';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
2
|
import { envConfig } from '../config';
|
|
3
3
|
import { getDatabaseForTenant, getMigrationsFolderPath } from '../utils';
|
|
4
|
-
import { generateMigration, migrationStatus, revertMigration, runForAllTenants, runMigrations } from './migration.runner';
|
|
4
|
+
import { generateMigration, migrationStatus, resetDatabase, revertMigration, runForAllTenants, runMigrations } from './migration.runner';
|
|
5
5
|
function showHelp() {
|
|
6
6
|
console.log(`
|
|
7
7
|
Migration CLI
|
|
@@ -13,6 +13,7 @@ Commands:
|
|
|
13
13
|
generate --name=<Name> Generate migration
|
|
14
14
|
run Run pending migrations
|
|
15
15
|
revert Revert last migration
|
|
16
|
+
reset Drop db, wipe migration files, recreate db, generate + run initial migration (dev only)
|
|
16
17
|
status Show migration status
|
|
17
18
|
run:all Run for all tenants
|
|
18
19
|
revert:all Revert for all tenants
|
|
@@ -21,6 +22,7 @@ Commands:
|
|
|
21
22
|
Options:
|
|
22
23
|
--config=<path> Migration config file (default: src/persistence/migration.config.ts)
|
|
23
24
|
--name=<Name> Migration name (for generate command)
|
|
25
|
+
--force Required to run 'reset' when MODE is not 'dev'
|
|
24
26
|
|
|
25
27
|
Environment:
|
|
26
28
|
TENANT_ID Target tenant (default: uses default database)
|
|
@@ -31,6 +33,7 @@ Examples:
|
|
|
31
33
|
npm run migration -- generate --name=CreateUsers --config=src/persistence/migration.config.ts
|
|
32
34
|
TENANT_ID=tenant1 npm run migration run
|
|
33
35
|
npm run migration run:all
|
|
36
|
+
npm run migration reset
|
|
34
37
|
`);
|
|
35
38
|
}
|
|
36
39
|
function parseArgs() {
|
|
@@ -39,6 +42,7 @@ function parseArgs() {
|
|
|
39
42
|
let name;
|
|
40
43
|
let configPath;
|
|
41
44
|
let datasourcePath;
|
|
45
|
+
let force = false;
|
|
42
46
|
for(let i = 0; i < args.length; i++){
|
|
43
47
|
const arg = args[i];
|
|
44
48
|
if (arg.startsWith('--name=')) {
|
|
@@ -47,6 +51,8 @@ function parseArgs() {
|
|
|
47
51
|
configPath = arg.split('=')[1];
|
|
48
52
|
} else if (arg.startsWith('--datasource=')) {
|
|
49
53
|
datasourcePath = arg.split('=')[1];
|
|
54
|
+
} else if (arg === '--force') {
|
|
55
|
+
force = true;
|
|
50
56
|
} else if (!arg.startsWith('-') && !command) {
|
|
51
57
|
command = arg;
|
|
52
58
|
}
|
|
@@ -55,7 +61,8 @@ function parseArgs() {
|
|
|
55
61
|
command,
|
|
56
62
|
name,
|
|
57
63
|
configPath,
|
|
58
|
-
datasourcePath
|
|
64
|
+
datasourcePath,
|
|
65
|
+
force
|
|
59
66
|
};
|
|
60
67
|
}
|
|
61
68
|
async function loadConfig(configPath) {
|
|
@@ -66,7 +73,7 @@ async function loadConfig(configPath) {
|
|
|
66
73
|
return module.migrationConfig || module.default?.migrationConfig || module;
|
|
67
74
|
}
|
|
68
75
|
export async function runMigrationCli(configOrPath) {
|
|
69
|
-
const { command, name, configPath: argConfigPath, datasourcePath } = parseArgs();
|
|
76
|
+
const { command, name, configPath: argConfigPath, datasourcePath, force } = parseArgs();
|
|
70
77
|
const tenantId = envConfig.getTenantId() ?? undefined;
|
|
71
78
|
// npm passes --name=X as npm_config_name
|
|
72
79
|
const migrationName = envConfig.tryGetValue('npm_config_name') || envConfig.tryGetValue('MIGRATION_NAME') || name;
|
|
@@ -149,6 +156,19 @@ export async function runMigrationCli(configOrPath) {
|
|
|
149
156
|
if (!result.success) process.exit(1);
|
|
150
157
|
break;
|
|
151
158
|
}
|
|
159
|
+
case 'reset':
|
|
160
|
+
{
|
|
161
|
+
if (envConfig.isProduction() && !force) {
|
|
162
|
+
console.error('ā Refusing to reset database outside dev mode. Pass --force to override.');
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
const result = await resetDatabase(config, tenantId);
|
|
166
|
+
if (!result.success) process.exit(1);
|
|
167
|
+
await generateMigration(config, migrationName || 'Init', tenantId, dsPath);
|
|
168
|
+
const runResult = await runMigrations(config, tenantId);
|
|
169
|
+
if (!runResult.success) process.exit(1);
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
152
172
|
case 'status':
|
|
153
173
|
await migrationStatus(config, tenantId);
|
|
154
174
|
break;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { execSync } from 'child_process';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
|
+
import { DataSource } from 'typeorm';
|
|
4
5
|
import { envConfig } from '../config';
|
|
5
|
-
import { getActiveTenants, getDatabaseForTenant, getMigrationsFolderPath } from '../utils';
|
|
6
|
+
import { getActiveTenants, getDatabaseForTenant, getMigrationsFolderPath, resolveDatabaseConnection } from '../utils';
|
|
6
7
|
import { initializeDataSource } from './datasource.factory';
|
|
7
8
|
function getLabel(tenantId) {
|
|
8
9
|
return tenantId ? `[${tenantId}]` : '[default]';
|
|
@@ -95,6 +96,71 @@ export async function revertMigration(config, tenantId) {
|
|
|
95
96
|
return {};
|
|
96
97
|
});
|
|
97
98
|
}
|
|
99
|
+
function clearMigrationFiles(basePath, tenantId, label) {
|
|
100
|
+
const folder = getMigrationsFolderPath(basePath, tenantId);
|
|
101
|
+
if (!fs.existsSync(folder)) return;
|
|
102
|
+
const files = fs.readdirSync(folder).filter((f)=>f.endsWith('.ts') || f.endsWith('.js'));
|
|
103
|
+
files.forEach((file)=>fs.rmSync(path.join(folder, file)));
|
|
104
|
+
console.log(`${label} ā Removed ${files.length} migration file(s) from ${folder}`);
|
|
105
|
+
}
|
|
106
|
+
async function dropAndRecreateDatabase(dbConfig, label) {
|
|
107
|
+
const { type, database } = dbConfig;
|
|
108
|
+
if (type === 'sqlite') {
|
|
109
|
+
if (database && fs.existsSync(database)) fs.rmSync(database);
|
|
110
|
+
console.log(`${label} ā Deleted sqlite file`);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (type !== 'mysql' && type !== 'mariadb' && type !== 'postgres') {
|
|
114
|
+
throw new Error(`Database reset is not supported for type '${type}'`);
|
|
115
|
+
}
|
|
116
|
+
const adminDs = new DataSource({
|
|
117
|
+
type,
|
|
118
|
+
host: dbConfig.host,
|
|
119
|
+
port: dbConfig.port,
|
|
120
|
+
username: dbConfig.username,
|
|
121
|
+
password: dbConfig.password,
|
|
122
|
+
database: type === 'postgres' ? 'postgres' : undefined
|
|
123
|
+
});
|
|
124
|
+
await adminDs.initialize();
|
|
125
|
+
try {
|
|
126
|
+
if (type === 'postgres') {
|
|
127
|
+
await adminDs.query(`SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = $1 AND pid <> pg_backend_pid()`, [
|
|
128
|
+
database
|
|
129
|
+
]);
|
|
130
|
+
await adminDs.query(`DROP DATABASE IF EXISTS "${database}"`);
|
|
131
|
+
await adminDs.query(`CREATE DATABASE "${database}"`);
|
|
132
|
+
} else {
|
|
133
|
+
await adminDs.query(`DROP DATABASE IF EXISTS \`${database}\``);
|
|
134
|
+
await adminDs.query(`CREATE DATABASE \`${database}\` CHARACTER SET utf8mb4`);
|
|
135
|
+
}
|
|
136
|
+
console.log(`${label} ā Database '${database}' dropped and recreated`);
|
|
137
|
+
} finally{
|
|
138
|
+
await adminDs.destroy();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
export async function resetDatabase(config, tenantId) {
|
|
142
|
+
const { database } = getDatabaseForTenant(config, tenantId);
|
|
143
|
+
const label = getLabel(tenantId);
|
|
144
|
+
try {
|
|
145
|
+
clearMigrationFiles(config.migrationsPath, tenantId, label);
|
|
146
|
+
const dbConfig = resolveDatabaseConnection(config, tenantId);
|
|
147
|
+
await dropAndRecreateDatabase(dbConfig, label);
|
|
148
|
+
return {
|
|
149
|
+
tenantId,
|
|
150
|
+
database,
|
|
151
|
+
success: true
|
|
152
|
+
};
|
|
153
|
+
} catch (error) {
|
|
154
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
155
|
+
console.error(`${label} ā Failed: ${errorMessage}`);
|
|
156
|
+
return {
|
|
157
|
+
tenantId,
|
|
158
|
+
database,
|
|
159
|
+
success: false,
|
|
160
|
+
error: errorMessage
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
98
164
|
export async function migrationStatus(config, tenantId) {
|
|
99
165
|
return withDataSource(config, tenantId, async (ds, label)=>{
|
|
100
166
|
const hasPending = await ds.showMigrations();
|
|
@@ -53,6 +53,22 @@
|
|
|
53
53
|
tenantConfig: defaultTenantConfig
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Resolve full connection details for a tenant.
|
|
58
|
+
*/ export function resolveDatabaseConnection(config, tenantId) {
|
|
59
|
+
const { database, tenant } = getDatabaseForTenant(config, tenantId);
|
|
60
|
+
return tenant ? {
|
|
61
|
+
...config.defaultDatabaseConfig,
|
|
62
|
+
host: tenant.host ?? config.defaultDatabaseConfig.host,
|
|
63
|
+
port: tenant.port ?? config.defaultDatabaseConfig.port,
|
|
64
|
+
username: tenant.username ?? config.defaultDatabaseConfig.username,
|
|
65
|
+
password: tenant.password ?? config.defaultDatabaseConfig.password,
|
|
66
|
+
database: tenant.database
|
|
67
|
+
} : {
|
|
68
|
+
...config.defaultDatabaseConfig,
|
|
69
|
+
database
|
|
70
|
+
};
|
|
71
|
+
}
|
|
56
72
|
/**
|
|
57
73
|
* Resolve entities based on tenant config
|
|
58
74
|
*/ export function resolveEntities(config, tenantConfig) {
|
package/migration/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { createMigrationDataSource, initializeDataSource } from './datasource.factory';
|
|
2
2
|
export { runMigrationCli } from './migration.cli';
|
|
3
|
-
export { generateMigration, runMigrations, revertMigration, migrationStatus, runForAllTenants, ensureMigrationsFolder, } from './migration.runner';
|
|
3
|
+
export { generateMigration, runMigrations, revertMigration, resetDatabase, migrationStatus, runForAllTenants, ensureMigrationsFolder, } from './migration.runner';
|
|
@@ -3,5 +3,6 @@ export declare function ensureMigrationsFolder(basePath: string, tenantId?: stri
|
|
|
3
3
|
export declare function generateMigration(config: IMigrationConfig, name: string, tenantId?: string, datasourcePath?: string): Promise<void>;
|
|
4
4
|
export declare function runMigrations(config: IMigrationConfig, tenantId?: string): Promise<IMigrationResult>;
|
|
5
5
|
export declare function revertMigration(config: IMigrationConfig, tenantId?: string): Promise<IMigrationResult>;
|
|
6
|
+
export declare function resetDatabase(config: IMigrationConfig, tenantId?: string): Promise<IMigrationResult>;
|
|
6
7
|
export declare function migrationStatus(config: IMigrationConfig, tenantId?: string): Promise<IMigrationResult>;
|
|
7
8
|
export declare function runForAllTenants(config: IMigrationConfig, command: 'run' | 'revert' | 'status'): Promise<IMigrationResult[]>;
|
package/package.json
CHANGED
|
@@ -8,5 +8,6 @@ export declare function getDatabaseForTenant(config: IMigrationConfig, tenantId?
|
|
|
8
8
|
tenant?: ITenantDatabaseConfig;
|
|
9
9
|
tenantConfig: ITenantDatabaseConfig;
|
|
10
10
|
};
|
|
11
|
+
export declare function resolveDatabaseConnection(config: IMigrationConfig, tenantId?: string): IDatabaseConfig;
|
|
11
12
|
export declare function resolveEntities(config: IMigrationConfig, tenantConfig?: ITenantDatabaseConfig): any[];
|
|
12
13
|
export declare function getActiveTenants(config: IMigrationConfig): ITenantDatabaseConfig[];
|