angel3_migration_runner 10.0.1
angel3_migration_runner: ^10.0.1 copied to clipboard
The implementation of database migration for Angel3 framework. Designed to work with Angel3 ORM.
Angel3 Migration Runner #
This package contains the implementation of the database migration for the following databases. It is designed to work with Angel3 ORM.
- PostgreSQL 14.x or greater
- MariaDB 10.2.x or greater
- MySQL 8.x or greater
Installation #
In your pubspec.yaml:
dependencies:
angel3_migration_runner: ^10.0.0
Usage #
- Use
PostgresMigrationRunnerto perform database migration for PostgreSQL. - Use
MySqlMigrationRunnerto perform database migration for MySQL. This runner is usingmysql_dartdriver. - Use
MariaDbMigrationRunnerto perform database migration for MariaDB. This runner is usingmysql_dartdriver.
Run the migrations from a command-line program, such as bin/migrate.dart, with runMigrations:
import 'package:angel3_migration_runner/angel3_migration_runner.dart';
import 'package:angel3_migration_runner/postgres.dart';
import 'package:postgres/postgres.dart';
import 'todo.dart';
void main(List<String> args) async {
var connection = await Connection.open(
Endpoint(
host: 'localhost',
database: 'demo',
username: 'demouser',
password: 'demo123',
),
settings: ConnectionSettings(sslMode: SslMode.disable),
);
var runner = PostgresMigrationRunner(
connection,
migrations: [UserMigration(), TodoMigration()],
);
// `dart bin/migrate.dart up`, `rollback`, `reset` or `refresh`
await runMigrations(runner, args);
}
See example/main.dart for MySQL too.
Supported Operations #
- up - Run the migrations not recorded in the
migrationstable yet, in a new batch, to generate the tables based on the ORM models. A migration that fails throws, and none after it is run, as they may depend on it. - rollback - Undo the migrations of the last batch, newest first.
- reset - Undo every migration, newest first, and clear out its records in the
migrationstable, which drops all the ORM related tables. - refresh - Run
resetfollowed byup.
runMigrations(runner, args) runs these as the commands of a command-line program, and closes the runner, even when a migration fails.
Migration Names #
Each migration is recorded in the migrations table by its Migration.name, which defaults to the name of its class. Override name to keep it stable:
- when the class is renamed, or two migration classes in different files have the same name, and
- when the program is compiled with
--obfuscate, which renames classes.
A migration recorded under another name is run again.
class CreateUsersMigration extends Migration {
@override
String get name => 'create_users';
...
}
Upgrading from 9.x #
Versions before 10.0.0 recorded a migration as <absolute source file>#<class name>. On its first run, the runner renames such a row to the migration's name when the row's class name belongs to exactly one row and one migration. Otherwise, as when two migrations share a class name, or the project was moved and the migration was recorded at both paths, it throws a StateError rather than guess. For those, give the migration a legacyPath, the end of the path it was recorded by:
@override
String get legacyPath => 'lib/src/migrations/users.dart#UserMigration';
Or set each path of the migrations table to the name of its migration by hand.
Transactions #
On PostgreSQL, each migration runs, and is recorded in the migrations table, in one transaction, so a migration that fails or is cut off is neither applied nor recorded.
MySQL and MariaDB commit each change of a table on its own, so a migration is recorded once it has run. If the connection is lost between the two, the migration's changes stay without its row in the migrations table, and the next up runs it again. Insert its row by hand in that case:
INSERT INTO migrations (batch, path) VALUES (<batch>, '<name>');
Limitation #
- Update schema changes is not supported
Migrating from 10.0.0 to 10.0.1 #
- MySQL and MariaDB: the runners use
mysql_dart4, which verifies the server's TLS certificate whensecureistrue(its default).connect()fails with aHandshakeExceptionif the certificate does not chain to a trusted root and name the host:- A server in Docker or on the same host, with the self-signed certificate MySQL and MariaDB generate: pass
verifyServerCertificate: falsetoMySQLConnection.createConnection. The traffic is still encrypted. - A server with a certificate from your own CA: keep verifying, and trust the CA with
securityContext: SecurityContext(withTrustedRoots: true)..setTrustedCertificates('ca.pem'). - A server with a certificate from a public CA, naming the host you connect to: nothing to change.
- A server in Docker or on the same host, with the self-signed certificate MySQL and MariaDB generate: pass
Migrating from 9.x to 10.0.0 #
The breaking changes of each release are listed in the CHANGELOG. Those of 10.0.0 that may need changes in an app:
- Migration names: a migration is recorded by its
Migration.name, where it was its source path and class name. Rows recorded by 9.x are renamed on the first run; see Upgrading from 9.x. - MySQL and MariaDB:
MySqlMigrationRunner,MariaDbMigrationRunnerandMariaDbSchema.runusemysql_dart, instead ofmysql_clientandmysql1. Pass itsMySQLConnection, and importpackage:mysql_dart/mysql_dart.dart. - Failures:
upof every runner throws when a migration fails, and runs none after it, where the PostgreSQL and MariaDB runners only logged it.MySqlSchema.runthrows when its SQL fails. - Duplicate names: two migrations of the same name throw a
StateError, including two of one class that takes arguments; give each its ownname. - String defaults are quoted and escaped alike on every database: give
defaultsTo('active'), not"'active'", and SQL asRawSql, e.g.defaultsTo(RawSql('CURRENT_TIMESTAMP')). numericanddecimalcolumns are created with their precision and scale, where MySQL and MariaDB rounded values to whole numbers. Without them they arenumeric(17, 3)on MySQL and MariaDB, and unbounded on PostgreSQL.changeColumnTypetakes theprecision,scaleandlengthof the new type (default length 255), the constraints after the change, andusingon PostgreSQL.- Table names are quoted per part:
`shop`.`orders`on MySQL and MariaDB,"audit"."events"on PostgreSQL. A PostgreSQL table with a.in its own name must be given in double quotes.