feat(smartmigration): add initial smartmigration package with MongoDB and S3 migration runner
This commit is contained in:
95
ts/classes.migrationstep.ts
Normal file
95
ts/classes.migrationstep.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import type {
|
||||
IMigrationContext,
|
||||
IMigrationStepDefinition,
|
||||
} from './interfaces.js';
|
||||
import type { SmartMigration } from './classes.smartmigration.js';
|
||||
import { SmartMigrationError } from './classes.versionresolver.js';
|
||||
|
||||
/**
|
||||
* Builder returned by `SmartMigration.step(id)`. The chain is:
|
||||
* .from('1.0.0').to('1.1.0').description('...').resumable().up(async ctx => {...})
|
||||
*
|
||||
* `.up()` is the terminal call: it commits the step to its parent SmartMigration
|
||||
* and returns that parent so further `.step(...)` calls can chain naturally.
|
||||
*/
|
||||
export class MigrationStepBuilder {
|
||||
private parent: SmartMigration;
|
||||
private id: string;
|
||||
private _from: string | null = null;
|
||||
private _to: string | null = null;
|
||||
private _description: string | undefined;
|
||||
private _resumable = false;
|
||||
|
||||
constructor(parent: SmartMigration, id: string) {
|
||||
this.parent = parent;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/** REQUIRED: the data version this step starts from. */
|
||||
public from(version: string): this {
|
||||
this._from = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** REQUIRED: the data version this step ends at. */
|
||||
public to(version: string): this {
|
||||
this._to = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Optional human-readable description. */
|
||||
public description(text: string): this {
|
||||
this._description = text;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the step as resumable. When set, the step's `up` handler receives a
|
||||
* `ctx.checkpoint` object that persists arbitrary key/value state to the
|
||||
* ledger between runs.
|
||||
*/
|
||||
public resumable(): this {
|
||||
this._resumable = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminal: register the step on the parent SmartMigration and return the
|
||||
* parent so that further steps can be chained.
|
||||
*/
|
||||
public up(handler: (ctx: IMigrationContext) => Promise<void>): SmartMigration {
|
||||
if (this._from === null) {
|
||||
throw new SmartMigrationError(
|
||||
'STEP_MISSING_FROM',
|
||||
`Migration step "${this.id}" is missing .from(version) before .up().`,
|
||||
{ stepId: this.id },
|
||||
);
|
||||
}
|
||||
if (this._to === null) {
|
||||
throw new SmartMigrationError(
|
||||
'STEP_MISSING_TO',
|
||||
`Migration step "${this.id}" is missing .to(version) before .up().`,
|
||||
{ stepId: this.id },
|
||||
);
|
||||
}
|
||||
if (typeof handler !== 'function') {
|
||||
throw new SmartMigrationError(
|
||||
'STEP_HANDLER_NOT_FUNCTION',
|
||||
`Migration step "${this.id}" was passed a non-function to .up().`,
|
||||
{ stepId: this.id },
|
||||
);
|
||||
}
|
||||
|
||||
const definition: IMigrationStepDefinition = {
|
||||
id: this.id,
|
||||
fromVersion: this._from,
|
||||
toVersion: this._to,
|
||||
description: this._description,
|
||||
isResumable: this._resumable,
|
||||
handler,
|
||||
};
|
||||
|
||||
this.parent.registerStep(definition);
|
||||
return this.parent;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user