draftMigration function
Future<void>
draftMigration({
- SchemaSnapshot? before,
- required SchemaSnapshot after,
- required int version,
- required String name,
- required String outputPath,
Saves a conservative schema change as a standalone Dart migration draft.
Review the saved SQL and fingerprint, then register it with a static import.
before must be the previous saved schema, never a reconstructed live model.
Omit it for the initial migration. Existing files are never overwritten.
Destructive or unsupported changes fail before any output is created.
Drafts support literal string, integer, real and boolean defaults.
Implementation
Future<void> draftMigration({
SchemaSnapshot? before,
required SchemaSnapshot after,
required int version,
required String name,
required String outputPath,
}) async {
if (!outputPath.endsWith('.dart')) {
throw const FormatException('Migration output must be a Dart file.');
}
final plan = planSchemaChange(
before ?? SchemaSnapshot(engine: after.engine, tables: const []),
after,
);
if (plan.steps.isEmpty) {
throw StateError('The schema has no storage changes to draft.');
}
for (final table in plan.snapshot.tables) {
for (final column in table.columns) {
final value = column.defaultValue;
if (value != null &&
value is! String &&
value is! num &&
value is! bool) {
throw FormatException(
'${table.name}.${column.name}: draft defaults must be scalar literals.',
);
}
}
}
final fingerprint = migrationFingerprint(
version: version,
name: name,
engine: plan.engine,
steps: plan.steps,
snapshot: plan.snapshot,
);
// Use the same validation as a saved definition before creating its file.
Migration(
version: version,
name: name,
engine: plan.engine,
steps: plan.steps,
snapshot: plan.snapshot,
reviewedFingerprint: fingerprint,
);
final source =
DartFormatter(languageVersion: DartFormatter.latestLanguageVersion)
.format('''
// Migration draft: review every SQL statement before committing this file.
// After application, preserve this history and add a new migration for changes.
import 'package:orm/database.dart';
import 'package:orm/migration.dart';
import 'package:orm/schema.dart';
const frozenSchema = SchemaSnapshot(
engine: Engine.${plan.engine.name},
tables: [${plan.snapshot.tables.map(emitTableDefinition).join(',')}],
);
final migration = Migration(
version: $version,
name: ${dartLiteral(name)},
engine: Engine.${plan.engine.name},
steps: [${plan.steps.map(dartLiteral).join(',')}],
snapshot: frozenSchema,
reviewedFingerprint: ${dartLiteral(fingerprint)},
);
''');
final output = File(p.normalize(p.absolute(outputPath)));
await output.parent.create(recursive: true);
await output.create(exclusive: true);
try {
await output.writeAsString(source, flush: true);
} catch (_) {
await output.delete();
rethrow;
}
}