@@ -84,6 +84,7 @@ def _get_create_table_sql(self) -> CreateTable:
8484 .column ("execution_time_ms" , "INTEGER" )
8585 .column ("checksum" , "VARCHAR(64)" )
8686 .column ("applied_by" , "VARCHAR(255)" )
87+ .column ("replaces" , "TEXT" )
8788 )
8889
8990 def _get_current_version_sql (self ) -> Select :
@@ -189,6 +190,70 @@ def _get_update_version_sql(self, old_version: str, new_version: str, new_versio
189190 .where (sql .version_num == old_version )
190191 )
191192
193+ def _get_delete_versions_sql (self , versions : "list[str]" ) -> Delete :
194+ """Get SQL builder for deleting multiple version records.
195+
196+ Used by squash operations to remove replaced migration records.
197+
198+ Args:
199+ versions: List of version strings to delete.
200+
201+ Returns:
202+ SQL builder object for delete.
203+ """
204+ return sql .delete ().from_ (self .version_table ).where (sql .version_num .in_ (versions ))
205+
206+ def _get_record_squashed_migration_sql (
207+ self ,
208+ version : str ,
209+ version_type : str ,
210+ execution_sequence : int ,
211+ description : str ,
212+ execution_time_ms : int ,
213+ checksum : str ,
214+ applied_by : str ,
215+ replaces : str ,
216+ ) -> Insert :
217+ """Get SQL builder for recording a squashed migration.
218+
219+ Args:
220+ version: Version number of the squashed migration.
221+ version_type: Version format type ('sequential' or 'timestamp').
222+ execution_sequence: Auto-incrementing application order.
223+ description: Description of the migration.
224+ execution_time_ms: Execution time in milliseconds.
225+ checksum: MD5 checksum of the migration content.
226+ applied_by: User who applied the migration.
227+ replaces: Comma-separated list of replaced versions.
228+
229+ Returns:
230+ SQL builder object for insert.
231+ """
232+ return (
233+ sql
234+ .insert (self .version_table )
235+ .columns (
236+ "version_num" ,
237+ "version_type" ,
238+ "execution_sequence" ,
239+ "description" ,
240+ "execution_time_ms" ,
241+ "checksum" ,
242+ "applied_by" ,
243+ "replaces" ,
244+ )
245+ .values (
246+ version ,
247+ version_type ,
248+ execution_sequence ,
249+ description ,
250+ execution_time_ms ,
251+ checksum ,
252+ applied_by ,
253+ replaces ,
254+ )
255+ )
256+
192257 def _get_check_column_exists_sql (self ) -> Select :
193258 """Get SQL to check what columns exist in the tracking table.
194259
@@ -324,7 +389,7 @@ def _extract_version(self, filename: str) -> str | None:
324389 parts = stem .split ("_" , 1 )
325390 return parts [0 ].zfill (4 ) if parts and parts [0 ].isdigit () else None
326391
327- def _calculate_checksum (self , content : str ) -> str :
392+ def calculate_checksum (self , content : str ) -> str :
328393 """Calculate MD5 checksum of migration content.
329394
330395 Args:
@@ -403,7 +468,7 @@ def _load_migration_metadata(self, file_path: Path, version: "str | None" = None
403468 loader = get_migration_loader (file_path , self .migrations_path , self .project_root , context_to_use )
404469 loader .validate_migration_file (file_path )
405470 content = file_path .read_text (encoding = "utf-8" )
406- checksum = self ._calculate_checksum (content )
471+ checksum = self .calculate_checksum (content )
407472 description = self ._extract_description (content , file_path )
408473 if not description :
409474 description = file_path .stem .split ("_" , 1 )[1 ] if "_" in file_path .stem else ""
0 commit comments