apply method

Future<List<String>> apply(
  1. List<Migration> migrations, {
  2. int? maxBackfillBatches,
})

Applies pending migrations, returning the IDs completed by this call. SQLite/PostgreSQL batches of transactional steps are atomic. CheckedSql and Backfill opt their containing migration into durable per-step recovery. MySQL/MariaDB DDL uses checked, recoverable steps because the database can commit schema changes implicitly.

maxBackfillBatches bounds nonempty data batches across this invocation. Reaching the limit returns normally with unfinished migrations still pending; completion verification can require a subsequent call.

Implementation

Future<List<String>> apply(
  List<Migration> migrations, {
  int? maxBackfillBatches,
}) async {
  if (maxBackfillBatches != null && maxBackfillBatches < 1) {
    throw ArgumentError.value(maxBackfillBatches, 'maxBackfillBatches');
  }
  migrations = List.unmodifiable(migrations);
  if (database.inTransaction) {
    throw const OrmException(
      'MIGRATION.SESSION',
      'Migrations require a dedicated outer transaction.',
    );
  }
  validateMigrations(migrations, dialect: database.dialect);
  Future<List<String>> run(SqlDatabase<Backend> session) async {
    if (isMysqlFamily(session.dialect)) {
      return applyRecoverableMysql(
        session,
        migrations,
        BackfillBudget(maxBackfillBatches),
      );
    }
    if (migrations.any(
      (m) => m.steps.any((s) => s is CheckedSql || s is Backfill),
    )) {
      return session.dialect == SqlDialect.sqlite
          ? applyRecoverableSqlite(
              session,
              migrations,
              BackfillBudget(maxBackfillBatches),
            )
          : applyRecoverable(
              session,
              migrations,
              BackfillBudget(maxBackfillBatches),
            );
    }
    return migrationTransaction(session, (tx) async {
      await tx.execute(SqlCommand(historyDdl));
      final pending = await Migrator(tx).plan(migrations);
      for (final migration in pending) {
        for (final step in migration.steps) {
          await executeStep(tx, step);
        }
        await recordMigration(tx, migration);
      }
      return [for (final migration in pending) migration.id];
    }, rebuild: needsRebuild(migrations, session.dialect));
  }

  return migrationSession(database, lockTimeout, run);
}