migrateToSchema method

Future<PostgresqlMigrationResult> migrateToSchema({
  1. required SessionExecutor executor,
  2. required SchemaDocument target,
  3. required String migrationName,
  4. bool allowWarnings = false,
})

Applies the schema diff to target and writes a history record.

Implementation

Future<PostgresqlMigrationResult> migrateToSchema({
  required pg.SessionExecutor executor,
  required SchemaDocument target,
  required String migrationName,
  bool allowWarnings = false,
}) async {
  await ensureHistoryTable(executor);
  final appliedNames = _activeMigrationNames(await loadHistory(executor));
  if (appliedNames.contains(migrationName)) {
    return PostgresqlMigrationResult(
      plan: const PostgresqlMigrationPlan(
        statements: <String>[],
        warnings: <String>[],
      ),
      applied: false,
    );
  }

  final filteredFrom = filterSchemaForUserModels(
    await planner.schemaIntrospector.introspect(executor),
    historyTableName: historyTableName,
  );
  final plan = _mergeRiskWarnings(
    planner.plan(from: filteredFrom, to: target),
    detectPotentialDataLossWarnings(from: filteredFrom, to: target),
  );
  final beforeSchema = schemaToSource(filteredFrom);
  final afterSchema = schemaToSource(target);
  final migrationSql = buildMigrationSqlScript(plan);
  final checksum = computeMigrationChecksum(
    provider: providerName,
    beforeSchema: beforeSchema,
    afterSchema: afterSchema,
    migrationSql: migrationSql,
    warnings: plan.warnings,
    requiresRebuild: plan.requiresRebuild,
  );
  if (plan.warnings.isNotEmpty && !allowWarnings) {
    throw StateError(
      'Migration plan contains warnings: ${plan.warnings.join(' | ')}',
    );
  }

  await executor.runTx((session) async {
    if (plan.requiresRebuild) {
      await _rebuildDatabase(
        session: session,
        source: filteredFrom,
        target: target,
      );
    } else {
      for (final statement in plan.statements) {
        await session.execute(statement, ignoreRows: true);
      }
    }
    await _recordHistory(
      session,
      migrationName: migrationName,
      statementCount: plan.requiresRebuild
          ? target.models.length
          : plan.statements.length,
      kind: PostgresqlMigrationRecordKind.apply,
      provider: providerName,
      checksum: checksum,
      beforeSchema: beforeSchema,
      afterSchema: afterSchema,
      warnings: plan.warnings,
      rebuildRequired: plan.requiresRebuild,
    );
  });

  return PostgresqlMigrationResult(
    plan: plan,
    applied: plan.requiresRebuild || plan.statements.isNotEmpty,
  );
}