@flusys/nestjs-core 6.0.0-rc.1 → 6.0.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.
@@ -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 = tenant ? {
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({
@@ -24,6 +24,9 @@ _export(exports, {
24
24
  get migrationStatus () {
25
25
  return _migrationrunner.migrationStatus;
26
26
  },
27
+ get resetDatabase () {
28
+ return _migrationrunner.resetDatabase;
29
+ },
27
30
  get revertMigration () {
28
31
  return _migrationrunner.revertMigration;
29
32
  },
@@ -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 = tenant ? {
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({
@@ -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) {
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/nestjs-core",
3
- "version": "6.0.0-rc.1",
3
+ "version": "6.0.1",
4
4
  "description": "Core types, interfaces, and constants for Flusys NestJS packages",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",
@@ -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[];