Skip to content

Migration rename detection creates a rename cycle when explicit column names match other field names #5915

Open

Description

@vchrisb

Describe the bug

Migration rename detection produces a bogus rename cycle when the live database schema is compared with the target definition, if a model maps one field to a column whose name is another field's name.

generateTableMigration (tools/serverpod_cli/lib/src/database/migration.dart) matches source and target columns by effectiveFieldName, which falls back to the column name when fieldName is null:

String get effectiveFieldName => fieldName ?? name;

A schema read from a live database never has field names, so each live column is matched to the field that has the same name as the column, not the field actually stored in it. Take a model with swapped column names:

first: String, column=second
second: String, column=first
  • live column second is treated as field second → target column first
  • live column first is treated as field first → target column second

This produces a rename cycle (first → second, second → first) for a table that is already in sync. The generated SQL can't run either, because each target name still exists when its rename runs.

The migrations themselves are fine (each is a plain CREATE TABLE). The bug only appears when the live schema is compared against the target definition.

This came up while adding a regression test in #5913. The test was removed from that PR so this can be handled separately.

To reproduce

  1. Create a model with fields mapped to each other's column names:

    class: TableWithSwappedColumnNames
    table: table_with_swapped_column_names
    fields:
      first: String, column=second
      second: String, column=first
      changed: bool
  2. Run serverpod create-migration and apply it. The table is created correctly.

  3. Compare the live database schema with the target definition. This happens in any code path that analyzes the live database and diffs it against the target, such as the schema check or a repair migration.

  4. The diff reports two renames (first → second, second → first) instead of "in sync". If you apply the generated SQL, it fails because the target column names already exist.

Expected behavior

  • A live table whose columns already match the target definition is reported as in sync, with no renames.
  • A possible fix: if the source column has no stored fieldName and the target still has a column with the same name, treat it as the same column, not a rename.

Library version

Serverpod 4.1.0-rc.1

Platform information

Server: Dart 3.13.7 (Windows x64), PostgreSQL (Serverpod embedded)

Additional context

No response

How experienced are you with this library?

None

Are you interested in working on a PR for this?

  • I want to work on this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions