migrateToSchema method

SqliteMigrationResult migrateToSchema({
  1. required Database database,
  2. required SchemaDocument target,
  3. required String migrationName,
  4. bool allowWarnings = false,
})

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

Implementation

SqliteMigrationResult migrateToSchema({
  required sqlite.Database database,
  required SchemaDocument target,
  required String migrationName,
  bool allowWarnings = false,
}) {
  ensureHistoryTable(database);
  final appliedNames = _activeMigrationNames(loadHistory(database));

  if (appliedNames.contains(migrationName)) {
    return SqliteMigrationResult(
      plan: const SqliteMigrationPlan(
        statements: <String>[],
        warnings: <String>[],
      ),
      applied: false,
    );
  }

  final filteredFrom = _currentSourceSchema(database);
  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(' | ')}',
    );
  }

  if (!plan.requiresRebuild && plan.statements.isEmpty) {
    _recordHistory(
      database: database,
      migrationName: migrationName,
      statementCount: 0,
      kind: SqliteMigrationRecordKind.apply,
      provider: providerName,
      checksum: checksum,
      beforeSchema: beforeSchema,
      afterSchema: afterSchema,
      warnings: plan.warnings,
      rebuildRequired: plan.requiresRebuild,
    );
    return SqliteMigrationResult(plan: plan, applied: false);
  }

  if (plan.requiresRebuild) {
    final statementCount = _rebuildDatabase(
      database: database,
      source: filteredFrom,
      target: target,
    );
    _recordHistory(
      database: database,
      migrationName: migrationName,
      statementCount: statementCount,
      kind: SqliteMigrationRecordKind.apply,
      provider: providerName,
      checksum: checksum,
      beforeSchema: beforeSchema,
      afterSchema: afterSchema,
      warnings: plan.warnings,
      rebuildRequired: true,
    );
    return SqliteMigrationResult(plan: plan, applied: true);
  }

  database.execute('BEGIN');
  try {
    for (final statement in plan.statements) {
      database.execute(statement);
    }
    _recordHistory(
      database: database,
      migrationName: migrationName,
      statementCount: plan.statements.length,
      kind: SqliteMigrationRecordKind.apply,
      provider: providerName,
      checksum: checksum,
      beforeSchema: beforeSchema,
      afterSchema: afterSchema,
      warnings: plan.warnings,
      rebuildRequired: false,
    );
    database.execute('COMMIT');
    return SqliteMigrationResult(plan: plan, applied: true);
  } catch (_) {
    database.execute('ROLLBACK');
    rethrow;
  }
}