@@ -61,12 +61,11 @@ def _pk_columns(model: type) -> list[str]:
6161 return [col .name for col in inspect (model ).mapper .primary_key ]
6262
6363
64- def migrate_table (src : Session , dst : Session , model : type ) -> tuple [int , int ]:
64+ def migrate_table (src : Session , dst : Session , model : type ) -> tuple [int , int , int ]:
6565 """Copy rows from src to dst for the given model.
6666
67- Returns (inserted, skipped) counts.
67+ Returns (inserted, skipped, orphaned ) counts.
6868 """
69- table_name = model .__tablename__
7069 cols = _columns (model )
7170 pk_cols = _pk_columns (model )
7271
@@ -91,12 +90,15 @@ def migrate_table(src: Session, dst: Session, model: type) -> tuple[int, int]:
9190 # Build a fresh detached copy so we don't accidentally modify the
9291 # source session's identity map.
9392 new_obj = model (** {col : getattr (row , col ) for col in cols })
94- dst .add (new_obj )
9593 try :
96- dst .flush ()
94+ # Use a SAVEPOINT so that a FK violation rolls back only this one
95+ # row — not the entire transaction (which would destroy all parent
96+ # rows flushed in earlier loop iterations or earlier tables).
97+ with dst .begin_nested ():
98+ dst .add (new_obj )
99+ dst .flush ()
97100 inserted += 1
98101 except IntegrityError :
99- dst .rollback ()
100102 orphaned += 1
101103
102104 return inserted , skipped , orphaned
@@ -173,15 +175,15 @@ def main() -> int:
173175 print (f" { table_name :<20} — { summary } " )
174176 total_inserted += inserted
175177 total_skipped += skipped + orphaned
178+ # Commit after every table so parent rows are durable before
179+ # child tables run their FK-constrained inserts.
180+ dst_session .commit ()
176181 except Exception as exc :
177182 dst_session .rollback ()
178183 print (f" { table_name :<20} — ERROR: { exc } " , file = sys .stderr )
179- print ("Rolling back entire transaction ." , file = sys .stderr )
184+ print ("Rolling back this table's changes ." , file = sys .stderr )
180185 return 1
181186
182- if not args .dry_run :
183- dst_session .commit ()
184-
185187 print (f"\n Done. Inserted { total_inserted } rows, skipped { total_skipped } duplicates." )
186188 return 0
187189
0 commit comments