Skip to content

Commit 1e5a03d

Browse files
committed
#135: Update documentation for v0.8.0 release
Created comprehensive v0.7-to-v0.8 migration guide with feature documentation and examples. Updated all documentation files: - README.md and docs/index.md with v0.8.0 "What's New" sections - Reorganized version migration index with "Current" and "Previous Releases" - Updated API docs for lockingService and THandler generic parameter - Updated guide docs with locking examples (production-deployment, cli-adapter-development) - Enhanced comparison.md with detailed comparison tables for JS/TS and cross-platform tools
1 parent fc5d3f4 commit 1e5a03d

11 files changed

Lines changed: 713 additions & 130 deletions

File tree

README.md

Lines changed: 24 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -21,60 +21,36 @@ MSR provides a lightweight, flexible framework for managing database migrations
2121

2222
---
2323

24-
## 🎉 What's New in v0.7.0
24+
## 🎉 What's New in v0.8.0
2525

26-
**Enhanced architecture, adapter extensibility, and improved maintainability:**
26+
**Production-ready locking, enhanced type safety, and critical bug fixes:**
2727

28-
- **🎨 Facade Pattern** - Services grouped into 4 logical facades (core, execution, output, orchestration) for better code organization
29-
- **🏭 Factory Pattern** - Service initialization extracted to dedicated factory, reducing constructor complexity by 83%
30-
- **🔧 Protected Facades** - Adapters can extend MigrationScriptExecutor and access internal services through protected facades
31-
- **✨ Extensible Configuration** - New `IConfigLoader` interface allows adapters to customize environment variable handling
32-
- **🗂️ .env File Support** - Load configuration from `.env`, `.env.production`, `.env.local` files with configurable priority
33-
- **🔨 Simplified Constructor** - Single parameter constructor with config moved into dependencies object (**BREAKING**)
34-
- **🔒 Better Encapsulation** - Internal services no longer exposed as public properties (**BREAKING**)
35-
- **⚡ Reduced Complexity** - Constructor reduced from 142 lines to 23 lines (83% reduction)
36-
- **📐 Workflow Ownership** - `executeBeforeMigrate()` moved to MigrationWorkflowOrchestrator for cleaner architecture
37-
- **✨ 100% Test Coverage** - All statements, branches, functions, and lines covered (1228/1228 tests passing)
28+
- **🔒 Migration Locking** - Prevent concurrent migrations with database-level locking mechanism for multi-instance deployments
29+
- **🛡️ Lock Ownership Verification** - Two-phase locking with ownership verification prevents race conditions and ensures safe execution
30+
- **🖥️ Lock CLI Commands** - New `lock:status` and `lock:release` commands for managing locks in production environments
31+
- **🔧 Handler Generic Type** - Type-safe handler access in adapters with optional second generic parameter (no more casting!)
32+
- **🐛 Down Migration Fix** - Fixed TypeError when rolling back migrations (migration records now properly matched with filesystem scripts)
33+
- **📦 npm Provenance** - Enhanced supply chain security with build provenance attestations
34+
- **✨ 100% Backwards Compatible** - Zero breaking changes from v0.7.x, all features are opt-in
3835

39-
**⚠️ BREAKING CHANGES in v0.7.0:** Constructor signature changed (config moved into dependencies), and service properties removed (use public API methods instead). Migration takes 15-30 minutes. See the [v0.6.x → v0.7.0 Migration Guide](https://migration-script-runner.github.io/msr-core/version-migration/v0.6-to-v0.7) for step-by-step instructions.
36+
**✅ NO BREAKING CHANGES in v0.8.0:** Fully backwards compatible with v0.7.x. Locking is disabled by default and can be enabled when ready. Handler generic type is optional with sensible defaults. See the [v0.7.x → v0.8.0 Migration Guide](https://migration-script-runner.github.io/msr-core/version-migration/v0.7-to-v0.8) for upgrade instructions and new features.
4037

41-
**[→ View architecture docs](https://migration-script-runner.github.io/msr-core/development/architecture/design-patterns)**
38+
**[→ View locking documentation](https://migration-script-runner.github.io/msr-core/configuration/locking-settings)**
4239

4340
---
4441

4542
## 📜 Previous Releases
4643

47-
### v0.6.0
48-
49-
**Enhanced type safety, metrics collection, and multi-format configuration:**
50-
51-
- **🛡️ Generic Type Parameters** - Database-specific type safety with `<DB extends IDB>` generics throughout the API (**BREAKING**: type parameters now required)
52-
- **📊 Metrics Collection** - Built-in collectors for observability with console, JSON, CSV, and logger-based output
53-
- **📄 YAML, TOML, and XML Support** - Use your preferred config format (`.yaml`, `.toml`, `.xml`) alongside JS/JSON
54-
- **🔌 Plugin Architecture** - Extensible loader system with optional peer dependencies keeps core lightweight
55-
- **🎚️ Log Level Control** - Configurable log levels (`error`, `warn`, `info`, `debug`) to control output verbosity
56-
- **💡 Better Error Messages** - Actionable error messages with installation instructions when formats aren't available
57-
58-
**[→ View migration guide](https://migration-script-runner.github.io/msr-core/version-migration/v0.5-to-v0.6)**
59-
60-
### v0.5.0
61-
62-
**Production-grade transaction management and cloud-native configuration:**
63-
64-
- **🔒 Transaction Management** - Configurable modes (per-migration, per-batch, none) with automatic retry logic and isolation level control
65-
- **⚙️ Environment Variables** - Complete MSR_* configuration support following 12-factor app principles for Docker, Kubernetes, and CI/CD
66-
- **📊 Enhanced Hooks** - Transaction lifecycle hooks for monitoring and metrics collection
67-
- **🚀 100% Backward Compatible** - Zero breaking changes from v0.4.x
68-
69-
**[→ View migration guide](https://migration-script-runner.github.io/msr-core/version-migration/v0.4-to-v0.5)**
44+
For information about previous releases, see the [Version Migration Guide](https://migration-script-runner.github.io/msr-core/version-migration/).
7045

7146
---
7247

7348
## ✨ Features
7449

75-
- **🖥️ CLI Factory** - Built-in command-line interface with migrate, list, down, validate, and backup commands (v0.7.0)
50+
- **🔒 Migration Locking** - Database-level locking prevents concurrent migrations in multi-instance deployments (v0.8.0)
51+
- **🖥️ CLI Factory** - Built-in command-line interface with migrate, list, down, validate, backup, and lock commands (v0.7.0+)
7652
- **🔌 Database Agnostic** - Works with any database (SQL, NoSQL, NewSQL) by implementing a simple interface
77-
- **🛡️ Type Safe** - Full TypeScript support with complete type definitions
53+
- **🛡️ Type Safe** - Full TypeScript support with complete type definitions and handler generics (v0.8.0)
7854
- **💾 Smart Rollback** - Multiple strategies: backup/restore, down() methods, both, or none
7955
- **🔒 Transaction Control** - Configurable transaction modes with automatic retry and isolation levels (v0.5.0)
8056
- **⚙️ Environment Variables** - Full 12-factor app configuration support with MSR_* variables (v0.5.0)
@@ -243,6 +219,15 @@ npx my-db-migrate validate
243219
# Create database backup
244220
npx my-db-migrate backup
245221

222+
# Check lock status (v0.8.0)
223+
npx my-db-migrate lock:status
224+
225+
# Force-release stuck lock (v0.8.0)
226+
npx my-db-migrate lock:release --force
227+
228+
# Run migration without locking (v0.8.0)
229+
npx my-db-migrate migrate --no-lock
230+
246231
# Use environment-specific config
247232
npx my-db-migrate migrate --config-file .env.production
248233
```

docs/api/core-classes.md

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ The main classes for executing and managing migrations.
2323

2424
The main class for executing database migrations.
2525

26-
**New in v0.6.0:** Generic type parameters provide full type safety for database-specific operations.
26+
**Generic Type Parameters:**
27+
- **v0.6.0:** Database type parameter (`DB extends IDB`) provides database-specific type safety
28+
- **v0.8.0:** Handler type parameter (`THandler extends IDatabaseMigrationHandler<DB>`) provides type-safe handler access in adapters
2729

2830
```typescript
2931
import { MigrationScriptExecutor, IDatabaseMigrationHandler, Config, IDB } from '@migration-script-runner/core';
@@ -33,14 +35,33 @@ interface IMyDatabase extends IDB {
3335
query(sql: string): Promise<any>;
3436
}
3537

38+
// Basic usage - handler type inferred
3639
const handler = new MyDatabaseHandler(); // implements IDatabaseMigrationHandler<IMyDatabase>
3740
const config = new Config();
3841
const executor = new MigrationScriptExecutor<IMyDatabase>({ handler , config });
42+
43+
// v0.8.0: Type-safe adapter with handler generic (for custom adapters)
44+
class MyAdapter extends MigrationScriptExecutor<IMyDatabase, MyDatabaseHandler> {
45+
// this.handler is now typed as MyDatabaseHandler (no casting needed!)
46+
getConnectionInfo() {
47+
return this.handler.customProperty; // Full IDE autocomplete
48+
}
49+
}
3950
```
4051

4152
#### Constructor
4253

43-
**Signature (v0.7.0+):**
54+
**Signature (v0.8.0+):**
55+
```typescript
56+
constructor<
57+
DB extends IDB,
58+
THandler extends IDatabaseMigrationHandler<DB> = IDatabaseMigrationHandler<DB>
59+
>(
60+
dependencies: IMigrationExecutorDependencies<DB, THandler>
61+
)
62+
```
63+
64+
**Signature (v0.7.0 - v0.7.x):**
4465
```typescript
4566
constructor<DB extends IDB>(
4667
dependencies: IMigrationExecutorDependencies<DB>

docs/api/interfaces/database-handler.md

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Interface that must be implemented for your specific database.
2727
{: .note }
2828
> **Design Origin**: The handler pattern emerged from MSR's 2017 Firebase prototype, where an `EntityService` provided clean helper methods like `updateAll(callback)` and `findAllBy(propertyName, value)`. Instead of raw database SDK calls in every migration, this service layer made migrations declarative and maintainable. This pattern proved so valuable it became core to MSR's architecture - allowing you to inject your own services, repositories, and business logic into migrations. Read more in the [origin story](../../about/origin-story).
2929
30-
**Signature (v0.6.0+):**
30+
**Signature (v0.8.0+):**
3131
```typescript
3232
interface IDatabaseMigrationHandler<DB extends IDB> {
3333
getName(): string;
@@ -36,6 +36,7 @@ interface IDatabaseMigrationHandler<DB extends IDB> {
3636
schemaVersion: ISchemaVersion<DB>;
3737
backup?: IBackup<DB>; // Optional - only needed for BACKUP or BOTH strategies
3838
transactionManager?: ITransactionManager<DB>; // Optional - auto-created if db supports transactions
39+
lockingService?: ILockingService<DB>; // Optional (v0.8.0) - enables concurrent migration prevention
3940
}
4041
```
4142

@@ -124,6 +125,122 @@ Handles database backup and restore operations. See [`IBackup` interface](backup
124125

125126
---
126127

128+
### lockingService
129+
130+
Locking interface for preventing concurrent migrations (optional, v0.8.0).
131+
132+
```typescript
133+
lockingService?: ILockingService<DB>
134+
```
135+
136+
**Optional (v0.8.0):** Provides database-level locking to prevent multiple processes from running migrations simultaneously. When not provided, locking is disabled.
137+
138+
**Use Cases:**
139+
- **Multi-instance deployments** - Multiple application servers running migrations
140+
- **Kubernetes/Docker** - Prevent concurrent migrations during rolling deployments
141+
- **CI/CD pipelines** - Avoid conflicts when parallel builds trigger migrations
142+
143+
**Example:**
144+
```typescript
145+
import { ILockingService } from '@migration-script-runner/core';
146+
147+
class PostgresLockingService implements ILockingService<PostgresDB> {
148+
constructor(private db: PostgresDB) {}
149+
150+
async acquireLock(executorId: string, timeout: number): Promise<boolean> {
151+
// Use SELECT FOR UPDATE NOWAIT or INSERT with ON CONFLICT
152+
const result = await this.db.query(`
153+
INSERT INTO migration_locks (executor_id, locked_at, expires_at)
154+
VALUES ($1, NOW(), NOW() + INTERVAL '${timeout}ms')
155+
ON CONFLICT (id) DO NOTHING
156+
RETURNING id
157+
`, [executorId]);
158+
return result.rows.length > 0;
159+
}
160+
161+
async verifyLockOwnership(executorId: string): Promise<boolean> {
162+
const result = await this.db.query(
163+
'SELECT executor_id FROM migration_locks WHERE id = 1'
164+
);
165+
return result.rows[0]?.executor_id === executorId;
166+
}
167+
168+
async releaseLock(executorId: string): Promise<void> {
169+
await this.db.query(
170+
'DELETE FROM migration_locks WHERE executor_id = $1',
171+
[executorId]
172+
);
173+
}
174+
175+
async forceReleaseLock(): Promise<void> {
176+
await this.db.query('DELETE FROM migration_locks WHERE id = 1');
177+
}
178+
179+
async checkAndReleaseExpiredLock(): Promise<void> {
180+
await this.db.query(
181+
'DELETE FROM migration_locks WHERE expires_at < NOW()'
182+
);
183+
}
184+
185+
async getLockStatus(): Promise<ILockStatus> {
186+
const result = await this.db.query(`
187+
SELECT executor_id, locked_at, expires_at
188+
FROM migration_locks WHERE id = 1
189+
`);
190+
191+
if (result.rows.length === 0) {
192+
return {
193+
isLocked: false,
194+
lockedBy: null,
195+
lockedAt: null,
196+
expiresAt: null
197+
};
198+
}
199+
200+
const row = result.rows[0];
201+
return {
202+
isLocked: true,
203+
lockedBy: row.executor_id,
204+
lockedAt: new Date(row.locked_at),
205+
expiresAt: new Date(row.expires_at)
206+
};
207+
}
208+
}
209+
210+
// Add to handler
211+
class PostgresHandler implements IDatabaseMigrationHandler<PostgresDB> {
212+
db: PostgresDB;
213+
schemaVersion: PostgresSchemaVersion;
214+
backup?: PostgresBackup;
215+
lockingService?: ILockingService<PostgresDB>;
216+
217+
constructor(pool: Pool, options: { useBackup?: boolean; useLocking?: boolean } = {}) {
218+
this.db = new PostgresDB(pool);
219+
this.schemaVersion = new PostgresSchemaVersion(this.db);
220+
221+
if (options.useBackup) {
222+
this.backup = new PostgresBackup(this.db, config);
223+
}
224+
225+
if (options.useLocking) {
226+
this.lockingService = new PostgresLockingService(this.db);
227+
}
228+
}
229+
230+
getName(): string {
231+
return 'PostgreSQL Handler';
232+
}
233+
234+
getVersion(): string {
235+
return '1.0.0';
236+
}
237+
}
238+
```
239+
240+
See [Locking Configuration](../configuration/locking-settings) for configuration options and [Lock Commands](../guides/lock-commands) for CLI usage.
241+
242+
---
243+
127244
## Complete Example
128245

129246
### PostgreSQL Handler

0 commit comments

Comments
 (0)