rollback method
Rolls back the most recently applied migrations.
Implementation
Future<MigrationReport> rollback({int steps = 1}) async {
if (steps < 1) {
throw ArgumentError.value(steps, 'steps', 'Must be >= 1');
}
final schema = _defaultSchema;
if (schema != null) {
await _schemaDriver.setCurrentSchema(schema);
}
await _ledger.ensureInitialized();
final applied = await _ledger.readApplied();
if (applied.isEmpty) {
return const MigrationReport([]);
}
final targets = applied.reversed.take(steps).toList();
// Emit batch started
final batchStopwatch = Stopwatch()..start();
if (_emitEvents) {
_events.emit(
MigrationBatchStartedEvent(
direction: MigrationDirection.down,
count: targets.length,
batch: null,
),
);
}
final actions = <MigrationAction>[];
for (var i = 0; i < targets.length; i++) {
final record = targets[i];
final descriptor = _descriptorById[record.id.toString()];
if (descriptor == null) {
throw StateError(
'No migration descriptor registered for ${record.id}.',
);
}
final migrationId = descriptor.id.toString();
final migrationName = descriptor.id.slug;
// Emit migration started
if (_emitEvents) {
_events.emit(
MigrationStartedEvent(
migrationId: migrationId,
migrationName: migrationName,
direction: MigrationDirection.down,
index: i + 1,
total: targets.length,
),
);
}
final stopwatch = Stopwatch()..start();
try {
final plan = await _planResolver(descriptor, MigrationDirection.down);
await _schemaDriver.applySchemaPlan(plan);
stopwatch.stop();
await _ledger.remove(record.id);
// Emit migration completed
if (_emitEvents) {
_events.emit(
MigrationCompletedEvent(
migrationId: migrationId,
migrationName: migrationName,
direction: MigrationDirection.down,
duration: stopwatch.elapsed,
),
);
}
actions.add(
MigrationAction(
descriptor: descriptor,
operation: MigrationOperation.rollback,
appliedAt: DateTime.now().toUtc(),
duration: stopwatch.elapsed,
),
);
} catch (error, stackTrace) {
stopwatch.stop();
// Emit migration failed
if (_emitEvents) {
_events.emit(
MigrationFailedEvent(
migrationId: migrationId,
migrationName: migrationName,
direction: MigrationDirection.down,
error: error,
stackTrace: stackTrace,
),
);
}
rethrow;
}
}
batchStopwatch.stop();
if (_emitEvents) {
_events.emit(
MigrationBatchCompletedEvent(
direction: MigrationDirection.down,
count: actions.length,
duration: batchStopwatch.elapsed,
),
);
}
return MigrationReport(actions);
}