generateDatabaseMigration function

DatabaseMigration generateDatabaseMigration({
  1. required DatabaseDefinition databaseSource,
  2. required DatabaseDefinition databaseTarget,
})

Implementation

DatabaseMigration generateDatabaseMigration({
  required DatabaseDefinition databaseSource,
  required DatabaseDefinition databaseTarget,
}) {
  var warnings = <DatabaseMigrationWarning>[];
  var actions = <DatabaseMigrationAction>[];

  var sourceTables =
      databaseSource.tables.where((table) => table.isManaged).toList();
  var targetTables =
      databaseTarget.tables.where((table) => table.isManaged).toList();
  var deleteTables = <String>{};

  // Mark tables which do not exist in the target schema anymore for deletion
  for (var srcTable in sourceTables) {
    if (!databaseTarget.containsTableNamed(srcTable.name)) {
      deleteTables.addAll([
        srcTable.name,
        // For any table we delete, we also need to delete any other existing table that has and retains a foreign key pointing into this table
        ..._findDependentTables(srcTable.name,
            sourceTables: sourceTables, targetTables: targetTables),
      ]);
    }
  }

  for (var tableName in deleteTables.toList().reversed) {
    actions.add(
      DatabaseMigrationAction(
        type: DatabaseMigrationActionType.deleteTable,
        deleteTable: tableName,
      ),
    );
    warnings.add(
      DatabaseMigrationWarning(
        type: DatabaseMigrationWarningType.tableDropped,
        message: 'Table "$tableName" will be dropped.',
        table: tableName,
        destrucive: true,
        columns: [],
      ),
    );
  }

  // Find added or modified tables
  for (var dstTable in targetTables) {
    var srcTable = databaseSource.tables.cast<TableDefinition?>().firstWhere(
        (table) => table?.name == dstTable.name,
        orElse: () => null);

    if (srcTable == null ||
        srcTable.managed == false ||
        deleteTables.contains(srcTable.name)) {
      // Added table
      actions.add(
        DatabaseMigrationAction(
          type: srcTable == null || deleteTables.contains(srcTable.name)
              ? DatabaseMigrationActionType.createTable
              : DatabaseMigrationActionType.createTableIfNotExists,
          createTable: dstTable,
        ),
      );
    } else {
      // Table exists in src and dst
      var diff = generateTableMigration(srcTable, dstTable, warnings);
      if (diff == null) {
        // Table was modified, but cannot be migrated. Recreate the table.
        actions.add(
          DatabaseMigrationAction(
            type: DatabaseMigrationActionType.deleteTable,
            deleteTable: dstTable.name,
          ),
        );
        actions.add(
          DatabaseMigrationAction(
            type: DatabaseMigrationActionType.createTable,
            createTable: dstTable,
          ),
        );
      } else if (!diff.isEmpty) {
        // Table was modified
        // TODO: Check if table can be modified

        actions.add(
          DatabaseMigrationAction(
            type: DatabaseMigrationActionType.alterTable,
            alterTable: diff,
          ),
        );
      }
    }
  }

  return DatabaseMigration(
    actions: actions,
    warnings: warnings,
    migrationApiVersion: DatabaseConstants.migrationApiVersion,
  );
}