From fb8b9d1e440585aec7220c1153829323191f75b5 Mon Sep 17 00:00:00 2001 From: Allen Foster Date: Tue, 8 Sep 2026 14:59:43 -0400 Subject: [PATCH] Fix 0762b3c7694d datetime migration on non-empty tables Two bugs in the row-conversion loops (unix_to_datetime/datetime_to_unix) that only manifest once a table has at least one row, so an empty-database migration test never exercises them: - row[column_name] used string-key indexing on a SQLAlchemy Core Row, which SQLAlchemy 2.0 no longer supports (positional-only); switch to row._mapping[column_name]. - cur_table was reflected once before the per-column temp_* column was added via op.add_column, so the later cur_table.update().values({...}) didn't recognize that column ("Unconsumed column names"); re-reflect cur_table after each op.add_column. Verified against a database with existing rows: reproduces both failures on the original code and succeeds after the fix. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01Rh1TMcQhLGM8TyQZ947Rvt --- .../versions/0762b3c7694d_swapping_to_datetime.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/mapcat/alembic/versions/0762b3c7694d_swapping_to_datetime.py b/mapcat/alembic/versions/0762b3c7694d_swapping_to_datetime.py index 4bf3ab8..48d10e4 100644 --- a/mapcat/alembic/versions/0762b3c7694d_swapping_to_datetime.py +++ b/mapcat/alembic/versions/0762b3c7694d_swapping_to_datetime.py @@ -68,12 +68,15 @@ def unix_to_datetime( op.add_column( table_name, sa.Column(temp_col_name, sa.DateTime(), nullable=True) ) + # Re-reflect: the table was just reflected before the temp column + # existed, so cur_table.c wouldn't otherwise know about it. + cur_table = sa.Table(table_name, sa.MetaData(), autoload_with=bind) stmt = sa.select(cur_table.c[column_name], cur_table.c[primary_key_name]) results = bind.execute(stmt).fetchall() for row in results: - unix_time = row[column_name] - primary_key_value = row[primary_key_name] + unix_time = row._mapping[column_name] + primary_key_value = row._mapping[primary_key_name] datetime_value = datetime.fromtimestamp(int(unix_time), tz=timezone.utc) update_stmt = ( cur_table.update() @@ -125,12 +128,15 @@ def datetime_to_unix( op.drop_index(f"ix_{table_name}_{column_name}", table_name=table_name) op.add_column(table_name, sa.Column(temp_col_name, sa.String(), nullable=True)) + # Re-reflect: the table was just reflected before the temp column + # existed, so cur_table.c wouldn't otherwise know about it. + cur_table = sa.Table(table_name, sa.MetaData(), autoload_with=bind) stmt = sa.select(cur_table.c[column_name], cur_table.c[primary_key_name]) results = bind.execute(stmt).fetchall() for row in results: - datetime_value = row[column_name] - primary_key_value = row[primary_key_name] + datetime_value = row._mapping[column_name] + primary_key_value = row._mapping[primary_key_name] unix_time = _datetime_to_unix_value(datetime_value) update_stmt = ( cur_table.update()