drizzle-multitenant 1.1.0 → 1.3.0
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 +28 -8
- package/dist/cli/index.js +2001 -2442
- package/dist/{context-Vki959ri.d.ts → context-BBLPNjmk.d.ts} +1 -1
- package/dist/cross-schema/index.js +1 -426
- package/dist/export/index.d.ts +395 -0
- package/dist/export/index.js +9 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.js +149 -2437
- package/dist/integrations/express.d.ts +3 -3
- package/dist/integrations/express.js +1 -110
- package/dist/integrations/fastify.d.ts +3 -3
- package/dist/integrations/fastify.js +1 -236
- package/dist/integrations/hono.js +0 -3
- package/dist/integrations/nestjs/index.d.ts +1 -1
- package/dist/integrations/nestjs/index.js +3 -10759
- package/dist/lint/index.d.ts +475 -0
- package/dist/lint/index.js +5 -0
- package/dist/metrics/index.d.ts +530 -0
- package/dist/metrics/index.js +3 -0
- package/dist/migrator/index.d.ts +1087 -270
- package/dist/migrator/index.js +149 -970
- package/dist/migrator-B7oPKe73.d.ts +1067 -0
- package/dist/scaffold/index.d.ts +330 -0
- package/dist/scaffold/index.js +277 -0
- package/dist/{types-BhK96FPC.d.ts → types-CGqsPe2Q.d.ts} +49 -1
- package/package.json +18 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cross-schema/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/integrations/express.js.map +0 -1
- package/dist/integrations/fastify.js.map +0 -1
- package/dist/integrations/hono.js.map +0 -1
- package/dist/integrations/nestjs/index.js.map +0 -1
- package/dist/migrator/index.js.map +0 -1
package/dist/migrator/index.d.ts
CHANGED
|
@@ -1,356 +1,1203 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { o as DetectedFormat, S as SeedFunction, k as TenantSeedResult, j as SeedOptions, l as SeedResults, p as SyncStatus, b as MigrationFile, q as TenantSyncStatus, r as TenantSyncResult, s as SyncOptions, t as SyncResults, d as MigrateOptions, e as MigrationResults, g as MigrationHooks, h as MigrationProgressCallback, i as MigrationErrorHandler, T as TenantMigrationResult, f as TenantMigrationStatus, u as ClonerConfig, v as ClonerDependencies, w as CloneTenantOptions, x as CloneTenantResult, y as SharedMigrateOptions, z as SharedMigrationResult, B as SharedMigrationStatus } from '../migrator-B7oPKe73.js';
|
|
2
|
+
export { _ as AnonymizeOptions, $ as AnonymizeRules, a0 as AnonymizeValue, A as AppliedMigration, Y as CloneProgressCallback, Z as CloneProgressStatus, P as ColumnDrift, J as ColumnInfo, R as ConstraintDrift, L as ConstraintInfo, C as CreateTenantOptions, G as DEFAULT_FORMAT, H as DRIZZLE_KIT_FORMAT, D as DropTenantOptions, Q as IndexDrift, K as IndexInfo, M as Migrator, a as MigratorConfig, X as SchemaDriftOptions, W as SchemaDriftStatus, a2 as SharedMigrationHooks, a1 as SharedMigratorConfig, m as SharedSeedFunction, n as SharedSeedResult, U as TableDrift, I as TableFormat, N as TableSchema, O as TenantSchema, V as TenantSchemaDrift, c as createMigrator, E as detectTableFormat, F as getFormatConfig } from '../migrator-B7oPKe73.js';
|
|
3
|
+
import * as pg from 'pg';
|
|
2
4
|
import { Pool } from 'pg';
|
|
5
|
+
import { C as Config } from '../types-CGqsPe2Q.js';
|
|
6
|
+
import 'drizzle-orm/postgres-js';
|
|
3
7
|
import 'drizzle-orm/node-postgres';
|
|
4
8
|
|
|
5
9
|
/**
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
type TableFormat = 'name' | 'hash' | 'drizzle-kit';
|
|
12
|
-
/**
|
|
13
|
-
* Detected table format information
|
|
14
|
-
*/
|
|
15
|
-
interface DetectedFormat {
|
|
16
|
-
/** The detected format type */
|
|
17
|
-
format: TableFormat;
|
|
18
|
-
/** The table name */
|
|
19
|
-
tableName: string;
|
|
20
|
-
/** Column configuration */
|
|
21
|
-
columns: {
|
|
22
|
-
/** Column used for identifying migrations */
|
|
23
|
-
identifier: 'name' | 'hash';
|
|
24
|
-
/** Column used for timestamp */
|
|
25
|
-
timestamp: 'applied_at' | 'created_at';
|
|
26
|
-
/** Data type of timestamp column */
|
|
27
|
-
timestampType: 'timestamp' | 'bigint';
|
|
28
|
-
};
|
|
10
|
+
* Options for creating a tenant schema
|
|
11
|
+
*/
|
|
12
|
+
interface CreateSchemaOptions {
|
|
13
|
+
/** Whether to also run migrations after creating (handled by Migrator) */
|
|
14
|
+
migrate?: boolean;
|
|
29
15
|
}
|
|
30
16
|
/**
|
|
31
|
-
*
|
|
17
|
+
* Options for dropping a tenant schema
|
|
32
18
|
*/
|
|
33
|
-
|
|
19
|
+
interface DropSchemaOptions {
|
|
20
|
+
/** Use CASCADE to drop all objects in schema */
|
|
21
|
+
cascade?: boolean;
|
|
22
|
+
/** Force drop without confirmation (used by CLI) */
|
|
23
|
+
force?: boolean;
|
|
24
|
+
}
|
|
34
25
|
/**
|
|
35
|
-
*
|
|
26
|
+
* Manages PostgreSQL schema lifecycle for multi-tenant applications.
|
|
27
|
+
*
|
|
28
|
+
* Extracted from Migrator to follow Single Responsibility Principle.
|
|
29
|
+
* Handles schema creation, deletion, existence checks, and migrations table management.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const schemaManager = new SchemaManager(config);
|
|
34
|
+
*
|
|
35
|
+
* // Create a new tenant schema
|
|
36
|
+
* await schemaManager.createSchema('tenant-123');
|
|
37
|
+
*
|
|
38
|
+
* // Check if schema exists
|
|
39
|
+
* const exists = await schemaManager.schemaExists('tenant-123');
|
|
40
|
+
*
|
|
41
|
+
* // Drop a tenant schema
|
|
42
|
+
* await schemaManager.dropSchema('tenant-123', { cascade: true });
|
|
43
|
+
* ```
|
|
36
44
|
*/
|
|
37
|
-
declare
|
|
45
|
+
declare class SchemaManager<TTenantSchema extends Record<string, unknown>, TSharedSchema extends Record<string, unknown>> {
|
|
46
|
+
private readonly config;
|
|
47
|
+
private readonly migrationsTable;
|
|
48
|
+
constructor(config: Config<TTenantSchema, TSharedSchema>, migrationsTable?: string);
|
|
49
|
+
/**
|
|
50
|
+
* Get the schema name for a tenant ID using the configured template
|
|
51
|
+
*
|
|
52
|
+
* @param tenantId - The tenant identifier
|
|
53
|
+
* @returns The PostgreSQL schema name
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const schemaName = schemaManager.getSchemaName('tenant-123');
|
|
58
|
+
* // Returns: 'tenant_tenant-123' (depends on schemaNameTemplate)
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
getSchemaName(tenantId: string): string;
|
|
62
|
+
/**
|
|
63
|
+
* Create a PostgreSQL pool for a specific schema
|
|
64
|
+
*
|
|
65
|
+
* The pool is configured with `search_path` set to the schema,
|
|
66
|
+
* allowing queries to run in tenant isolation.
|
|
67
|
+
*
|
|
68
|
+
* @param schemaName - The PostgreSQL schema name
|
|
69
|
+
* @returns A configured Pool instance
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const pool = await schemaManager.createPool('tenant_123');
|
|
74
|
+
* try {
|
|
75
|
+
* await pool.query('SELECT * FROM users'); // Queries tenant_123.users
|
|
76
|
+
* } finally {
|
|
77
|
+
* await pool.end();
|
|
78
|
+
* }
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
createPool(schemaName: string): Promise<Pool>;
|
|
82
|
+
/**
|
|
83
|
+
* Create a PostgreSQL pool without schema-specific search_path
|
|
84
|
+
*
|
|
85
|
+
* Used for operations that need to work across schemas or
|
|
86
|
+
* before a schema exists (like creating the schema itself).
|
|
87
|
+
*
|
|
88
|
+
* @returns A Pool instance connected to the database
|
|
89
|
+
*/
|
|
90
|
+
createRootPool(): Promise<Pool>;
|
|
91
|
+
/**
|
|
92
|
+
* Create a new tenant schema in the database
|
|
93
|
+
*
|
|
94
|
+
* @param tenantId - The tenant identifier
|
|
95
|
+
* @returns Promise that resolves when schema is created
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* await schemaManager.createSchema('new-tenant');
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
createSchema(tenantId: string): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Drop a tenant schema from the database
|
|
105
|
+
*
|
|
106
|
+
* @param tenantId - The tenant identifier
|
|
107
|
+
* @param options - Drop options (cascade, force)
|
|
108
|
+
* @returns Promise that resolves when schema is dropped
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* // Drop with CASCADE (removes all objects)
|
|
113
|
+
* await schemaManager.dropSchema('old-tenant', { cascade: true });
|
|
114
|
+
*
|
|
115
|
+
* // Drop with RESTRICT (fails if objects exist)
|
|
116
|
+
* await schemaManager.dropSchema('old-tenant', { cascade: false });
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
dropSchema(tenantId: string, options?: DropSchemaOptions): Promise<void>;
|
|
120
|
+
/**
|
|
121
|
+
* Check if a tenant schema exists in the database
|
|
122
|
+
*
|
|
123
|
+
* @param tenantId - The tenant identifier
|
|
124
|
+
* @returns True if schema exists, false otherwise
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* if (await schemaManager.schemaExists('tenant-123')) {
|
|
129
|
+
* console.log('Tenant schema exists');
|
|
130
|
+
* }
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
schemaExists(tenantId: string): Promise<boolean>;
|
|
134
|
+
/**
|
|
135
|
+
* List all schemas matching a pattern
|
|
136
|
+
*
|
|
137
|
+
* @param pattern - SQL LIKE pattern to filter schemas (optional)
|
|
138
|
+
* @returns Array of schema names
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* // List all tenant schemas
|
|
143
|
+
* const schemas = await schemaManager.listSchemas('tenant_%');
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
listSchemas(pattern?: string): Promise<string[]>;
|
|
147
|
+
/**
|
|
148
|
+
* Ensure the migrations table exists with the correct format
|
|
149
|
+
*
|
|
150
|
+
* Creates the migrations tracking table if it doesn't exist,
|
|
151
|
+
* using the appropriate column types based on the format.
|
|
152
|
+
*
|
|
153
|
+
* @param pool - Database pool to use
|
|
154
|
+
* @param schemaName - The schema to create the table in
|
|
155
|
+
* @param format - The detected/configured table format
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```typescript
|
|
159
|
+
* const pool = await schemaManager.createPool('tenant_123');
|
|
160
|
+
* await schemaManager.ensureMigrationsTable(pool, 'tenant_123', format);
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
ensureMigrationsTable(pool: Pool, schemaName: string, format: DetectedFormat): Promise<void>;
|
|
164
|
+
/**
|
|
165
|
+
* Check if the migrations table exists in a schema
|
|
166
|
+
*
|
|
167
|
+
* @param pool - Database pool to use
|
|
168
|
+
* @param schemaName - The schema to check
|
|
169
|
+
* @returns True if migrations table exists
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* const pool = await schemaManager.createPool('tenant_123');
|
|
174
|
+
* if (await schemaManager.migrationsTableExists(pool, 'tenant_123')) {
|
|
175
|
+
* console.log('Migrations table exists');
|
|
176
|
+
* }
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
migrationsTableExists(pool: Pool, schemaName: string): Promise<boolean>;
|
|
180
|
+
/**
|
|
181
|
+
* Get the configured migrations table name
|
|
182
|
+
*
|
|
183
|
+
* @returns The migrations table name
|
|
184
|
+
*/
|
|
185
|
+
getMigrationsTableName(): string;
|
|
186
|
+
}
|
|
38
187
|
/**
|
|
39
|
-
*
|
|
188
|
+
* Factory function to create a SchemaManager instance
|
|
189
|
+
*
|
|
190
|
+
* @param config - The tenant configuration
|
|
191
|
+
* @param migrationsTable - Optional custom migrations table name
|
|
192
|
+
* @returns A new SchemaManager instance
|
|
40
193
|
*
|
|
41
|
-
* @
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* const schemaManager = createSchemaManager(config);
|
|
197
|
+
* await schemaManager.createSchema('tenant-123');
|
|
198
|
+
* ```
|
|
45
199
|
*/
|
|
46
|
-
declare function
|
|
200
|
+
declare function createSchemaManager<TTenantSchema extends Record<string, unknown>, TSharedSchema extends Record<string, unknown>>(config: Config<TTenantSchema, TSharedSchema>, migrationsTable?: string): SchemaManager<TTenantSchema, TSharedSchema>;
|
|
201
|
+
|
|
47
202
|
/**
|
|
48
|
-
*
|
|
203
|
+
* Interfaces for Migrator module refactoring
|
|
204
|
+
*
|
|
205
|
+
* These interfaces define the contracts for the extracted modules.
|
|
206
|
+
* They should be implemented when refactoring the god component.
|
|
207
|
+
*
|
|
208
|
+
* @see REFACTOR_PROPOSAL.md for full refactoring plan
|
|
49
209
|
*/
|
|
50
|
-
declare function getFormatConfig(format: TableFormat, tableName?: string): DetectedFormat;
|
|
51
210
|
|
|
52
211
|
/**
|
|
53
|
-
*
|
|
54
|
-
*/
|
|
55
|
-
interface
|
|
56
|
-
/**
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
/** SQL content */
|
|
61
|
-
sql: string;
|
|
62
|
-
/** Timestamp extracted from filename */
|
|
63
|
-
timestamp: number;
|
|
64
|
-
/** SHA-256 hash of file content (for drizzle-kit compatibility) */
|
|
65
|
-
hash: string;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Migration status for a tenant
|
|
69
|
-
*/
|
|
70
|
-
interface TenantMigrationStatus {
|
|
71
|
-
tenantId: string;
|
|
72
|
-
schemaName: string;
|
|
73
|
-
appliedCount: number;
|
|
74
|
-
pendingCount: number;
|
|
75
|
-
pendingMigrations: string[];
|
|
76
|
-
status: 'ok' | 'behind' | 'error';
|
|
77
|
-
error?: string;
|
|
78
|
-
/** Detected table format (null for new tenants without migrations table) */
|
|
79
|
-
format: TableFormat | null;
|
|
212
|
+
* Options for executing a single migration
|
|
213
|
+
*/
|
|
214
|
+
interface ExecuteMigrationOptions {
|
|
215
|
+
/** Whether to skip actual SQL execution (mark as applied only) */
|
|
216
|
+
markOnly?: boolean;
|
|
217
|
+
/** Progress callback */
|
|
218
|
+
onProgress?: (status: 'applying' | 'recording') => void;
|
|
80
219
|
}
|
|
81
220
|
/**
|
|
82
|
-
*
|
|
83
|
-
*/
|
|
84
|
-
interface
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
format?:
|
|
221
|
+
* Responsible for executing migrations on a single tenant
|
|
222
|
+
*/
|
|
223
|
+
interface IMigrationExecutor {
|
|
224
|
+
/**
|
|
225
|
+
* Execute a single migration on a tenant
|
|
226
|
+
*/
|
|
227
|
+
executeMigration(pool: Pool, schemaName: string, migration: MigrationFile, format: DetectedFormat, options?: ExecuteMigrationOptions): Promise<void>;
|
|
228
|
+
/**
|
|
229
|
+
* Execute multiple migrations on a tenant
|
|
230
|
+
*/
|
|
231
|
+
executeMigrations(pool: Pool, schemaName: string, migrations: MigrationFile[], format: DetectedFormat, options?: ExecuteMigrationOptions): Promise<string[]>;
|
|
232
|
+
/**
|
|
233
|
+
* Record a migration as applied without executing SQL
|
|
234
|
+
*/
|
|
235
|
+
recordMigration(pool: Pool, schemaName: string, migration: MigrationFile, format: DetectedFormat): Promise<void>;
|
|
236
|
+
/**
|
|
237
|
+
* Get list of applied migrations for a tenant
|
|
238
|
+
*/
|
|
239
|
+
getAppliedMigrations(pool: Pool, schemaName: string, format: DetectedFormat): Promise<Array<{
|
|
240
|
+
identifier: string;
|
|
241
|
+
name?: string;
|
|
242
|
+
hash?: string;
|
|
243
|
+
appliedAt: Date;
|
|
244
|
+
}>>;
|
|
245
|
+
/**
|
|
246
|
+
* Get pending migrations (not yet applied)
|
|
247
|
+
*/
|
|
248
|
+
getPendingMigrations(pool: Pool, schemaName: string, allMigrations: MigrationFile[], format: DetectedFormat): Promise<MigrationFile[]>;
|
|
93
249
|
}
|
|
94
250
|
/**
|
|
95
|
-
*
|
|
251
|
+
* Batch execution options
|
|
96
252
|
*/
|
|
97
|
-
interface
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
failed: number;
|
|
101
|
-
skipped: number;
|
|
102
|
-
details: TenantMigrationResult[];
|
|
253
|
+
interface BatchExecuteOptions extends MigrateOptions {
|
|
254
|
+
/** Migrations to apply (if not provided, loads from disk) */
|
|
255
|
+
migrations?: MigrationFile[];
|
|
103
256
|
}
|
|
104
257
|
/**
|
|
105
|
-
*
|
|
258
|
+
* Responsible for batch migration operations across multiple tenants
|
|
106
259
|
*/
|
|
107
|
-
|
|
260
|
+
interface IBatchExecutor {
|
|
261
|
+
/**
|
|
262
|
+
* Migrate all tenants in parallel
|
|
263
|
+
*/
|
|
264
|
+
migrateAll(options?: BatchExecuteOptions): Promise<MigrationResults>;
|
|
265
|
+
/**
|
|
266
|
+
* Migrate specific tenants in parallel
|
|
267
|
+
*/
|
|
268
|
+
migrateTenants(tenantIds: string[], options?: BatchExecuteOptions): Promise<MigrationResults>;
|
|
269
|
+
/**
|
|
270
|
+
* Mark all tenants as applied without executing SQL
|
|
271
|
+
*/
|
|
272
|
+
markAllAsApplied(options?: MigrateOptions): Promise<MigrationResults>;
|
|
273
|
+
}
|
|
108
274
|
/**
|
|
109
|
-
*
|
|
275
|
+
* Responsible for synchronizing migration state between disk and database
|
|
110
276
|
*/
|
|
111
|
-
|
|
277
|
+
interface ISyncManager {
|
|
278
|
+
/**
|
|
279
|
+
* Get sync status for all tenants
|
|
280
|
+
*/
|
|
281
|
+
getSyncStatus(): Promise<SyncStatus>;
|
|
282
|
+
/**
|
|
283
|
+
* Get sync status for a specific tenant
|
|
284
|
+
*/
|
|
285
|
+
getTenantSyncStatus(tenantId: string, migrations?: MigrationFile[]): Promise<TenantSyncStatus>;
|
|
286
|
+
/**
|
|
287
|
+
* Mark missing migrations as applied for a tenant
|
|
288
|
+
*/
|
|
289
|
+
markMissing(tenantId: string): Promise<TenantSyncResult>;
|
|
290
|
+
/**
|
|
291
|
+
* Mark missing migrations as applied for all tenants
|
|
292
|
+
*/
|
|
293
|
+
markAllMissing(options?: SyncOptions): Promise<SyncResults>;
|
|
294
|
+
/**
|
|
295
|
+
* Remove orphan records from a tenant
|
|
296
|
+
*/
|
|
297
|
+
cleanOrphans(tenantId: string): Promise<TenantSyncResult>;
|
|
298
|
+
/**
|
|
299
|
+
* Remove orphan records from all tenants
|
|
300
|
+
*/
|
|
301
|
+
cleanAllOrphans(options?: SyncOptions): Promise<SyncResults>;
|
|
302
|
+
}
|
|
112
303
|
/**
|
|
113
|
-
*
|
|
304
|
+
* Responsible for seeding tenant databases
|
|
114
305
|
*/
|
|
115
|
-
interface
|
|
116
|
-
/**
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
306
|
+
interface ISeeder<TSchema extends Record<string, unknown> = Record<string, unknown>> {
|
|
307
|
+
/**
|
|
308
|
+
* Seed a single tenant
|
|
309
|
+
*/
|
|
310
|
+
seedTenant(tenantId: string, seedFn: SeedFunction<TSchema>): Promise<TenantSeedResult>;
|
|
311
|
+
/**
|
|
312
|
+
* Seed all tenants
|
|
313
|
+
*/
|
|
314
|
+
seedAll(seedFn: SeedFunction<TSchema>, options?: SeedOptions): Promise<SeedResults>;
|
|
315
|
+
/**
|
|
316
|
+
* Seed specific tenants
|
|
317
|
+
*/
|
|
318
|
+
seedTenants(tenantIds: string[], seedFn: SeedFunction<TSchema>, options?: SeedOptions): Promise<SeedResults>;
|
|
124
319
|
}
|
|
320
|
+
|
|
125
321
|
/**
|
|
126
|
-
*
|
|
322
|
+
* Configuration for the Seeder
|
|
127
323
|
*/
|
|
128
|
-
interface
|
|
129
|
-
/** Path to tenant migrations folder */
|
|
130
|
-
migrationsFolder: string;
|
|
131
|
-
/** Table name for tracking migrations */
|
|
132
|
-
migrationsTable?: string;
|
|
324
|
+
interface SeederConfig {
|
|
133
325
|
/** Function to discover tenant IDs */
|
|
134
326
|
tenantDiscovery: () => Promise<string[]>;
|
|
135
|
-
|
|
136
|
-
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Seeder dependencies
|
|
330
|
+
*/
|
|
331
|
+
interface SeederDependencies<TTenantSchema extends Record<string, unknown> = Record<string, unknown>> {
|
|
332
|
+
/** Pool creation for specific schemas */
|
|
333
|
+
createPool: (schemaName: string) => Promise<pg.Pool>;
|
|
334
|
+
/** Schema name template function */
|
|
335
|
+
schemaNameTemplate: (tenantId: string) => string;
|
|
336
|
+
/** Tenant schema definition */
|
|
337
|
+
tenantSchema: TTenantSchema;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Responsible for seeding tenant databases with initial data.
|
|
342
|
+
*
|
|
343
|
+
* Extracted from Migrator to follow Single Responsibility Principle.
|
|
344
|
+
* Handles seeding individual tenants and batch seeding operations.
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* ```typescript
|
|
348
|
+
* const seeder = new Seeder(config, dependencies);
|
|
349
|
+
*
|
|
350
|
+
* // Seed a single tenant
|
|
351
|
+
* const result = await seeder.seedTenant('tenant-123', async (db, tenantId) => {
|
|
352
|
+
* await db.insert(roles).values([
|
|
353
|
+
* { name: 'admin', permissions: ['*'] },
|
|
354
|
+
* { name: 'user', permissions: ['read'] },
|
|
355
|
+
* ]);
|
|
356
|
+
* });
|
|
357
|
+
*
|
|
358
|
+
* // Seed all tenants
|
|
359
|
+
* const results = await seeder.seedAll(seedFn, { concurrency: 10 });
|
|
360
|
+
* ```
|
|
361
|
+
*/
|
|
362
|
+
declare class Seeder<TTenantSchema extends Record<string, unknown> = Record<string, unknown>> implements ISeeder<TTenantSchema> {
|
|
363
|
+
private readonly config;
|
|
364
|
+
private readonly deps;
|
|
365
|
+
constructor(config: SeederConfig, deps: SeederDependencies<TTenantSchema>);
|
|
366
|
+
/**
|
|
367
|
+
* Seed a single tenant with initial data
|
|
368
|
+
*
|
|
369
|
+
* Creates a database connection for the tenant, executes the seed function,
|
|
370
|
+
* and properly cleans up the connection afterward.
|
|
371
|
+
*
|
|
372
|
+
* @param tenantId - The tenant identifier
|
|
373
|
+
* @param seedFn - Function that seeds the database
|
|
374
|
+
* @returns Result of the seeding operation
|
|
375
|
+
*
|
|
376
|
+
* @example
|
|
377
|
+
* ```typescript
|
|
378
|
+
* const result = await seeder.seedTenant('tenant-123', async (db, tenantId) => {
|
|
379
|
+
* await db.insert(users).values([
|
|
380
|
+
* { name: 'Admin', email: `admin@${tenantId}.com` },
|
|
381
|
+
* ]);
|
|
382
|
+
* });
|
|
383
|
+
*
|
|
384
|
+
* if (result.success) {
|
|
385
|
+
* console.log(`Seeded ${result.tenantId} in ${result.durationMs}ms`);
|
|
386
|
+
* }
|
|
387
|
+
* ```
|
|
388
|
+
*/
|
|
389
|
+
seedTenant(tenantId: string, seedFn: SeedFunction<TTenantSchema>): Promise<TenantSeedResult>;
|
|
390
|
+
/**
|
|
391
|
+
* Seed all tenants with initial data in parallel
|
|
392
|
+
*
|
|
393
|
+
* Discovers all tenants and seeds them in batches with configurable concurrency.
|
|
394
|
+
* Supports progress callbacks and abort-on-error behavior.
|
|
395
|
+
*
|
|
396
|
+
* @param seedFn - Function that seeds each database
|
|
397
|
+
* @param options - Seeding options
|
|
398
|
+
* @returns Aggregate results of all seeding operations
|
|
399
|
+
*
|
|
400
|
+
* @example
|
|
401
|
+
* ```typescript
|
|
402
|
+
* const results = await seeder.seedAll(
|
|
403
|
+
* async (db, tenantId) => {
|
|
404
|
+
* await db.insert(settings).values({ key: 'initialized', value: 'true' });
|
|
405
|
+
* },
|
|
406
|
+
* {
|
|
407
|
+
* concurrency: 5,
|
|
408
|
+
* onProgress: (id, status) => console.log(`${id}: ${status}`),
|
|
409
|
+
* }
|
|
410
|
+
* );
|
|
411
|
+
*
|
|
412
|
+
* console.log(`Succeeded: ${results.succeeded}/${results.total}`);
|
|
413
|
+
* ```
|
|
414
|
+
*/
|
|
415
|
+
seedAll(seedFn: SeedFunction<TTenantSchema>, options?: SeedOptions): Promise<SeedResults>;
|
|
416
|
+
/**
|
|
417
|
+
* Seed specific tenants with initial data
|
|
418
|
+
*
|
|
419
|
+
* Seeds only the specified tenants in batches with configurable concurrency.
|
|
420
|
+
*
|
|
421
|
+
* @param tenantIds - List of tenant IDs to seed
|
|
422
|
+
* @param seedFn - Function that seeds each database
|
|
423
|
+
* @param options - Seeding options
|
|
424
|
+
* @returns Aggregate results of seeding operations
|
|
425
|
+
*
|
|
426
|
+
* @example
|
|
427
|
+
* ```typescript
|
|
428
|
+
* const results = await seeder.seedTenants(
|
|
429
|
+
* ['tenant-1', 'tenant-2', 'tenant-3'],
|
|
430
|
+
* async (db) => {
|
|
431
|
+
* await db.insert(config).values({ setup: true });
|
|
432
|
+
* },
|
|
433
|
+
* { concurrency: 2 }
|
|
434
|
+
* );
|
|
435
|
+
* ```
|
|
436
|
+
*/
|
|
437
|
+
seedTenants(tenantIds: string[], seedFn: SeedFunction<TTenantSchema>, options?: SeedOptions): Promise<SeedResults>;
|
|
438
|
+
/**
|
|
439
|
+
* Create a skipped result for aborted seeding
|
|
440
|
+
*/
|
|
441
|
+
private createSkippedResult;
|
|
137
442
|
/**
|
|
138
|
-
*
|
|
139
|
-
* - "auto": Auto-detect existing format, use defaultFormat for new tables
|
|
140
|
-
* - "name": Use filename (drizzle-multitenant native)
|
|
141
|
-
* - "hash": Use SHA-256 hash
|
|
142
|
-
* - "drizzle-kit": Exact drizzle-kit format (hash + bigint timestamp)
|
|
143
|
-
* @default "auto"
|
|
443
|
+
* Create an error result for failed seeding
|
|
144
444
|
*/
|
|
145
|
-
|
|
445
|
+
private createErrorResult;
|
|
146
446
|
/**
|
|
147
|
-
*
|
|
148
|
-
* @default "name"
|
|
447
|
+
* Aggregate individual results into a summary
|
|
149
448
|
*/
|
|
150
|
-
|
|
449
|
+
private aggregateResults;
|
|
151
450
|
}
|
|
152
451
|
/**
|
|
153
|
-
*
|
|
452
|
+
* Factory function to create a Seeder instance
|
|
453
|
+
*
|
|
454
|
+
* @param config - Seeder configuration
|
|
455
|
+
* @param dependencies - Required dependencies
|
|
456
|
+
* @returns A configured Seeder instance
|
|
457
|
+
*
|
|
458
|
+
* @example
|
|
459
|
+
* ```typescript
|
|
460
|
+
* const seeder = createSeeder(
|
|
461
|
+
* { tenantDiscovery: async () => ['t1', 't2'] },
|
|
462
|
+
* {
|
|
463
|
+
* createPool: schemaManager.createPool.bind(schemaManager),
|
|
464
|
+
* schemaNameTemplate: (id) => `tenant_${id}`,
|
|
465
|
+
* tenantSchema: schema,
|
|
466
|
+
* }
|
|
467
|
+
* );
|
|
468
|
+
* ```
|
|
154
469
|
*/
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
470
|
+
declare function createSeeder<TTenantSchema extends Record<string, unknown> = Record<string, unknown>>(config: SeederConfig, dependencies: SeederDependencies<TTenantSchema>): Seeder<TTenantSchema>;
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Internal types for the SyncManager module
|
|
474
|
+
*
|
|
475
|
+
* Public types are re-exported from the main types.ts file
|
|
476
|
+
* @module sync/types
|
|
477
|
+
*/
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Configuration for the SyncManager
|
|
481
|
+
*/
|
|
482
|
+
interface SyncManagerConfig {
|
|
483
|
+
/** Function to discover tenant IDs */
|
|
484
|
+
tenantDiscovery: () => Promise<string[]>;
|
|
485
|
+
/** Path to migrations folder */
|
|
486
|
+
migrationsFolder: string;
|
|
487
|
+
/** Migrations table name */
|
|
488
|
+
migrationsTable: string;
|
|
164
489
|
}
|
|
165
490
|
/**
|
|
166
|
-
*
|
|
491
|
+
* SyncManager dependencies
|
|
167
492
|
*/
|
|
168
|
-
interface
|
|
169
|
-
/**
|
|
170
|
-
|
|
493
|
+
interface SyncManagerDependencies {
|
|
494
|
+
/** Create a pool for a specific schema */
|
|
495
|
+
createPool: (schemaName: string) => Promise<Pool>;
|
|
496
|
+
/** Schema name template function */
|
|
497
|
+
schemaNameTemplate: (tenantId: string) => string;
|
|
498
|
+
/** Check if migrations table exists */
|
|
499
|
+
migrationsTableExists: (pool: Pool, schemaName: string) => Promise<boolean>;
|
|
500
|
+
/** Ensure migrations table exists */
|
|
501
|
+
ensureMigrationsTable: (pool: Pool, schemaName: string, format: DetectedFormat) => Promise<void>;
|
|
502
|
+
/** Get or detect the format for a schema */
|
|
503
|
+
getOrDetectFormat: (pool: Pool, schemaName: string) => Promise<DetectedFormat>;
|
|
504
|
+
/** Load migrations from disk */
|
|
505
|
+
loadMigrations: () => Promise<MigrationFile[]>;
|
|
171
506
|
}
|
|
507
|
+
|
|
172
508
|
/**
|
|
173
|
-
*
|
|
509
|
+
* Responsible for synchronizing migration state between disk and database.
|
|
510
|
+
*
|
|
511
|
+
* Extracted from Migrator to follow Single Responsibility Principle.
|
|
512
|
+
* Handles detection of divergences and reconciliation operations.
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* ```typescript
|
|
516
|
+
* const syncManager = new SyncManager(config, dependencies);
|
|
517
|
+
*
|
|
518
|
+
* // Check sync status
|
|
519
|
+
* const status = await syncManager.getSyncStatus();
|
|
520
|
+
* if (status.outOfSync > 0) {
|
|
521
|
+
* console.log(`${status.outOfSync} tenants out of sync`);
|
|
522
|
+
* }
|
|
523
|
+
*
|
|
524
|
+
* // Mark missing migrations as applied
|
|
525
|
+
* await syncManager.markAllMissing({ concurrency: 10 });
|
|
526
|
+
*
|
|
527
|
+
* // Clean orphan records
|
|
528
|
+
* await syncManager.cleanAllOrphans({ concurrency: 10 });
|
|
529
|
+
* ```
|
|
174
530
|
*/
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
531
|
+
declare class SyncManager implements ISyncManager {
|
|
532
|
+
private readonly config;
|
|
533
|
+
private readonly deps;
|
|
534
|
+
constructor(config: SyncManagerConfig, deps: SyncManagerDependencies);
|
|
535
|
+
/**
|
|
536
|
+
* Get sync status for all tenants
|
|
537
|
+
*
|
|
538
|
+
* Detects divergences between migrations on disk and tracking in database.
|
|
539
|
+
* A tenant is "in sync" when all disk migrations are tracked and no orphan records exist.
|
|
540
|
+
*
|
|
541
|
+
* @returns Aggregate sync status for all tenants
|
|
542
|
+
*
|
|
543
|
+
* @example
|
|
544
|
+
* ```typescript
|
|
545
|
+
* const status = await syncManager.getSyncStatus();
|
|
546
|
+
* console.log(`Total: ${status.total}, In sync: ${status.inSync}, Out of sync: ${status.outOfSync}`);
|
|
547
|
+
*
|
|
548
|
+
* for (const tenant of status.details.filter(d => !d.inSync)) {
|
|
549
|
+
* console.log(`${tenant.tenantId}: missing=${tenant.missing.length}, orphans=${tenant.orphans.length}`);
|
|
550
|
+
* }
|
|
551
|
+
* ```
|
|
552
|
+
*/
|
|
553
|
+
getSyncStatus(): Promise<SyncStatus>;
|
|
554
|
+
/**
|
|
555
|
+
* Get sync status for a specific tenant
|
|
556
|
+
*
|
|
557
|
+
* Compares migrations on disk with records in the database.
|
|
558
|
+
* Identifies missing migrations (on disk but not tracked) and
|
|
559
|
+
* orphan records (tracked but not on disk).
|
|
560
|
+
*
|
|
561
|
+
* @param tenantId - The tenant identifier
|
|
562
|
+
* @param migrations - Optional pre-loaded migrations (avoids reloading from disk)
|
|
563
|
+
* @returns Sync status for the tenant
|
|
564
|
+
*
|
|
565
|
+
* @example
|
|
566
|
+
* ```typescript
|
|
567
|
+
* const status = await syncManager.getTenantSyncStatus('tenant-123');
|
|
568
|
+
* if (status.missing.length > 0) {
|
|
569
|
+
* console.log(`Missing: ${status.missing.join(', ')}`);
|
|
570
|
+
* }
|
|
571
|
+
* if (status.orphans.length > 0) {
|
|
572
|
+
* console.log(`Orphans: ${status.orphans.join(', ')}`);
|
|
573
|
+
* }
|
|
574
|
+
* ```
|
|
575
|
+
*/
|
|
576
|
+
getTenantSyncStatus(tenantId: string, migrations?: MigrationFile[]): Promise<TenantSyncStatus>;
|
|
577
|
+
/**
|
|
578
|
+
* Mark missing migrations as applied for a tenant
|
|
579
|
+
*
|
|
580
|
+
* Records migrations that exist on disk but are not tracked in the database.
|
|
581
|
+
* Useful for syncing tracking state with already-applied migrations.
|
|
582
|
+
*
|
|
583
|
+
* @param tenantId - The tenant identifier
|
|
584
|
+
* @returns Result of the mark operation
|
|
585
|
+
*
|
|
586
|
+
* @example
|
|
587
|
+
* ```typescript
|
|
588
|
+
* const result = await syncManager.markMissing('tenant-123');
|
|
589
|
+
* if (result.success) {
|
|
590
|
+
* console.log(`Marked ${result.markedMigrations.length} migrations as applied`);
|
|
591
|
+
* }
|
|
592
|
+
* ```
|
|
593
|
+
*/
|
|
594
|
+
markMissing(tenantId: string): Promise<TenantSyncResult>;
|
|
595
|
+
/**
|
|
596
|
+
* Mark missing migrations as applied for all tenants
|
|
597
|
+
*
|
|
598
|
+
* Processes all tenants in parallel with configurable concurrency.
|
|
599
|
+
* Supports progress callbacks and abort-on-error behavior.
|
|
600
|
+
*
|
|
601
|
+
* @param options - Sync options
|
|
602
|
+
* @returns Aggregate results of all mark operations
|
|
603
|
+
*
|
|
604
|
+
* @example
|
|
605
|
+
* ```typescript
|
|
606
|
+
* const results = await syncManager.markAllMissing({
|
|
607
|
+
* concurrency: 10,
|
|
608
|
+
* onProgress: (id, status) => console.log(`${id}: ${status}`),
|
|
609
|
+
* });
|
|
610
|
+
* console.log(`Succeeded: ${results.succeeded}/${results.total}`);
|
|
611
|
+
* ```
|
|
612
|
+
*/
|
|
613
|
+
markAllMissing(options?: SyncOptions): Promise<SyncResults>;
|
|
614
|
+
/**
|
|
615
|
+
* Remove orphan migration records for a tenant
|
|
616
|
+
*
|
|
617
|
+
* Deletes records from the migrations table that don't have
|
|
618
|
+
* corresponding files on disk.
|
|
619
|
+
*
|
|
620
|
+
* @param tenantId - The tenant identifier
|
|
621
|
+
* @returns Result of the clean operation
|
|
622
|
+
*
|
|
623
|
+
* @example
|
|
624
|
+
* ```typescript
|
|
625
|
+
* const result = await syncManager.cleanOrphans('tenant-123');
|
|
626
|
+
* if (result.success) {
|
|
627
|
+
* console.log(`Removed ${result.removedOrphans.length} orphan records`);
|
|
628
|
+
* }
|
|
629
|
+
* ```
|
|
630
|
+
*/
|
|
631
|
+
cleanOrphans(tenantId: string): Promise<TenantSyncResult>;
|
|
632
|
+
/**
|
|
633
|
+
* Remove orphan migration records for all tenants
|
|
634
|
+
*
|
|
635
|
+
* Processes all tenants in parallel with configurable concurrency.
|
|
636
|
+
* Supports progress callbacks and abort-on-error behavior.
|
|
637
|
+
*
|
|
638
|
+
* @param options - Sync options
|
|
639
|
+
* @returns Aggregate results of all clean operations
|
|
640
|
+
*
|
|
641
|
+
* @example
|
|
642
|
+
* ```typescript
|
|
643
|
+
* const results = await syncManager.cleanAllOrphans({
|
|
644
|
+
* concurrency: 10,
|
|
645
|
+
* onProgress: (id, status) => console.log(`${id}: ${status}`),
|
|
646
|
+
* });
|
|
647
|
+
* console.log(`Succeeded: ${results.succeeded}/${results.total}`);
|
|
648
|
+
* ```
|
|
649
|
+
*/
|
|
650
|
+
cleanAllOrphans(options?: SyncOptions): Promise<SyncResults>;
|
|
651
|
+
/**
|
|
652
|
+
* Get applied migrations for a schema
|
|
653
|
+
*/
|
|
654
|
+
private getAppliedMigrations;
|
|
655
|
+
/**
|
|
656
|
+
* Check if a migration has been applied
|
|
657
|
+
*/
|
|
658
|
+
private isMigrationApplied;
|
|
659
|
+
/**
|
|
660
|
+
* Record a migration as applied (without executing SQL)
|
|
661
|
+
*/
|
|
662
|
+
private recordMigration;
|
|
663
|
+
/**
|
|
664
|
+
* Create a skipped sync result for aborted operations
|
|
665
|
+
*/
|
|
666
|
+
private createSkippedSyncResult;
|
|
667
|
+
/**
|
|
668
|
+
* Create an error sync result for failed operations
|
|
669
|
+
*/
|
|
670
|
+
private createErrorSyncResult;
|
|
671
|
+
/**
|
|
672
|
+
* Aggregate individual sync results into a summary
|
|
673
|
+
*/
|
|
674
|
+
private aggregateSyncResults;
|
|
180
675
|
}
|
|
181
676
|
/**
|
|
182
|
-
*
|
|
677
|
+
* Factory function to create a SyncManager instance
|
|
678
|
+
*
|
|
679
|
+
* @param config - SyncManager configuration
|
|
680
|
+
* @param dependencies - Required dependencies
|
|
681
|
+
* @returns A configured SyncManager instance
|
|
682
|
+
*
|
|
683
|
+
* @example
|
|
684
|
+
* ```typescript
|
|
685
|
+
* const syncManager = createSyncManager(
|
|
686
|
+
* {
|
|
687
|
+
* tenantDiscovery: async () => ['t1', 't2'],
|
|
688
|
+
* migrationsFolder: './migrations',
|
|
689
|
+
* migrationsTable: '__drizzle_migrations',
|
|
690
|
+
* },
|
|
691
|
+
* {
|
|
692
|
+
* createPool: schemaManager.createPool.bind(schemaManager),
|
|
693
|
+
* schemaNameTemplate: (id) => `tenant_${id}`,
|
|
694
|
+
* migrationsTableExists: schemaManager.migrationsTableExists.bind(schemaManager),
|
|
695
|
+
* ensureMigrationsTable: schemaManager.ensureMigrationsTable.bind(schemaManager),
|
|
696
|
+
* getOrDetectFormat: migrator.getOrDetectFormat.bind(migrator),
|
|
697
|
+
* loadMigrations: migrator.loadMigrations.bind(migrator),
|
|
698
|
+
* }
|
|
699
|
+
* );
|
|
700
|
+
* ```
|
|
701
|
+
*/
|
|
702
|
+
declare function createSyncManager(config: SyncManagerConfig, dependencies: SyncManagerDependencies): SyncManager;
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* Applied migration with parsed data
|
|
183
706
|
*/
|
|
184
707
|
interface AppliedMigration {
|
|
185
|
-
id: number;
|
|
186
|
-
/** Migration identifier (name or hash depending on format) */
|
|
187
708
|
identifier: string;
|
|
188
|
-
/** Migration name (only available in name-based format) */
|
|
189
709
|
name?: string;
|
|
190
|
-
/** Migration hash (only available in hash-based format) */
|
|
191
710
|
hash?: string;
|
|
192
711
|
appliedAt: Date;
|
|
193
712
|
}
|
|
194
713
|
/**
|
|
195
|
-
*
|
|
196
|
-
*/
|
|
197
|
-
interface
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
/** Migrations in disk but not tracked in database */
|
|
201
|
-
missing: string[];
|
|
202
|
-
/** Migrations tracked in database but not found in disk */
|
|
203
|
-
orphans: string[];
|
|
204
|
-
/** Whether the tenant is in sync */
|
|
205
|
-
inSync: boolean;
|
|
206
|
-
/** Table format used */
|
|
207
|
-
format: TableFormat | null;
|
|
208
|
-
/** Error if any */
|
|
209
|
-
error?: string;
|
|
714
|
+
* Configuration for MigrationExecutor
|
|
715
|
+
*/
|
|
716
|
+
interface MigrationExecutorConfig {
|
|
717
|
+
/** Migration hooks for lifecycle events */
|
|
718
|
+
hooks?: MigrationHooks | undefined;
|
|
210
719
|
}
|
|
211
720
|
/**
|
|
212
|
-
*
|
|
721
|
+
* Dependencies for MigrationExecutor
|
|
213
722
|
*/
|
|
214
|
-
interface
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
723
|
+
interface MigrationExecutorDependencies {
|
|
724
|
+
/** Create a database pool for a schema */
|
|
725
|
+
createPool: (schemaName: string) => Promise<Pool>;
|
|
726
|
+
/** Get schema name from tenant ID */
|
|
727
|
+
schemaNameTemplate: (tenantId: string) => string;
|
|
728
|
+
/** Check if migrations table exists */
|
|
729
|
+
migrationsTableExists: (pool: Pool, schemaName: string) => Promise<boolean>;
|
|
730
|
+
/** Ensure migrations table exists with correct format */
|
|
731
|
+
ensureMigrationsTable: (pool: Pool, schemaName: string, format: DetectedFormat) => Promise<void>;
|
|
732
|
+
/** Get or detect table format */
|
|
733
|
+
getOrDetectFormat: (pool: Pool, schemaName: string) => Promise<DetectedFormat>;
|
|
734
|
+
/** Load migrations from disk */
|
|
735
|
+
loadMigrations: () => Promise<MigrationFile[]>;
|
|
220
736
|
}
|
|
221
737
|
/**
|
|
222
|
-
*
|
|
223
|
-
*/
|
|
224
|
-
interface
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
markedMigrations: string[];
|
|
230
|
-
/** Orphan records that were removed */
|
|
231
|
-
removedOrphans: string[];
|
|
232
|
-
error?: string;
|
|
233
|
-
durationMs: number;
|
|
738
|
+
* Options for migrating a single tenant
|
|
739
|
+
*/
|
|
740
|
+
interface MigrateTenantOptions {
|
|
741
|
+
/** Whether to skip actual SQL execution (dry run) */
|
|
742
|
+
dryRun?: boolean | undefined;
|
|
743
|
+
/** Progress callback */
|
|
744
|
+
onProgress?: MigrationProgressCallback | undefined;
|
|
234
745
|
}
|
|
235
746
|
/**
|
|
236
|
-
*
|
|
747
|
+
* Configuration for BatchExecutor
|
|
237
748
|
*/
|
|
238
|
-
interface
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
failed: number;
|
|
242
|
-
details: TenantSyncResult[];
|
|
749
|
+
interface BatchExecutorConfig {
|
|
750
|
+
/** Function to discover tenant IDs */
|
|
751
|
+
tenantDiscovery: () => Promise<string[]>;
|
|
243
752
|
}
|
|
244
753
|
/**
|
|
245
|
-
* Options for
|
|
754
|
+
* Options for batch migration operations
|
|
246
755
|
*/
|
|
247
|
-
interface
|
|
248
|
-
/** Number of concurrent
|
|
756
|
+
interface BatchMigrateOptions {
|
|
757
|
+
/** Number of concurrent migrations */
|
|
249
758
|
concurrency?: number;
|
|
250
759
|
/** Progress callback */
|
|
251
|
-
onProgress?:
|
|
760
|
+
onProgress?: MigrationProgressCallback;
|
|
252
761
|
/** Error handler */
|
|
253
762
|
onError?: MigrationErrorHandler;
|
|
763
|
+
/** Dry run mode */
|
|
764
|
+
dryRun?: boolean;
|
|
254
765
|
}
|
|
255
766
|
|
|
256
767
|
/**
|
|
257
|
-
*
|
|
768
|
+
* Responsible for executing migrations on individual tenants.
|
|
769
|
+
*
|
|
770
|
+
* Extracted from Migrator to follow Single Responsibility Principle.
|
|
771
|
+
* Handles single-tenant migration operations including:
|
|
772
|
+
* - Executing migrations with SQL
|
|
773
|
+
* - Marking migrations as applied (without SQL)
|
|
774
|
+
* - Checking migration status
|
|
775
|
+
* - Getting applied/pending migrations
|
|
776
|
+
*
|
|
777
|
+
* @example
|
|
778
|
+
* ```typescript
|
|
779
|
+
* const executor = new MigrationExecutor(config, dependencies);
|
|
780
|
+
*
|
|
781
|
+
* // Migrate a single tenant
|
|
782
|
+
* const result = await executor.migrateTenant('tenant-123');
|
|
783
|
+
*
|
|
784
|
+
* // Mark migrations as applied without executing SQL
|
|
785
|
+
* const markResult = await executor.markAsApplied('tenant-123');
|
|
786
|
+
*
|
|
787
|
+
* // Get tenant status
|
|
788
|
+
* const status = await executor.getTenantStatus('tenant-123');
|
|
789
|
+
* ```
|
|
258
790
|
*/
|
|
259
|
-
declare class
|
|
260
|
-
private readonly
|
|
261
|
-
private readonly
|
|
262
|
-
|
|
263
|
-
constructor(tenantConfig: Config<TTenantSchema, TSharedSchema>, migratorConfig: MigratorConfig);
|
|
791
|
+
declare class MigrationExecutor implements IMigrationExecutor {
|
|
792
|
+
private readonly config;
|
|
793
|
+
private readonly deps;
|
|
794
|
+
constructor(config: MigrationExecutorConfig, deps: MigrationExecutorDependencies);
|
|
264
795
|
/**
|
|
265
|
-
* Migrate
|
|
796
|
+
* Migrate a single tenant
|
|
797
|
+
*
|
|
798
|
+
* Applies all pending migrations to the tenant's schema.
|
|
799
|
+
* Creates the migrations table if it doesn't exist.
|
|
800
|
+
*
|
|
801
|
+
* @param tenantId - The tenant identifier
|
|
802
|
+
* @param migrations - Optional pre-loaded migrations (avoids reloading from disk)
|
|
803
|
+
* @param options - Migration options (dryRun, onProgress)
|
|
804
|
+
* @returns Migration result with applied migrations and duration
|
|
805
|
+
*
|
|
806
|
+
* @example
|
|
807
|
+
* ```typescript
|
|
808
|
+
* const result = await executor.migrateTenant('tenant-123', undefined, {
|
|
809
|
+
* dryRun: false,
|
|
810
|
+
* onProgress: (id, status, name) => console.log(`${id}: ${status} ${name}`),
|
|
811
|
+
* });
|
|
812
|
+
*
|
|
813
|
+
* if (result.success) {
|
|
814
|
+
* console.log(`Applied ${result.appliedMigrations.length} migrations`);
|
|
815
|
+
* }
|
|
816
|
+
* ```
|
|
266
817
|
*/
|
|
267
|
-
|
|
818
|
+
migrateTenant(tenantId: string, migrations?: MigrationFile[], options?: MigrateTenantOptions): Promise<TenantMigrationResult>;
|
|
268
819
|
/**
|
|
269
|
-
*
|
|
820
|
+
* Mark migrations as applied without executing SQL
|
|
821
|
+
*
|
|
822
|
+
* Useful for syncing tracking state with already-applied migrations
|
|
823
|
+
* or when migrations were applied manually.
|
|
824
|
+
*
|
|
825
|
+
* @param tenantId - The tenant identifier
|
|
826
|
+
* @param options - Options with progress callback
|
|
827
|
+
* @returns Result with list of marked migrations
|
|
828
|
+
*
|
|
829
|
+
* @example
|
|
830
|
+
* ```typescript
|
|
831
|
+
* const result = await executor.markAsApplied('tenant-123', {
|
|
832
|
+
* onProgress: (id, status, name) => console.log(`${id}: marking ${name}`),
|
|
833
|
+
* });
|
|
834
|
+
*
|
|
835
|
+
* console.log(`Marked ${result.appliedMigrations.length} migrations`);
|
|
836
|
+
* ```
|
|
270
837
|
*/
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
onProgress?: MigrateOptions['onProgress'];
|
|
838
|
+
markAsApplied(tenantId: string, options?: {
|
|
839
|
+
onProgress?: MigrateTenantOptions['onProgress'];
|
|
274
840
|
}): Promise<TenantMigrationResult>;
|
|
275
841
|
/**
|
|
276
|
-
*
|
|
842
|
+
* Get migration status for a specific tenant
|
|
843
|
+
*
|
|
844
|
+
* Returns information about applied and pending migrations.
|
|
845
|
+
*
|
|
846
|
+
* @param tenantId - The tenant identifier
|
|
847
|
+
* @param migrations - Optional pre-loaded migrations
|
|
848
|
+
* @returns Migration status with counts and pending list
|
|
849
|
+
*
|
|
850
|
+
* @example
|
|
851
|
+
* ```typescript
|
|
852
|
+
* const status = await executor.getTenantStatus('tenant-123');
|
|
853
|
+
* if (status.status === 'behind') {
|
|
854
|
+
* console.log(`Pending: ${status.pendingMigrations.join(', ')}`);
|
|
855
|
+
* }
|
|
856
|
+
* ```
|
|
277
857
|
*/
|
|
278
|
-
|
|
858
|
+
getTenantStatus(tenantId: string, migrations?: MigrationFile[]): Promise<TenantMigrationStatus>;
|
|
279
859
|
/**
|
|
280
|
-
*
|
|
860
|
+
* Execute a single migration on a schema
|
|
281
861
|
*/
|
|
282
|
-
|
|
862
|
+
executeMigration(pool: Pool, schemaName: string, migration: MigrationFile, format: DetectedFormat, options?: {
|
|
863
|
+
markOnly?: boolean;
|
|
864
|
+
onProgress?: (status: 'applying' | 'recording') => void;
|
|
865
|
+
}): Promise<void>;
|
|
283
866
|
/**
|
|
284
|
-
*
|
|
867
|
+
* Execute multiple migrations on a schema
|
|
285
868
|
*/
|
|
286
|
-
|
|
869
|
+
executeMigrations(pool: Pool, schemaName: string, migrations: MigrationFile[], format: DetectedFormat, options?: {
|
|
870
|
+
markOnly?: boolean;
|
|
871
|
+
onProgress?: (status: 'applying' | 'recording') => void;
|
|
872
|
+
}): Promise<string[]>;
|
|
287
873
|
/**
|
|
288
|
-
*
|
|
874
|
+
* Record a migration as applied without executing SQL
|
|
289
875
|
*/
|
|
290
|
-
|
|
876
|
+
recordMigration(pool: Pool, schemaName: string, migration: MigrationFile, format: DetectedFormat): Promise<void>;
|
|
291
877
|
/**
|
|
292
|
-
*
|
|
878
|
+
* Get list of applied migrations for a tenant
|
|
293
879
|
*/
|
|
294
|
-
|
|
880
|
+
getAppliedMigrations(pool: Pool, schemaName: string, format: DetectedFormat): Promise<AppliedMigration[]>;
|
|
295
881
|
/**
|
|
296
|
-
*
|
|
882
|
+
* Get pending migrations (not yet applied)
|
|
297
883
|
*/
|
|
298
|
-
|
|
884
|
+
getPendingMigrations(pool: Pool, schemaName: string, allMigrations: MigrationFile[], format: DetectedFormat): Promise<MigrationFile[]>;
|
|
299
885
|
/**
|
|
300
|
-
*
|
|
301
|
-
* Useful for syncing tracking state with already-applied migrations
|
|
886
|
+
* Check if a migration has been applied
|
|
302
887
|
*/
|
|
303
|
-
|
|
304
|
-
onProgress?: MigrateOptions['onProgress'];
|
|
305
|
-
}): Promise<TenantMigrationResult>;
|
|
888
|
+
private isMigrationApplied;
|
|
306
889
|
/**
|
|
307
|
-
*
|
|
308
|
-
* Useful for syncing tracking state with already-applied migrations
|
|
890
|
+
* Apply a migration to a schema (execute SQL + record)
|
|
309
891
|
*/
|
|
310
|
-
|
|
892
|
+
private applyMigration;
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* Factory function to create a MigrationExecutor instance
|
|
896
|
+
*
|
|
897
|
+
* @param config - Executor configuration (hooks)
|
|
898
|
+
* @param dependencies - Required dependencies
|
|
899
|
+
* @returns A configured MigrationExecutor instance
|
|
900
|
+
*
|
|
901
|
+
* @example
|
|
902
|
+
* ```typescript
|
|
903
|
+
* const executor = createMigrationExecutor(
|
|
904
|
+
* { hooks: { beforeTenant: async (id) => console.log(`Starting ${id}`) } },
|
|
905
|
+
* {
|
|
906
|
+
* createPool: schemaManager.createPool.bind(schemaManager),
|
|
907
|
+
* schemaNameTemplate: (id) => `tenant_${id}`,
|
|
908
|
+
* migrationsTableExists: schemaManager.migrationsTableExists.bind(schemaManager),
|
|
909
|
+
* ensureMigrationsTable: schemaManager.ensureMigrationsTable.bind(schemaManager),
|
|
910
|
+
* getOrDetectFormat: async (pool, schema) => getFormatConfig('name', table),
|
|
911
|
+
* loadMigrations: async () => loadMigrationsFromDisk(),
|
|
912
|
+
* }
|
|
913
|
+
* );
|
|
914
|
+
* ```
|
|
915
|
+
*/
|
|
916
|
+
declare function createMigrationExecutor(config: MigrationExecutorConfig, dependencies: MigrationExecutorDependencies): MigrationExecutor;
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Responsible for batch migration operations across multiple tenants.
|
|
920
|
+
*
|
|
921
|
+
* Extracted from Migrator to follow Single Responsibility Principle.
|
|
922
|
+
* Handles parallel migration operations including:
|
|
923
|
+
* - Migrating all tenants with configurable concurrency
|
|
924
|
+
* - Migrating specific tenants
|
|
925
|
+
* - Marking all migrations as applied
|
|
926
|
+
* - Progress tracking and error handling
|
|
927
|
+
*
|
|
928
|
+
* @example
|
|
929
|
+
* ```typescript
|
|
930
|
+
* const batchExecutor = new BatchExecutor(config, migrationExecutor, loadMigrations);
|
|
931
|
+
*
|
|
932
|
+
* // Migrate all tenants with concurrency 10
|
|
933
|
+
* const results = await batchExecutor.migrateAll({ concurrency: 10 });
|
|
934
|
+
*
|
|
935
|
+
* // Migrate specific tenants
|
|
936
|
+
* const specificResults = await batchExecutor.migrateTenants(['t1', 't2'], {
|
|
937
|
+
* onProgress: (id, status) => console.log(`${id}: ${status}`),
|
|
938
|
+
* });
|
|
939
|
+
* ```
|
|
940
|
+
*/
|
|
941
|
+
declare class BatchExecutor implements IBatchExecutor {
|
|
942
|
+
private readonly config;
|
|
943
|
+
private readonly executor;
|
|
944
|
+
private readonly loadMigrations;
|
|
945
|
+
constructor(config: BatchExecutorConfig, executor: MigrationExecutor, loadMigrations: () => Promise<MigrationFile[]>);
|
|
311
946
|
/**
|
|
312
|
-
*
|
|
313
|
-
*
|
|
947
|
+
* Migrate all tenants in parallel
|
|
948
|
+
*
|
|
949
|
+
* Processes tenants in batches with configurable concurrency.
|
|
950
|
+
* Supports progress callbacks, error handling, and abort behavior.
|
|
951
|
+
*
|
|
952
|
+
* @param options - Migration options (concurrency, dryRun, callbacks)
|
|
953
|
+
* @returns Aggregate results for all tenants
|
|
954
|
+
*
|
|
955
|
+
* @example
|
|
956
|
+
* ```typescript
|
|
957
|
+
* const results = await batchExecutor.migrateAll({
|
|
958
|
+
* concurrency: 10,
|
|
959
|
+
* dryRun: false,
|
|
960
|
+
* onProgress: (id, status) => console.log(`${id}: ${status}`),
|
|
961
|
+
* onError: (id, error) => {
|
|
962
|
+
* console.error(`${id} failed: ${error.message}`);
|
|
963
|
+
* return 'continue'; // or 'abort' to stop all
|
|
964
|
+
* },
|
|
965
|
+
* });
|
|
966
|
+
*
|
|
967
|
+
* console.log(`Succeeded: ${results.succeeded}/${results.total}`);
|
|
968
|
+
* ```
|
|
314
969
|
*/
|
|
315
|
-
|
|
970
|
+
migrateAll(options?: BatchMigrateOptions): Promise<MigrationResults>;
|
|
316
971
|
/**
|
|
317
|
-
*
|
|
972
|
+
* Migrate specific tenants in parallel
|
|
973
|
+
*
|
|
974
|
+
* Same as migrateAll but for a subset of tenants.
|
|
975
|
+
*
|
|
976
|
+
* @param tenantIds - List of tenant IDs to migrate
|
|
977
|
+
* @param options - Migration options
|
|
978
|
+
* @returns Aggregate results for specified tenants
|
|
979
|
+
*
|
|
980
|
+
* @example
|
|
981
|
+
* ```typescript
|
|
982
|
+
* const results = await batchExecutor.migrateTenants(
|
|
983
|
+
* ['tenant-1', 'tenant-2', 'tenant-3'],
|
|
984
|
+
* { concurrency: 5 }
|
|
985
|
+
* );
|
|
986
|
+
* ```
|
|
318
987
|
*/
|
|
319
|
-
|
|
988
|
+
migrateTenants(tenantIds: string[], options?: BatchMigrateOptions): Promise<MigrationResults>;
|
|
320
989
|
/**
|
|
321
|
-
* Mark
|
|
990
|
+
* Mark all tenants as applied without executing SQL
|
|
991
|
+
*
|
|
992
|
+
* Useful for syncing tracking state with already-applied migrations.
|
|
993
|
+
* Processes tenants in parallel with configurable concurrency.
|
|
994
|
+
*
|
|
995
|
+
* @param options - Migration options
|
|
996
|
+
* @returns Aggregate results for all tenants
|
|
997
|
+
*
|
|
998
|
+
* @example
|
|
999
|
+
* ```typescript
|
|
1000
|
+
* const results = await batchExecutor.markAllAsApplied({
|
|
1001
|
+
* concurrency: 10,
|
|
1002
|
+
* onProgress: (id, status) => console.log(`${id}: ${status}`),
|
|
1003
|
+
* });
|
|
1004
|
+
* ```
|
|
322
1005
|
*/
|
|
323
|
-
|
|
1006
|
+
markAllAsApplied(options?: BatchMigrateOptions): Promise<MigrationResults>;
|
|
324
1007
|
/**
|
|
325
|
-
*
|
|
1008
|
+
* Get migration status for all tenants
|
|
1009
|
+
*
|
|
1010
|
+
* Queries each tenant's migration status sequentially.
|
|
1011
|
+
*
|
|
1012
|
+
* @returns List of migration status for all tenants
|
|
1013
|
+
*
|
|
1014
|
+
* @example
|
|
1015
|
+
* ```typescript
|
|
1016
|
+
* const statuses = await batchExecutor.getStatus();
|
|
1017
|
+
* const behind = statuses.filter(s => s.status === 'behind');
|
|
1018
|
+
* console.log(`${behind.length} tenants need migrations`);
|
|
1019
|
+
* ```
|
|
326
1020
|
*/
|
|
327
|
-
|
|
1021
|
+
getStatus(): Promise<TenantMigrationStatus[]>;
|
|
328
1022
|
/**
|
|
329
|
-
*
|
|
1023
|
+
* Create a skipped result for aborted operations
|
|
330
1024
|
*/
|
|
331
|
-
|
|
1025
|
+
private createSkippedResult;
|
|
332
1026
|
/**
|
|
333
|
-
*
|
|
1027
|
+
* Create an error result for failed operations
|
|
334
1028
|
*/
|
|
335
|
-
|
|
1029
|
+
private createErrorResult;
|
|
336
1030
|
/**
|
|
337
|
-
*
|
|
1031
|
+
* Aggregate individual migration results into a summary
|
|
338
1032
|
*/
|
|
339
|
-
private
|
|
1033
|
+
private aggregateResults;
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Factory function to create a BatchExecutor instance
|
|
1037
|
+
*
|
|
1038
|
+
* @param config - Batch configuration (tenantDiscovery)
|
|
1039
|
+
* @param executor - MigrationExecutor instance
|
|
1040
|
+
* @param loadMigrations - Function to load migrations from disk
|
|
1041
|
+
* @returns A configured BatchExecutor instance
|
|
1042
|
+
*
|
|
1043
|
+
* @example
|
|
1044
|
+
* ```typescript
|
|
1045
|
+
* const batchExecutor = createBatchExecutor(
|
|
1046
|
+
* { tenantDiscovery: async () => ['t1', 't2', 't3'] },
|
|
1047
|
+
* migrationExecutor,
|
|
1048
|
+
* async () => loadMigrationsFromDisk('./migrations')
|
|
1049
|
+
* );
|
|
1050
|
+
* ```
|
|
1051
|
+
*/
|
|
1052
|
+
declare function createBatchExecutor(config: BatchExecutorConfig, executor: MigrationExecutor, loadMigrations: () => Promise<MigrationFile[]>): BatchExecutor;
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* Cloner
|
|
1056
|
+
*
|
|
1057
|
+
* Clones a tenant to another, including structure and optionally data.
|
|
1058
|
+
*
|
|
1059
|
+
* @module clone/cloner
|
|
1060
|
+
*/
|
|
1061
|
+
|
|
1062
|
+
/**
|
|
1063
|
+
* Clones tenants with support for introspection + DDL
|
|
1064
|
+
*
|
|
1065
|
+
* @example
|
|
1066
|
+
* ```typescript
|
|
1067
|
+
* const cloner = createCloner(config, dependencies);
|
|
1068
|
+
*
|
|
1069
|
+
* // Schema-only clone
|
|
1070
|
+
* await cloner.cloneTenant('source', 'target');
|
|
1071
|
+
*
|
|
1072
|
+
* // Clone with data
|
|
1073
|
+
* await cloner.cloneTenant('source', 'target', { includeData: true });
|
|
1074
|
+
*
|
|
1075
|
+
* // Clone with anonymization
|
|
1076
|
+
* await cloner.cloneTenant('source', 'target', {
|
|
1077
|
+
* includeData: true,
|
|
1078
|
+
* anonymize: {
|
|
1079
|
+
* enabled: true,
|
|
1080
|
+
* rules: { users: { email: null, phone: null } },
|
|
1081
|
+
* },
|
|
1082
|
+
* });
|
|
1083
|
+
* ```
|
|
1084
|
+
*/
|
|
1085
|
+
declare class Cloner {
|
|
1086
|
+
private readonly deps;
|
|
1087
|
+
private readonly migrationsTable;
|
|
1088
|
+
constructor(config: ClonerConfig, deps: ClonerDependencies);
|
|
340
1089
|
/**
|
|
341
|
-
*
|
|
1090
|
+
* Clone a tenant to another
|
|
1091
|
+
*
|
|
1092
|
+
* @param sourceTenantId - Source tenant ID
|
|
1093
|
+
* @param targetTenantId - Target tenant ID
|
|
1094
|
+
* @param options - Clone options
|
|
1095
|
+
* @returns Clone result
|
|
342
1096
|
*/
|
|
343
|
-
|
|
1097
|
+
cloneTenant(sourceTenantId: string, targetTenantId: string, options?: CloneTenantOptions): Promise<CloneTenantResult>;
|
|
1098
|
+
private createErrorResult;
|
|
1099
|
+
}
|
|
1100
|
+
/**
|
|
1101
|
+
* Factory function for Cloner
|
|
1102
|
+
*
|
|
1103
|
+
* @param config - Cloner configuration
|
|
1104
|
+
* @param dependencies - Cloner dependencies
|
|
1105
|
+
* @returns Cloner instance
|
|
1106
|
+
*/
|
|
1107
|
+
declare function createCloner(config: ClonerConfig, dependencies: ClonerDependencies): Cloner;
|
|
1108
|
+
|
|
1109
|
+
/**
|
|
1110
|
+
* Configuration for SharedMigrationExecutor
|
|
1111
|
+
*/
|
|
1112
|
+
interface SharedMigrationExecutorConfig {
|
|
1113
|
+
/** Schema name for shared tables (default: 'public') */
|
|
1114
|
+
schemaName?: string;
|
|
1115
|
+
/** Table name for tracking migrations */
|
|
1116
|
+
migrationsTable: string;
|
|
1117
|
+
/** Hooks for migration events */
|
|
1118
|
+
hooks?: {
|
|
1119
|
+
beforeMigration?: () => void | Promise<void>;
|
|
1120
|
+
afterMigration?: (migrationName: string, durationMs: number) => void | Promise<void>;
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Dependencies for SharedMigrationExecutor
|
|
1125
|
+
*/
|
|
1126
|
+
interface SharedMigrationExecutorDependencies {
|
|
1127
|
+
/** Create a database pool for the shared schema */
|
|
1128
|
+
createPool: () => Promise<Pool>;
|
|
1129
|
+
/** Check if migrations table exists */
|
|
1130
|
+
migrationsTableExists: (pool: Pool, schemaName: string) => Promise<boolean>;
|
|
1131
|
+
/** Ensure migrations table exists with correct format */
|
|
1132
|
+
ensureMigrationsTable: (pool: Pool, schemaName: string, format: DetectedFormat) => Promise<void>;
|
|
1133
|
+
/** Get or detect migration table format */
|
|
1134
|
+
getOrDetectFormat: (pool: Pool, schemaName: string) => Promise<DetectedFormat>;
|
|
1135
|
+
/** Load migrations from disk */
|
|
1136
|
+
loadMigrations: () => Promise<MigrationFile[]>;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
/**
|
|
1140
|
+
* Executor for shared schema migrations
|
|
1141
|
+
*
|
|
1142
|
+
* Handles migrations for the shared/public schema, separate from tenant schemas.
|
|
1143
|
+
* Used for tables that are shared across all tenants (e.g., plans, roles, permissions).
|
|
1144
|
+
*
|
|
1145
|
+
* @example
|
|
1146
|
+
* ```typescript
|
|
1147
|
+
* const executor = new SharedMigrationExecutor(config, dependencies);
|
|
1148
|
+
*
|
|
1149
|
+
* // Get status
|
|
1150
|
+
* const status = await executor.getStatus();
|
|
1151
|
+
* console.log(`Pending: ${status.pendingCount}`);
|
|
1152
|
+
*
|
|
1153
|
+
* // Apply migrations
|
|
1154
|
+
* const result = await executor.migrate();
|
|
1155
|
+
* console.log(`Applied: ${result.appliedMigrations.length}`);
|
|
1156
|
+
* ```
|
|
1157
|
+
*/
|
|
1158
|
+
declare class SharedMigrationExecutor {
|
|
1159
|
+
private readonly config;
|
|
1160
|
+
private readonly deps;
|
|
1161
|
+
private readonly schemaName;
|
|
1162
|
+
constructor(config: SharedMigrationExecutorConfig, deps: SharedMigrationExecutorDependencies);
|
|
344
1163
|
/**
|
|
345
|
-
*
|
|
1164
|
+
* Apply pending migrations to the shared schema
|
|
1165
|
+
*
|
|
1166
|
+
* @param options - Migration options (dryRun, onProgress)
|
|
1167
|
+
* @returns Migration result with applied migrations
|
|
1168
|
+
*
|
|
1169
|
+
* @example
|
|
1170
|
+
* ```typescript
|
|
1171
|
+
* const result = await executor.migrate({
|
|
1172
|
+
* dryRun: false,
|
|
1173
|
+
* onProgress: (status, name) => console.log(`${status}: ${name}`),
|
|
1174
|
+
* });
|
|
1175
|
+
*
|
|
1176
|
+
* if (result.success) {
|
|
1177
|
+
* console.log(`Applied ${result.appliedMigrations.length} migrations`);
|
|
1178
|
+
* }
|
|
1179
|
+
* ```
|
|
346
1180
|
*/
|
|
347
|
-
|
|
1181
|
+
migrate(options?: SharedMigrateOptions): Promise<SharedMigrationResult>;
|
|
348
1182
|
/**
|
|
349
|
-
*
|
|
1183
|
+
* Mark migrations as applied without executing SQL
|
|
1184
|
+
*
|
|
1185
|
+
* Useful for syncing tracking state with already-applied migrations.
|
|
1186
|
+
*
|
|
1187
|
+
* @param options - Options with progress callback
|
|
1188
|
+
* @returns Result with list of marked migrations
|
|
350
1189
|
*/
|
|
351
|
-
|
|
1190
|
+
markAsApplied(options?: {
|
|
1191
|
+
onProgress?: SharedMigrateOptions['onProgress'];
|
|
1192
|
+
}): Promise<SharedMigrationResult>;
|
|
352
1193
|
/**
|
|
353
|
-
* Get
|
|
1194
|
+
* Get migration status for the shared schema
|
|
1195
|
+
*
|
|
1196
|
+
* @returns Status with applied/pending counts
|
|
1197
|
+
*/
|
|
1198
|
+
getStatus(): Promise<SharedMigrationStatus>;
|
|
1199
|
+
/**
|
|
1200
|
+
* Get list of applied migrations
|
|
354
1201
|
*/
|
|
355
1202
|
private getAppliedMigrations;
|
|
356
1203
|
/**
|
|
@@ -358,47 +1205,17 @@ declare class Migrator<TTenantSchema extends Record<string, unknown>, TSharedSch
|
|
|
358
1205
|
*/
|
|
359
1206
|
private isMigrationApplied;
|
|
360
1207
|
/**
|
|
361
|
-
*
|
|
362
|
-
* Returns the configured format or auto-detects from existing table
|
|
363
|
-
*/
|
|
364
|
-
private getOrDetectFormat;
|
|
365
|
-
/**
|
|
366
|
-
* Apply a migration to a schema
|
|
1208
|
+
* Apply a migration (execute SQL + record)
|
|
367
1209
|
*/
|
|
368
1210
|
private applyMigration;
|
|
369
1211
|
/**
|
|
370
1212
|
* Record a migration as applied without executing SQL
|
|
371
|
-
* Used by markAsApplied to sync tracking state
|
|
372
1213
|
*/
|
|
373
1214
|
private recordMigration;
|
|
374
|
-
/**
|
|
375
|
-
* Create a skipped result
|
|
376
|
-
*/
|
|
377
|
-
private createSkippedResult;
|
|
378
|
-
/**
|
|
379
|
-
* Create an error result
|
|
380
|
-
*/
|
|
381
|
-
private createErrorResult;
|
|
382
|
-
/**
|
|
383
|
-
* Aggregate migration results
|
|
384
|
-
*/
|
|
385
|
-
private aggregateResults;
|
|
386
|
-
/**
|
|
387
|
-
* Create a skipped sync result
|
|
388
|
-
*/
|
|
389
|
-
private createSkippedSyncResult;
|
|
390
|
-
/**
|
|
391
|
-
* Create an error sync result
|
|
392
|
-
*/
|
|
393
|
-
private createErrorSyncResult;
|
|
394
|
-
/**
|
|
395
|
-
* Aggregate sync results
|
|
396
|
-
*/
|
|
397
|
-
private aggregateSyncResults;
|
|
398
1215
|
}
|
|
399
1216
|
/**
|
|
400
|
-
*
|
|
1217
|
+
* Factory function to create a SharedMigrationExecutor
|
|
401
1218
|
*/
|
|
402
|
-
declare function
|
|
1219
|
+
declare function createSharedMigrationExecutor(config: SharedMigrationExecutorConfig, dependencies: SharedMigrationExecutorDependencies): SharedMigrationExecutor;
|
|
403
1220
|
|
|
404
|
-
export { type
|
|
1221
|
+
export { BatchExecutor, type BatchExecutorConfig, type BatchMigrateOptions, CloneTenantOptions, CloneTenantResult, Cloner, ClonerConfig, ClonerDependencies, type CreateSchemaOptions, DetectedFormat, type DropSchemaOptions, MigrateOptions, type MigrateTenantOptions, MigrationErrorHandler, MigrationExecutor, type MigrationExecutorConfig, type MigrationExecutorDependencies, MigrationFile, MigrationHooks, MigrationProgressCallback, MigrationResults, SchemaManager, SeedFunction, SeedOptions, SeedResults, Seeder, type SeederConfig, type SeederDependencies, SharedMigrateOptions, SharedMigrationExecutor, type SharedMigrationExecutorConfig, type SharedMigrationExecutorDependencies, SharedMigrationResult, SharedMigrationStatus, SyncManager, type SyncManagerConfig, type SyncManagerDependencies, SyncOptions, SyncResults, SyncStatus, TenantMigrationResult, TenantMigrationStatus, TenantSeedResult, TenantSyncResult, TenantSyncStatus, createBatchExecutor, createCloner, createMigrationExecutor, createSchemaManager, createSeeder, createSharedMigrationExecutor, createSyncManager };
|