Files
smartmigration/ts/classes.migrationstep.ts

96 lines
2.7 KiB
TypeScript
Raw Normal View History

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;
}
}