@@ -278,6 +278,36 @@ async fn run_migrations(pool: &DbPool, database_url: &str, approval: Option<&str
278278mod tests {
279279 use super :: require_migration_approval;
280280
281+ #[ cfg( feature = "sqlite" ) ]
282+ #[ derive( diesel:: QueryableByName ) ]
283+ struct RowCount {
284+ #[ diesel( sql_type = diesel:: sql_types:: BigInt ) ]
285+ count : i64 ,
286+ }
287+
288+ #[ cfg( feature = "sqlite" ) ]
289+ fn table_count ( conn : & mut diesel:: SqliteConnection , table : & str ) -> i64 {
290+ use diesel:: RunQueryDsl ;
291+
292+ diesel:: sql_query ( format ! ( "SELECT COUNT(*) AS count FROM {table}" ) )
293+ . get_result :: < RowCount > ( conn)
294+ . unwrap ( )
295+ . count
296+ }
297+
298+ #[ cfg( feature = "sqlite" ) ]
299+ fn foreign_keys_enabled ( conn : & mut diesel:: SqliteConnection ) -> bool {
300+ use diesel:: RunQueryDsl ;
301+
302+ diesel:: sql_query (
303+ "SELECT COUNT(*) AS count FROM pragma_foreign_keys WHERE foreign_keys = 1" ,
304+ )
305+ . get_result :: < RowCount > ( conn)
306+ . unwrap ( )
307+ . count
308+ == 1
309+ }
310+
281311 #[ test]
282312 fn fresh_database_does_not_require_approval ( ) {
283313 assert ! ( require_migration_approval( false , & [ "20260721" . to_owned( ) ] , None ) . is_ok( ) ) ;
@@ -290,4 +320,48 @@ mod tests {
290320 assert ! ( require_migration_approval( true , & pending, Some ( "20260721" ) ) . is_err( ) ) ;
291321 assert ! ( require_migration_approval( true , & pending, Some ( "20260721,20260722" ) ) . is_ok( ) ) ;
292322 }
323+
324+ #[ cfg( feature = "sqlite" ) ]
325+ #[ test]
326+ fn channel_migration_preserves_referencing_rows ( ) {
327+ use diesel:: Connection ;
328+ use diesel:: connection:: SimpleConnection ;
329+ use diesel_migrations:: MigrationHarness ;
330+
331+ let mut conn = diesel:: SqliteConnection :: establish ( ":memory:" ) . unwrap ( ) ;
332+ conn. batch_execute ( "PRAGMA foreign_keys = ON;" ) . unwrap ( ) ;
333+
334+ let migrations = conn. pending_migrations ( super :: MIGRATIONS ) . unwrap ( ) ;
335+ let channel_migration = migrations
336+ . iter ( )
337+ . position ( |migration| migration. name ( ) . version ( ) . to_string ( ) == "202608181323460000" )
338+ . expect ( "channel migration must be embedded" ) ;
339+
340+ conn. run_migrations ( & migrations[ ..channel_migration] )
341+ . unwrap ( ) ;
342+ conn. batch_execute (
343+ "INSERT INTO channel (id, name, avatar, verified) \
344+ VALUES ('channel-1', 'Channel', 'https://example.test/avatar', false); \
345+ INSERT INTO video (id, title, upload_date, uploader_id, thumbnail_url, duration) \
346+ VALUES ('video-1', 'Video', 0, 'channel-1', \
347+ 'https://example.test/thumbnail', 60);",
348+ )
349+ . unwrap ( ) ;
350+
351+ assert_eq ! ( table_count( & mut conn, "video" ) , 1 ) ;
352+ conn. run_migration ( migrations[ channel_migration] . as_ref ( ) )
353+ . unwrap ( ) ;
354+ assert ! ( foreign_keys_enabled( & mut conn) ) ;
355+ assert_eq ! ( table_count( & mut conn, "channel" ) , 1 ) ;
356+ assert_eq ! ( table_count( & mut conn, "video" ) , 1 ) ;
357+
358+ conn. batch_execute ( "UPDATE channel SET avatar = NULL;" )
359+ . unwrap ( ) ;
360+ conn. revert_migration ( migrations[ channel_migration] . as_ref ( ) )
361+ . unwrap ( ) ;
362+ assert ! ( foreign_keys_enabled( & mut conn) ) ;
363+ assert_eq ! ( table_count( & mut conn, "channel" ) , 1 ) ;
364+ assert_eq ! ( table_count( & mut conn, "video" ) , 1 ) ;
365+ assert_eq ! ( table_count( & mut conn, "pragma_foreign_key_check" ) , 0 ) ;
366+ }
293367}
0 commit comments