Skip to main content

flix_db/entity/
mod.rs

1//! Entity structs for interacting with the database.
2
3#![expect(clippy::exhaustive_enums, reason = "reflects the database schema")]
4#![expect(clippy::exhaustive_structs, reason = "reflects the database schema")]
5#![expect(clippy::derive_partial_eq_without_eq, reason = "#[sea_orm::model]")]
6#![expect(clippy::impl_trait_in_params, reason = "#[sea_orm::model]")]
7#![expect(clippy::same_name_method, reason = "#[sea_orm::model]")]
8
9pub mod content;
10pub mod info;
11#[cfg(feature = "tmdb")]
12pub mod tmdb;
13pub mod watched;
14
15#[cfg(test)]
16mod tests {
17	use flix_model::numbers::{EpisodeNumber, SeasonNumber};
18	#[cfg(feature = "tmdb")]
19	use flix_tmdb::model::id::TmdbRepr as TmdbReprId;
20
21	use sea_orm::ActiveValue::Set;
22	use sea_orm::entity::prelude::*;
23	use sea_orm::sqlx::error::ErrorKind;
24	use seamantic::model::id::SeaOrmRepr as SeaOrmReprId;
25
26	use crate::entity;
27	use crate::entity::content::test::{
28		make_content_collection, make_content_episode, make_content_library, make_content_movie,
29		make_content_season, make_content_show,
30	};
31	#[cfg(feature = "tmdb")]
32	use crate::entity::tmdb::test::{
33		make_tmdb_collection, make_tmdb_episode, make_tmdb_movie, make_tmdb_season, make_tmdb_show,
34	};
35	use crate::entity::watched::test::{make_watched_episode, make_watched_movie};
36	use crate::tests::new_initialized_memory_db;
37
38	#[derive(Debug)]
39	pub(crate) enum ErrorKindNot {
40		Runtime,
41		Sqlx,
42		Database,
43	}
44
45	/// Extract the error kind from a [`DbErr`].
46	///
47	/// # Errors
48	/// If the [`DbErr`] internals diverge from [`SqlxError::Database`].
49	pub(crate) fn get_error_kind(error: DbErr) -> Result<ErrorKind, ErrorKindNot> {
50		let (DbErr::Conn(runtime_err) | DbErr::Exec(runtime_err) | DbErr::Query(runtime_err)) =
51			error
52		else {
53			return Err(ErrorKindNot::Runtime);
54		};
55
56		let RuntimeErr::SqlxError(sqlx_err) = runtime_err else {
57			return Err(ErrorKindNot::Sqlx);
58		};
59
60		let SqlxError::Database(database_err) = sqlx_err.as_ref() else {
61			return Err(ErrorKindNot::Database);
62		};
63
64		Ok(database_err.kind())
65	}
66
67	/// Helper macro for writing tests for `ActiveModel` structs where
68	/// toggling [`sea_orm::ActiveValue`] is needed.
69	macro_rules! notsettable {
70		($field:ident, $value:expr $(, $($skip:ident),+)?) => {
71			if notsettable!(@skip, $field $(, $($skip),+)?) {
72				NotSet
73			} else {
74				Set($value)
75			}
76		};
77		(@skip, $field:ident $(, $skip:ident),*) => {
78			false $(|| stringify!($field) == stringify!($skip))*
79		};
80	}
81	pub(super) use notsettable;
82
83	/// Helper macro for writing tests for `ActiveModel` structs where
84	/// toggling [`sea_orm::ActiveValue`] is needed.
85	macro_rules! noneable {
86			($field:ident, $value:expr $(, $($skip:ident),+)?) => {
87				if noneable!(@skip, $field $(, $($skip),+)?) {
88					None
89				} else {
90					Some($value)
91				}
92			};
93			(@skip, $field:ident $(, $skip:ident),*) => {
94				false $(|| stringify!($field) == stringify!($skip))*
95			};
96		}
97	pub(super) use noneable;
98
99	struct FlixId {
100		collection: SeaOrmReprId,
101		movie: SeaOrmReprId,
102		show: SeaOrmReprId,
103		season: u32,
104		episode: u32,
105	}
106
107	#[cfg(feature = "tmdb")]
108	struct TmdbId {
109		collection: TmdbReprId,
110		movie: TmdbReprId,
111		show: TmdbReprId,
112		season: u32,
113		episode: u32,
114	}
115
116	struct ContentId {
117		library: SeaOrmReprId,
118	}
119
120	struct WatchId {
121		user: SeaOrmReprId,
122	}
123
124	struct DbId {
125		flix: FlixId,
126		#[cfg(feature = "tmdb")]
127		tmdb: TmdbId,
128		content: ContentId,
129		watch: WatchId,
130	}
131
132	impl Default for DbId {
133		fn default() -> Self {
134			Self {
135				flix: FlixId {
136					collection: 1,
137					movie: 2,
138					show: 3,
139					season: 4,
140					episode: 5,
141				},
142				#[cfg(feature = "tmdb")]
143				tmdb: TmdbId {
144					collection: 6,
145					movie: 7,
146					show: 8,
147					season: 9,
148					episode: 10,
149				},
150				content: ContentId { library: 11 },
151				watch: WatchId { user: 12 },
152			}
153		}
154	}
155
156	/// Initialize a database with data to be deleted.
157	///
158	/// # Panics
159	/// If any database operation fails, since this is only for testing.
160	#[expect(clippy::default_numeric_fallback, reason = "unit test")]
161	async fn initialize_deletion_test_database(id: &DbId) -> DatabaseConnection {
162		let db = new_initialized_memory_db().await;
163
164		// Populate the database
165		make_content_library!(&db, id.content.library);
166		make_content_collection!(&db, id.content.library, id.flix.collection, None);
167		make_content_movie!(
168			&db,
169			id.content.library,
170			id.flix.movie,
171			Some(id.flix.collection)
172		);
173		make_content_show!(
174			&db,
175			id.content.library,
176			id.flix.show,
177			Some(id.flix.collection)
178		);
179		make_content_season!(&db, id.content.library, id.flix.show, id.flix.season);
180		make_content_episode!(
181			&db,
182			id.content.library,
183			id.flix.show,
184			id.flix.season,
185			id.flix.episode
186		);
187
188		#[cfg(feature = "tmdb")]
189		make_tmdb_collection!(&db, id.tmdb.collection, id.flix.collection);
190		#[cfg(feature = "tmdb")]
191		make_tmdb_movie!(&db, id.tmdb.movie, id.flix.movie);
192		#[cfg(feature = "tmdb")]
193		make_tmdb_show!(&db, id.tmdb.show, id.flix.show);
194		#[cfg(feature = "tmdb")]
195		make_tmdb_season!(
196			&db,
197			id.tmdb.show,
198			id.tmdb.season,
199			id.flix.show,
200			id.flix.season
201		);
202		#[cfg(feature = "tmdb")]
203		make_tmdb_episode!(
204			&db,
205			id.tmdb.show,
206			id.tmdb.season,
207			id.tmdb.episode,
208			id.flix.show,
209			id.flix.season,
210			id.flix.episode
211		);
212
213		make_watched_movie!(&db, id.flix.movie, id.watch.user);
214		make_watched_episode!(
215			&db,
216			id.flix.show,
217			id.flix.season,
218			id.flix.episode,
219			id.watch.user
220		);
221
222		// Check that everything has one entry
223		assert_eq!(
224			Ok(1),
225			entity::info::collections::Entity::find().count(&db).await
226		);
227		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
228		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
229		assert_eq!(
230			Ok(1),
231			entity::info::seasons::Entity::find().count(&db).await
232		);
233		assert_eq!(
234			Ok(1),
235			entity::info::episodes::Entity::find().count(&db).await
236		);
237
238		#[cfg(feature = "tmdb")]
239		assert_eq!(
240			Ok(1),
241			entity::tmdb::collections::Entity::find().count(&db).await
242		);
243		#[cfg(feature = "tmdb")]
244		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
245		#[cfg(feature = "tmdb")]
246		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
247		#[cfg(feature = "tmdb")]
248		assert_eq!(
249			Ok(1),
250			entity::tmdb::seasons::Entity::find().count(&db).await
251		);
252		#[cfg(feature = "tmdb")]
253		assert_eq!(
254			Ok(1),
255			entity::tmdb::episodes::Entity::find().count(&db).await
256		);
257
258		assert_eq!(
259			Ok(1),
260			entity::content::libraries::Entity::find().count(&db).await
261		);
262		assert_eq!(
263			Ok(1),
264			entity::content::collections::Entity::find()
265				.count(&db)
266				.await
267		);
268		assert_eq!(
269			Ok(1),
270			entity::content::movies::Entity::find().count(&db).await
271		);
272		assert_eq!(
273			Ok(1),
274			entity::content::shows::Entity::find().count(&db).await
275		);
276		assert_eq!(
277			Ok(1),
278			entity::content::seasons::Entity::find().count(&db).await
279		);
280		assert_eq!(
281			Ok(1),
282			entity::content::episodes::Entity::find().count(&db).await
283		);
284
285		assert_eq!(
286			Ok(1),
287			entity::watched::movies::Entity::find().count(&db).await
288		);
289		assert_eq!(
290			Ok(1),
291			entity::watched::episodes::Entity::find().count(&db).await
292		);
293
294		db
295	}
296
297	#[cfg(not(miri))]
298	#[tokio::test]
299	#[expect(clippy::missing_panics_doc, reason = "unit test")]
300	async fn delete_info_collection() {
301		let id = DbId::default();
302		let db = initialize_deletion_test_database(&id).await;
303
304		_ = entity::info::collections::Entity::delete_by_id(seamantic::model::id::Id::from_raw(
305			id.flix.collection,
306		))
307		.exec(&db)
308		.await
309		.expect("Entity::delete_by_id");
310
311		assert_eq!(
312			Ok(0),
313			entity::info::collections::Entity::find().count(&db).await
314		);
315		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
316		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
317		assert_eq!(
318			Ok(1),
319			entity::info::seasons::Entity::find().count(&db).await
320		);
321		assert_eq!(
322			Ok(1),
323			entity::info::episodes::Entity::find().count(&db).await
324		);
325
326		#[cfg(feature = "tmdb")]
327		assert_eq!(
328			Ok(0),
329			entity::tmdb::collections::Entity::find().count(&db).await
330		);
331		#[cfg(feature = "tmdb")]
332		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
333		#[cfg(feature = "tmdb")]
334		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
335		#[cfg(feature = "tmdb")]
336		assert_eq!(
337			Ok(1),
338			entity::tmdb::seasons::Entity::find().count(&db).await
339		);
340		#[cfg(feature = "tmdb")]
341		assert_eq!(
342			Ok(1),
343			entity::tmdb::episodes::Entity::find().count(&db).await
344		);
345
346		assert_eq!(
347			Ok(1),
348			entity::content::libraries::Entity::find().count(&db).await
349		);
350		assert_eq!(
351			Ok(0),
352			entity::content::collections::Entity::find()
353				.count(&db)
354				.await
355		);
356		assert_eq!(
357			Ok(0),
358			entity::content::movies::Entity::find().count(&db).await
359		);
360		assert_eq!(
361			Ok(0),
362			entity::content::shows::Entity::find().count(&db).await
363		);
364		assert_eq!(
365			Ok(0),
366			entity::content::seasons::Entity::find().count(&db).await
367		);
368		assert_eq!(
369			Ok(0),
370			entity::content::episodes::Entity::find().count(&db).await
371		);
372
373		assert_eq!(
374			Ok(1),
375			entity::watched::movies::Entity::find().count(&db).await
376		);
377		assert_eq!(
378			Ok(1),
379			entity::watched::episodes::Entity::find().count(&db).await
380		);
381	}
382
383	#[cfg(not(miri))]
384	#[tokio::test]
385	#[expect(clippy::missing_panics_doc, reason = "unit test")]
386	async fn delete_info_movie() {
387		let id = DbId::default();
388		let db = initialize_deletion_test_database(&id).await;
389
390		_ = entity::info::movies::Entity::delete_by_id(seamantic::model::id::Id::from_raw(
391			id.flix.movie,
392		))
393		.exec(&db)
394		.await
395		.expect("Entity::delete_by_id");
396
397		assert_eq!(
398			Ok(1),
399			entity::info::collections::Entity::find().count(&db).await
400		);
401		assert_eq!(Ok(0), entity::info::movies::Entity::find().count(&db).await);
402		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
403		assert_eq!(
404			Ok(1),
405			entity::info::seasons::Entity::find().count(&db).await
406		);
407		assert_eq!(
408			Ok(1),
409			entity::info::episodes::Entity::find().count(&db).await
410		);
411
412		#[cfg(feature = "tmdb")]
413		assert_eq!(
414			Ok(1),
415			entity::tmdb::collections::Entity::find().count(&db).await
416		);
417		#[cfg(feature = "tmdb")]
418		assert_eq!(Ok(0), entity::tmdb::movies::Entity::find().count(&db).await);
419		#[cfg(feature = "tmdb")]
420		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
421		#[cfg(feature = "tmdb")]
422		assert_eq!(
423			Ok(1),
424			entity::tmdb::seasons::Entity::find().count(&db).await
425		);
426		#[cfg(feature = "tmdb")]
427		assert_eq!(
428			Ok(1),
429			entity::tmdb::episodes::Entity::find().count(&db).await
430		);
431
432		assert_eq!(
433			Ok(1),
434			entity::content::libraries::Entity::find().count(&db).await
435		);
436		assert_eq!(
437			Ok(1),
438			entity::content::collections::Entity::find()
439				.count(&db)
440				.await
441		);
442		assert_eq!(
443			Ok(0),
444			entity::content::movies::Entity::find().count(&db).await
445		);
446		assert_eq!(
447			Ok(1),
448			entity::content::shows::Entity::find().count(&db).await
449		);
450		assert_eq!(
451			Ok(1),
452			entity::content::seasons::Entity::find().count(&db).await
453		);
454		assert_eq!(
455			Ok(1),
456			entity::content::episodes::Entity::find().count(&db).await
457		);
458
459		assert_eq!(
460			Ok(0),
461			entity::watched::movies::Entity::find().count(&db).await
462		);
463		assert_eq!(
464			Ok(1),
465			entity::watched::episodes::Entity::find().count(&db).await
466		);
467	}
468
469	#[cfg(not(miri))]
470	#[tokio::test]
471	#[expect(clippy::missing_panics_doc, reason = "unit test")]
472	async fn delete_info_show() {
473		let id = DbId::default();
474		let db = initialize_deletion_test_database(&id).await;
475
476		_ = entity::info::shows::Entity::delete_by_id(seamantic::model::id::Id::from_raw(
477			id.flix.show,
478		))
479		.exec(&db)
480		.await
481		.expect("Entity::delete_by_id");
482
483		assert_eq!(
484			Ok(1),
485			entity::info::collections::Entity::find().count(&db).await
486		);
487		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
488		assert_eq!(Ok(0), entity::info::shows::Entity::find().count(&db).await);
489		assert_eq!(
490			Ok(0),
491			entity::info::seasons::Entity::find().count(&db).await
492		);
493		assert_eq!(
494			Ok(0),
495			entity::info::episodes::Entity::find().count(&db).await
496		);
497
498		#[cfg(feature = "tmdb")]
499		assert_eq!(
500			Ok(1),
501			entity::tmdb::collections::Entity::find().count(&db).await
502		);
503		#[cfg(feature = "tmdb")]
504		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
505		#[cfg(feature = "tmdb")]
506		assert_eq!(Ok(0), entity::tmdb::shows::Entity::find().count(&db).await);
507		#[cfg(feature = "tmdb")]
508		assert_eq!(
509			Ok(0),
510			entity::tmdb::seasons::Entity::find().count(&db).await
511		);
512		#[cfg(feature = "tmdb")]
513		assert_eq!(
514			Ok(0),
515			entity::tmdb::episodes::Entity::find().count(&db).await
516		);
517
518		assert_eq!(
519			Ok(1),
520			entity::content::libraries::Entity::find().count(&db).await
521		);
522		assert_eq!(
523			Ok(1),
524			entity::content::collections::Entity::find()
525				.count(&db)
526				.await
527		);
528		assert_eq!(
529			Ok(1),
530			entity::content::movies::Entity::find().count(&db).await
531		);
532		assert_eq!(
533			Ok(0),
534			entity::content::shows::Entity::find().count(&db).await
535		);
536		assert_eq!(
537			Ok(0),
538			entity::content::seasons::Entity::find().count(&db).await
539		);
540		assert_eq!(
541			Ok(0),
542			entity::content::episodes::Entity::find().count(&db).await
543		);
544
545		assert_eq!(
546			Ok(1),
547			entity::watched::movies::Entity::find().count(&db).await
548		);
549		assert_eq!(
550			Ok(0),
551			entity::watched::episodes::Entity::find().count(&db).await
552		);
553	}
554
555	#[cfg(not(miri))]
556	#[tokio::test]
557	#[expect(clippy::missing_panics_doc, reason = "unit test")]
558	async fn delete_info_season() {
559		let id = DbId::default();
560		let db = initialize_deletion_test_database(&id).await;
561
562		_ = entity::info::seasons::Entity::delete_by_id((
563			seamantic::model::id::Id::from_raw(id.flix.show),
564			SeasonNumber::new(id.flix.season),
565		))
566		.exec(&db)
567		.await
568		.expect("Entity::delete_by_id");
569
570		assert_eq!(
571			Ok(1),
572			entity::info::collections::Entity::find().count(&db).await
573		);
574		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
575		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
576		assert_eq!(
577			Ok(0),
578			entity::info::seasons::Entity::find().count(&db).await
579		);
580		assert_eq!(
581			Ok(0),
582			entity::info::episodes::Entity::find().count(&db).await
583		);
584
585		#[cfg(feature = "tmdb")]
586		assert_eq!(
587			Ok(1),
588			entity::tmdb::collections::Entity::find().count(&db).await
589		);
590		#[cfg(feature = "tmdb")]
591		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
592		#[cfg(feature = "tmdb")]
593		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
594		#[cfg(feature = "tmdb")]
595		assert_eq!(
596			Ok(0),
597			entity::tmdb::seasons::Entity::find().count(&db).await
598		);
599		#[cfg(feature = "tmdb")]
600		assert_eq!(
601			Ok(0),
602			entity::tmdb::episodes::Entity::find().count(&db).await
603		);
604
605		assert_eq!(
606			Ok(1),
607			entity::content::libraries::Entity::find().count(&db).await
608		);
609		assert_eq!(
610			Ok(1),
611			entity::content::collections::Entity::find()
612				.count(&db)
613				.await
614		);
615		assert_eq!(
616			Ok(1),
617			entity::content::movies::Entity::find().count(&db).await
618		);
619		assert_eq!(
620			Ok(1),
621			entity::content::shows::Entity::find().count(&db).await
622		);
623		assert_eq!(
624			Ok(0),
625			entity::content::seasons::Entity::find().count(&db).await
626		);
627		assert_eq!(
628			Ok(0),
629			entity::content::episodes::Entity::find().count(&db).await
630		);
631
632		assert_eq!(
633			Ok(1),
634			entity::watched::movies::Entity::find().count(&db).await
635		);
636		assert_eq!(
637			Ok(0),
638			entity::watched::episodes::Entity::find().count(&db).await
639		);
640	}
641
642	#[cfg(not(miri))]
643	#[tokio::test]
644	#[expect(clippy::missing_panics_doc, reason = "unit test")]
645	async fn delete_info_episodes() {
646		let id = DbId::default();
647		let db = initialize_deletion_test_database(&id).await;
648
649		_ = entity::info::episodes::Entity::delete_by_id((
650			seamantic::model::id::Id::from_raw(id.flix.show),
651			SeasonNumber::new(id.flix.season),
652			EpisodeNumber::new(id.flix.episode),
653		))
654		.exec(&db)
655		.await
656		.expect("Entity::delete_by_id");
657
658		assert_eq!(
659			Ok(1),
660			entity::info::collections::Entity::find().count(&db).await
661		);
662		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
663		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
664		assert_eq!(
665			Ok(1),
666			entity::info::seasons::Entity::find().count(&db).await
667		);
668		assert_eq!(
669			Ok(0),
670			entity::info::episodes::Entity::find().count(&db).await
671		);
672
673		#[cfg(feature = "tmdb")]
674		assert_eq!(
675			Ok(1),
676			entity::tmdb::collections::Entity::find().count(&db).await
677		);
678		#[cfg(feature = "tmdb")]
679		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
680		#[cfg(feature = "tmdb")]
681		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
682		#[cfg(feature = "tmdb")]
683		assert_eq!(
684			Ok(1),
685			entity::tmdb::seasons::Entity::find().count(&db).await
686		);
687		#[cfg(feature = "tmdb")]
688		assert_eq!(
689			Ok(0),
690			entity::tmdb::episodes::Entity::find().count(&db).await
691		);
692
693		assert_eq!(
694			Ok(1),
695			entity::content::libraries::Entity::find().count(&db).await
696		);
697		assert_eq!(
698			Ok(1),
699			entity::content::collections::Entity::find()
700				.count(&db)
701				.await
702		);
703		assert_eq!(
704			Ok(1),
705			entity::content::movies::Entity::find().count(&db).await
706		);
707		assert_eq!(
708			Ok(1),
709			entity::content::shows::Entity::find().count(&db).await
710		);
711		assert_eq!(
712			Ok(1),
713			entity::content::seasons::Entity::find().count(&db).await
714		);
715		assert_eq!(
716			Ok(0),
717			entity::content::episodes::Entity::find().count(&db).await
718		);
719
720		assert_eq!(
721			Ok(1),
722			entity::watched::movies::Entity::find().count(&db).await
723		);
724		assert_eq!(
725			Ok(0),
726			entity::watched::episodes::Entity::find().count(&db).await
727		);
728	}
729
730	#[cfg(not(miri))]
731	#[cfg(feature = "tmdb")]
732	#[tokio::test]
733	#[expect(clippy::missing_panics_doc, reason = "unit test")]
734	async fn delete_tmdb_collection() {
735		let id = DbId::default();
736		let db = initialize_deletion_test_database(&id).await;
737
738		_ = entity::tmdb::collections::Entity::delete_by_id(flix_tmdb::model::id::Id::from_raw(
739			id.tmdb.collection,
740		))
741		.exec(&db)
742		.await
743		.expect("Entity::delete_by_id");
744
745		assert_eq!(
746			Ok(1),
747			entity::info::collections::Entity::find().count(&db).await
748		);
749		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
750		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
751		assert_eq!(
752			Ok(1),
753			entity::info::seasons::Entity::find().count(&db).await
754		);
755		assert_eq!(
756			Ok(1),
757			entity::info::episodes::Entity::find().count(&db).await
758		);
759
760		#[cfg(feature = "tmdb")]
761		assert_eq!(
762			Ok(0),
763			entity::tmdb::collections::Entity::find().count(&db).await
764		);
765		#[cfg(feature = "tmdb")]
766		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
767		#[cfg(feature = "tmdb")]
768		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
769		#[cfg(feature = "tmdb")]
770		assert_eq!(
771			Ok(1),
772			entity::tmdb::seasons::Entity::find().count(&db).await
773		);
774		#[cfg(feature = "tmdb")]
775		assert_eq!(
776			Ok(1),
777			entity::tmdb::episodes::Entity::find().count(&db).await
778		);
779
780		assert_eq!(
781			Ok(1),
782			entity::content::libraries::Entity::find().count(&db).await
783		);
784		assert_eq!(
785			Ok(1),
786			entity::content::collections::Entity::find()
787				.count(&db)
788				.await
789		);
790		assert_eq!(
791			Ok(1),
792			entity::content::movies::Entity::find().count(&db).await
793		);
794		assert_eq!(
795			Ok(1),
796			entity::content::shows::Entity::find().count(&db).await
797		);
798		assert_eq!(
799			Ok(1),
800			entity::content::seasons::Entity::find().count(&db).await
801		);
802		assert_eq!(
803			Ok(1),
804			entity::content::episodes::Entity::find().count(&db).await
805		);
806
807		assert_eq!(
808			Ok(1),
809			entity::watched::movies::Entity::find().count(&db).await
810		);
811		assert_eq!(
812			Ok(1),
813			entity::watched::episodes::Entity::find().count(&db).await
814		);
815	}
816
817	#[cfg(not(miri))]
818	#[cfg(feature = "tmdb")]
819	#[tokio::test]
820	#[expect(clippy::missing_panics_doc, reason = "unit test")]
821	async fn delete_tmdb_movie() {
822		let id = DbId::default();
823		let db = initialize_deletion_test_database(&id).await;
824
825		_ = entity::tmdb::movies::Entity::delete_by_id(flix_tmdb::model::id::Id::from_raw(
826			id.tmdb.movie,
827		))
828		.exec(&db)
829		.await
830		.expect("Entity::delete_by_id");
831
832		assert_eq!(
833			Ok(1),
834			entity::info::collections::Entity::find().count(&db).await
835		);
836		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
837		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
838		assert_eq!(
839			Ok(1),
840			entity::info::seasons::Entity::find().count(&db).await
841		);
842		assert_eq!(
843			Ok(1),
844			entity::info::episodes::Entity::find().count(&db).await
845		);
846
847		#[cfg(feature = "tmdb")]
848		assert_eq!(
849			Ok(1),
850			entity::tmdb::collections::Entity::find().count(&db).await
851		);
852		#[cfg(feature = "tmdb")]
853		assert_eq!(Ok(0), entity::tmdb::movies::Entity::find().count(&db).await);
854		#[cfg(feature = "tmdb")]
855		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
856		#[cfg(feature = "tmdb")]
857		assert_eq!(
858			Ok(1),
859			entity::tmdb::seasons::Entity::find().count(&db).await
860		);
861		#[cfg(feature = "tmdb")]
862		assert_eq!(
863			Ok(1),
864			entity::tmdb::episodes::Entity::find().count(&db).await
865		);
866
867		assert_eq!(
868			Ok(1),
869			entity::content::libraries::Entity::find().count(&db).await
870		);
871		assert_eq!(
872			Ok(1),
873			entity::content::collections::Entity::find()
874				.count(&db)
875				.await
876		);
877		assert_eq!(
878			Ok(1),
879			entity::content::movies::Entity::find().count(&db).await
880		);
881		assert_eq!(
882			Ok(1),
883			entity::content::shows::Entity::find().count(&db).await
884		);
885		assert_eq!(
886			Ok(1),
887			entity::content::seasons::Entity::find().count(&db).await
888		);
889		assert_eq!(
890			Ok(1),
891			entity::content::episodes::Entity::find().count(&db).await
892		);
893
894		assert_eq!(
895			Ok(1),
896			entity::watched::movies::Entity::find().count(&db).await
897		);
898		assert_eq!(
899			Ok(1),
900			entity::watched::episodes::Entity::find().count(&db).await
901		);
902	}
903
904	#[cfg(not(miri))]
905	#[cfg(feature = "tmdb")]
906	#[tokio::test]
907	#[expect(clippy::missing_panics_doc, reason = "unit test")]
908	async fn delete_tmdb_show() {
909		let id = DbId::default();
910		let db = initialize_deletion_test_database(&id).await;
911
912		_ = entity::tmdb::shows::Entity::delete_by_id(flix_tmdb::model::id::Id::from_raw(
913			id.tmdb.show,
914		))
915		.exec(&db)
916		.await
917		.expect("Entity::delete_by_id");
918
919		assert_eq!(
920			Ok(1),
921			entity::info::collections::Entity::find().count(&db).await
922		);
923		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
924		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
925		assert_eq!(
926			Ok(1),
927			entity::info::seasons::Entity::find().count(&db).await
928		);
929		assert_eq!(
930			Ok(1),
931			entity::info::episodes::Entity::find().count(&db).await
932		);
933
934		#[cfg(feature = "tmdb")]
935		assert_eq!(
936			Ok(1),
937			entity::tmdb::collections::Entity::find().count(&db).await
938		);
939		#[cfg(feature = "tmdb")]
940		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
941		#[cfg(feature = "tmdb")]
942		assert_eq!(Ok(0), entity::tmdb::shows::Entity::find().count(&db).await);
943		#[cfg(feature = "tmdb")]
944		assert_eq!(
945			Ok(0),
946			entity::tmdb::seasons::Entity::find().count(&db).await
947		);
948		#[cfg(feature = "tmdb")]
949		assert_eq!(
950			Ok(0),
951			entity::tmdb::episodes::Entity::find().count(&db).await
952		);
953
954		assert_eq!(
955			Ok(1),
956			entity::content::libraries::Entity::find().count(&db).await
957		);
958		assert_eq!(
959			Ok(1),
960			entity::content::collections::Entity::find()
961				.count(&db)
962				.await
963		);
964		assert_eq!(
965			Ok(1),
966			entity::content::movies::Entity::find().count(&db).await
967		);
968		assert_eq!(
969			Ok(1),
970			entity::content::shows::Entity::find().count(&db).await
971		);
972		assert_eq!(
973			Ok(1),
974			entity::content::seasons::Entity::find().count(&db).await
975		);
976		assert_eq!(
977			Ok(1),
978			entity::content::episodes::Entity::find().count(&db).await
979		);
980
981		assert_eq!(
982			Ok(1),
983			entity::watched::movies::Entity::find().count(&db).await
984		);
985		assert_eq!(
986			Ok(1),
987			entity::watched::episodes::Entity::find().count(&db).await
988		);
989	}
990
991	#[cfg(not(miri))]
992	#[cfg(feature = "tmdb")]
993	#[tokio::test]
994	#[expect(clippy::missing_panics_doc, reason = "unit test")]
995	async fn delete_tmdb_season() {
996		let id = DbId::default();
997		let db = initialize_deletion_test_database(&id).await;
998
999		_ = entity::tmdb::seasons::Entity::delete_by_id((
1000			flix_tmdb::model::id::Id::from_raw(id.tmdb.show),
1001			SeasonNumber::new(id.tmdb.season),
1002		))
1003		.exec(&db)
1004		.await
1005		.expect("Entity::delete_by_id");
1006
1007		assert_eq!(
1008			Ok(1),
1009			entity::info::collections::Entity::find().count(&db).await
1010		);
1011		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
1012		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
1013		assert_eq!(
1014			Ok(1),
1015			entity::info::seasons::Entity::find().count(&db).await
1016		);
1017		assert_eq!(
1018			Ok(1),
1019			entity::info::episodes::Entity::find().count(&db).await
1020		);
1021
1022		#[cfg(feature = "tmdb")]
1023		assert_eq!(
1024			Ok(1),
1025			entity::tmdb::collections::Entity::find().count(&db).await
1026		);
1027		#[cfg(feature = "tmdb")]
1028		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
1029		#[cfg(feature = "tmdb")]
1030		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
1031		#[cfg(feature = "tmdb")]
1032		assert_eq!(
1033			Ok(0),
1034			entity::tmdb::seasons::Entity::find().count(&db).await
1035		);
1036		#[cfg(feature = "tmdb")]
1037		assert_eq!(
1038			Ok(0),
1039			entity::tmdb::episodes::Entity::find().count(&db).await
1040		);
1041
1042		assert_eq!(
1043			Ok(1),
1044			entity::content::libraries::Entity::find().count(&db).await
1045		);
1046		assert_eq!(
1047			Ok(1),
1048			entity::content::collections::Entity::find()
1049				.count(&db)
1050				.await
1051		);
1052		assert_eq!(
1053			Ok(1),
1054			entity::content::movies::Entity::find().count(&db).await
1055		);
1056		assert_eq!(
1057			Ok(1),
1058			entity::content::shows::Entity::find().count(&db).await
1059		);
1060		assert_eq!(
1061			Ok(1),
1062			entity::content::seasons::Entity::find().count(&db).await
1063		);
1064		assert_eq!(
1065			Ok(1),
1066			entity::content::episodes::Entity::find().count(&db).await
1067		);
1068
1069		assert_eq!(
1070			Ok(1),
1071			entity::watched::movies::Entity::find().count(&db).await
1072		);
1073		assert_eq!(
1074			Ok(1),
1075			entity::watched::episodes::Entity::find().count(&db).await
1076		);
1077	}
1078
1079	#[cfg(not(miri))]
1080	#[cfg(feature = "tmdb")]
1081	#[tokio::test]
1082	#[expect(clippy::missing_panics_doc, reason = "unit test")]
1083	async fn delete_tmdb_episode() {
1084		let id = DbId::default();
1085		let db = initialize_deletion_test_database(&id).await;
1086
1087		_ = entity::tmdb::episodes::Entity::delete_by_id((
1088			flix_tmdb::model::id::Id::from_raw(id.tmdb.show),
1089			SeasonNumber::new(id.tmdb.season),
1090			EpisodeNumber::new(id.tmdb.episode),
1091		))
1092		.exec(&db)
1093		.await
1094		.expect("Entity::delete_by_id");
1095
1096		assert_eq!(
1097			Ok(1),
1098			entity::info::collections::Entity::find().count(&db).await
1099		);
1100		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
1101		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
1102		assert_eq!(
1103			Ok(1),
1104			entity::info::seasons::Entity::find().count(&db).await
1105		);
1106		assert_eq!(
1107			Ok(1),
1108			entity::info::episodes::Entity::find().count(&db).await
1109		);
1110
1111		#[cfg(feature = "tmdb")]
1112		assert_eq!(
1113			Ok(1),
1114			entity::tmdb::collections::Entity::find().count(&db).await
1115		);
1116		#[cfg(feature = "tmdb")]
1117		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
1118		#[cfg(feature = "tmdb")]
1119		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
1120		#[cfg(feature = "tmdb")]
1121		assert_eq!(
1122			Ok(1),
1123			entity::tmdb::seasons::Entity::find().count(&db).await
1124		);
1125		#[cfg(feature = "tmdb")]
1126		assert_eq!(
1127			Ok(0),
1128			entity::tmdb::episodes::Entity::find().count(&db).await
1129		);
1130
1131		assert_eq!(
1132			Ok(1),
1133			entity::content::libraries::Entity::find().count(&db).await
1134		);
1135		assert_eq!(
1136			Ok(1),
1137			entity::content::collections::Entity::find()
1138				.count(&db)
1139				.await
1140		);
1141		assert_eq!(
1142			Ok(1),
1143			entity::content::movies::Entity::find().count(&db).await
1144		);
1145		assert_eq!(
1146			Ok(1),
1147			entity::content::shows::Entity::find().count(&db).await
1148		);
1149		assert_eq!(
1150			Ok(1),
1151			entity::content::seasons::Entity::find().count(&db).await
1152		);
1153		assert_eq!(
1154			Ok(1),
1155			entity::content::episodes::Entity::find().count(&db).await
1156		);
1157
1158		assert_eq!(
1159			Ok(1),
1160			entity::watched::movies::Entity::find().count(&db).await
1161		);
1162		assert_eq!(
1163			Ok(1),
1164			entity::watched::episodes::Entity::find().count(&db).await
1165		);
1166	}
1167
1168	#[cfg(not(miri))]
1169	#[tokio::test]
1170	#[expect(clippy::missing_panics_doc, reason = "unit test")]
1171	async fn delete_content_library() {
1172		let id = DbId::default();
1173		let db = initialize_deletion_test_database(&id).await;
1174
1175		_ = entity::content::libraries::Entity::delete_by_id(seamantic::model::id::Id::from_raw(
1176			id.content.library,
1177		))
1178		.exec(&db)
1179		.await
1180		.expect("Entity::delete_by_id");
1181
1182		assert_eq!(
1183			Ok(1),
1184			entity::info::collections::Entity::find().count(&db).await
1185		);
1186		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
1187		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
1188		assert_eq!(
1189			Ok(1),
1190			entity::info::seasons::Entity::find().count(&db).await
1191		);
1192		assert_eq!(
1193			Ok(1),
1194			entity::info::episodes::Entity::find().count(&db).await
1195		);
1196
1197		#[cfg(feature = "tmdb")]
1198		assert_eq!(
1199			Ok(1),
1200			entity::tmdb::collections::Entity::find().count(&db).await
1201		);
1202		#[cfg(feature = "tmdb")]
1203		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
1204		#[cfg(feature = "tmdb")]
1205		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
1206		#[cfg(feature = "tmdb")]
1207		assert_eq!(
1208			Ok(1),
1209			entity::tmdb::seasons::Entity::find().count(&db).await
1210		);
1211		#[cfg(feature = "tmdb")]
1212		assert_eq!(
1213			Ok(1),
1214			entity::tmdb::episodes::Entity::find().count(&db).await
1215		);
1216
1217		assert_eq!(
1218			Ok(0),
1219			entity::content::libraries::Entity::find().count(&db).await
1220		);
1221		assert_eq!(
1222			Ok(0),
1223			entity::content::collections::Entity::find()
1224				.count(&db)
1225				.await
1226		);
1227		assert_eq!(
1228			Ok(0),
1229			entity::content::movies::Entity::find().count(&db).await
1230		);
1231		assert_eq!(
1232			Ok(0),
1233			entity::content::shows::Entity::find().count(&db).await
1234		);
1235		assert_eq!(
1236			Ok(0),
1237			entity::content::seasons::Entity::find().count(&db).await
1238		);
1239		assert_eq!(
1240			Ok(0),
1241			entity::content::episodes::Entity::find().count(&db).await
1242		);
1243
1244		assert_eq!(
1245			Ok(1),
1246			entity::watched::movies::Entity::find().count(&db).await
1247		);
1248		assert_eq!(
1249			Ok(1),
1250			entity::watched::episodes::Entity::find().count(&db).await
1251		);
1252	}
1253
1254	#[cfg(not(miri))]
1255	#[tokio::test]
1256	#[expect(clippy::missing_panics_doc, reason = "unit test")]
1257	async fn delete_content_collection() {
1258		let id = DbId::default();
1259		let db = initialize_deletion_test_database(&id).await;
1260
1261		_ = entity::content::collections::Entity::delete_by_id(seamantic::model::id::Id::from_raw(
1262			id.flix.collection,
1263		))
1264		.exec(&db)
1265		.await
1266		.expect("Entity::delete_by_id");
1267
1268		assert_eq!(
1269			Ok(1),
1270			entity::info::collections::Entity::find().count(&db).await
1271		);
1272		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
1273		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
1274		assert_eq!(
1275			Ok(1),
1276			entity::info::seasons::Entity::find().count(&db).await
1277		);
1278		assert_eq!(
1279			Ok(1),
1280			entity::info::episodes::Entity::find().count(&db).await
1281		);
1282
1283		#[cfg(feature = "tmdb")]
1284		assert_eq!(
1285			Ok(1),
1286			entity::tmdb::collections::Entity::find().count(&db).await
1287		);
1288		#[cfg(feature = "tmdb")]
1289		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
1290		#[cfg(feature = "tmdb")]
1291		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
1292		#[cfg(feature = "tmdb")]
1293		assert_eq!(
1294			Ok(1),
1295			entity::tmdb::seasons::Entity::find().count(&db).await
1296		);
1297		#[cfg(feature = "tmdb")]
1298		assert_eq!(
1299			Ok(1),
1300			entity::tmdb::episodes::Entity::find().count(&db).await
1301		);
1302
1303		assert_eq!(
1304			Ok(1),
1305			entity::content::libraries::Entity::find().count(&db).await
1306		);
1307		assert_eq!(
1308			Ok(0),
1309			entity::content::collections::Entity::find()
1310				.count(&db)
1311				.await
1312		);
1313		assert_eq!(
1314			Ok(0),
1315			entity::content::movies::Entity::find().count(&db).await
1316		);
1317		assert_eq!(
1318			Ok(0),
1319			entity::content::shows::Entity::find().count(&db).await
1320		);
1321		assert_eq!(
1322			Ok(0),
1323			entity::content::seasons::Entity::find().count(&db).await
1324		);
1325		assert_eq!(
1326			Ok(0),
1327			entity::content::episodes::Entity::find().count(&db).await
1328		);
1329
1330		assert_eq!(
1331			Ok(1),
1332			entity::watched::movies::Entity::find().count(&db).await
1333		);
1334		assert_eq!(
1335			Ok(1),
1336			entity::watched::episodes::Entity::find().count(&db).await
1337		);
1338	}
1339
1340	#[cfg(not(miri))]
1341	#[tokio::test]
1342	#[expect(clippy::missing_panics_doc, reason = "unit test")]
1343	async fn delete_content_movie() {
1344		let id = DbId::default();
1345		let db = initialize_deletion_test_database(&id).await;
1346
1347		_ = entity::content::movies::Entity::delete_by_id(seamantic::model::id::Id::from_raw(
1348			id.flix.movie,
1349		))
1350		.exec(&db)
1351		.await
1352		.expect("Entity::delete_by_id");
1353
1354		assert_eq!(
1355			Ok(1),
1356			entity::info::collections::Entity::find().count(&db).await
1357		);
1358		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
1359		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
1360		assert_eq!(
1361			Ok(1),
1362			entity::info::seasons::Entity::find().count(&db).await
1363		);
1364		assert_eq!(
1365			Ok(1),
1366			entity::info::episodes::Entity::find().count(&db).await
1367		);
1368
1369		#[cfg(feature = "tmdb")]
1370		assert_eq!(
1371			Ok(1),
1372			entity::tmdb::collections::Entity::find().count(&db).await
1373		);
1374		#[cfg(feature = "tmdb")]
1375		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
1376		#[cfg(feature = "tmdb")]
1377		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
1378		#[cfg(feature = "tmdb")]
1379		assert_eq!(
1380			Ok(1),
1381			entity::tmdb::seasons::Entity::find().count(&db).await
1382		);
1383		#[cfg(feature = "tmdb")]
1384		assert_eq!(
1385			Ok(1),
1386			entity::tmdb::episodes::Entity::find().count(&db).await
1387		);
1388
1389		assert_eq!(
1390			Ok(1),
1391			entity::content::libraries::Entity::find().count(&db).await
1392		);
1393		assert_eq!(
1394			Ok(1),
1395			entity::content::collections::Entity::find()
1396				.count(&db)
1397				.await
1398		);
1399		assert_eq!(
1400			Ok(0),
1401			entity::content::movies::Entity::find().count(&db).await
1402		);
1403		assert_eq!(
1404			Ok(1),
1405			entity::content::shows::Entity::find().count(&db).await
1406		);
1407		assert_eq!(
1408			Ok(1),
1409			entity::content::seasons::Entity::find().count(&db).await
1410		);
1411		assert_eq!(
1412			Ok(1),
1413			entity::content::episodes::Entity::find().count(&db).await
1414		);
1415
1416		assert_eq!(
1417			Ok(1),
1418			entity::watched::movies::Entity::find().count(&db).await
1419		);
1420		assert_eq!(
1421			Ok(1),
1422			entity::watched::episodes::Entity::find().count(&db).await
1423		);
1424	}
1425
1426	#[cfg(not(miri))]
1427	#[tokio::test]
1428	#[expect(clippy::missing_panics_doc, reason = "unit test")]
1429	async fn delete_content_show() {
1430		let id = DbId::default();
1431		let db = initialize_deletion_test_database(&id).await;
1432
1433		_ = entity::content::shows::Entity::delete_by_id(seamantic::model::id::Id::from_raw(
1434			id.flix.show,
1435		))
1436		.exec(&db)
1437		.await
1438		.expect("Entity::delete_by_id");
1439
1440		assert_eq!(
1441			Ok(1),
1442			entity::info::collections::Entity::find().count(&db).await
1443		);
1444		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
1445		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
1446		assert_eq!(
1447			Ok(1),
1448			entity::info::seasons::Entity::find().count(&db).await
1449		);
1450		assert_eq!(
1451			Ok(1),
1452			entity::info::episodes::Entity::find().count(&db).await
1453		);
1454
1455		#[cfg(feature = "tmdb")]
1456		assert_eq!(
1457			Ok(1),
1458			entity::tmdb::collections::Entity::find().count(&db).await
1459		);
1460		#[cfg(feature = "tmdb")]
1461		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
1462		#[cfg(feature = "tmdb")]
1463		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
1464		#[cfg(feature = "tmdb")]
1465		assert_eq!(
1466			Ok(1),
1467			entity::tmdb::seasons::Entity::find().count(&db).await
1468		);
1469		#[cfg(feature = "tmdb")]
1470		assert_eq!(
1471			Ok(1),
1472			entity::tmdb::episodes::Entity::find().count(&db).await
1473		);
1474
1475		assert_eq!(
1476			Ok(1),
1477			entity::content::libraries::Entity::find().count(&db).await
1478		);
1479		assert_eq!(
1480			Ok(1),
1481			entity::content::collections::Entity::find()
1482				.count(&db)
1483				.await
1484		);
1485		assert_eq!(
1486			Ok(1),
1487			entity::content::movies::Entity::find().count(&db).await
1488		);
1489		assert_eq!(
1490			Ok(0),
1491			entity::content::shows::Entity::find().count(&db).await
1492		);
1493		assert_eq!(
1494			Ok(0),
1495			entity::content::seasons::Entity::find().count(&db).await
1496		);
1497		assert_eq!(
1498			Ok(0),
1499			entity::content::episodes::Entity::find().count(&db).await
1500		);
1501
1502		assert_eq!(
1503			Ok(1),
1504			entity::watched::movies::Entity::find().count(&db).await
1505		);
1506		assert_eq!(
1507			Ok(1),
1508			entity::watched::episodes::Entity::find().count(&db).await
1509		);
1510	}
1511
1512	#[cfg(not(miri))]
1513	#[tokio::test]
1514	#[expect(clippy::missing_panics_doc, reason = "unit test")]
1515	async fn delete_content_season() {
1516		let id = DbId::default();
1517		let db = initialize_deletion_test_database(&id).await;
1518
1519		_ = entity::content::seasons::Entity::delete_by_id((
1520			seamantic::model::id::Id::from_raw(id.flix.show),
1521			SeasonNumber::new(id.flix.season),
1522		))
1523		.exec(&db)
1524		.await
1525		.expect("Entity::delete_by_id");
1526
1527		assert_eq!(
1528			Ok(1),
1529			entity::info::collections::Entity::find().count(&db).await
1530		);
1531		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
1532		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
1533		assert_eq!(
1534			Ok(1),
1535			entity::info::seasons::Entity::find().count(&db).await
1536		);
1537		assert_eq!(
1538			Ok(1),
1539			entity::info::episodes::Entity::find().count(&db).await
1540		);
1541
1542		#[cfg(feature = "tmdb")]
1543		assert_eq!(
1544			Ok(1),
1545			entity::tmdb::collections::Entity::find().count(&db).await
1546		);
1547		#[cfg(feature = "tmdb")]
1548		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
1549		#[cfg(feature = "tmdb")]
1550		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
1551		#[cfg(feature = "tmdb")]
1552		assert_eq!(
1553			Ok(1),
1554			entity::tmdb::seasons::Entity::find().count(&db).await
1555		);
1556		#[cfg(feature = "tmdb")]
1557		assert_eq!(
1558			Ok(1),
1559			entity::tmdb::episodes::Entity::find().count(&db).await
1560		);
1561
1562		assert_eq!(
1563			Ok(1),
1564			entity::content::libraries::Entity::find().count(&db).await
1565		);
1566		assert_eq!(
1567			Ok(1),
1568			entity::content::collections::Entity::find()
1569				.count(&db)
1570				.await
1571		);
1572		assert_eq!(
1573			Ok(1),
1574			entity::content::movies::Entity::find().count(&db).await
1575		);
1576		assert_eq!(
1577			Ok(1),
1578			entity::content::shows::Entity::find().count(&db).await
1579		);
1580		assert_eq!(
1581			Ok(0),
1582			entity::content::seasons::Entity::find().count(&db).await
1583		);
1584		assert_eq!(
1585			Ok(0),
1586			entity::content::episodes::Entity::find().count(&db).await
1587		);
1588
1589		assert_eq!(
1590			Ok(1),
1591			entity::watched::movies::Entity::find().count(&db).await
1592		);
1593		assert_eq!(
1594			Ok(1),
1595			entity::watched::episodes::Entity::find().count(&db).await
1596		);
1597	}
1598
1599	#[cfg(not(miri))]
1600	#[tokio::test]
1601	#[expect(clippy::missing_panics_doc, reason = "unit test")]
1602	async fn delete_content_episode() {
1603		let id = DbId::default();
1604		let db = initialize_deletion_test_database(&id).await;
1605
1606		_ = entity::content::episodes::Entity::delete_by_id((
1607			seamantic::model::id::Id::from_raw(id.flix.show),
1608			SeasonNumber::new(id.flix.season),
1609			EpisodeNumber::new(id.flix.episode),
1610		))
1611		.exec(&db)
1612		.await
1613		.expect("Entity::delete_by_id");
1614
1615		assert_eq!(
1616			Ok(1),
1617			entity::info::collections::Entity::find().count(&db).await
1618		);
1619		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
1620		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
1621		assert_eq!(
1622			Ok(1),
1623			entity::info::seasons::Entity::find().count(&db).await
1624		);
1625		assert_eq!(
1626			Ok(1),
1627			entity::info::episodes::Entity::find().count(&db).await
1628		);
1629
1630		#[cfg(feature = "tmdb")]
1631		assert_eq!(
1632			Ok(1),
1633			entity::tmdb::collections::Entity::find().count(&db).await
1634		);
1635		#[cfg(feature = "tmdb")]
1636		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
1637		#[cfg(feature = "tmdb")]
1638		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
1639		#[cfg(feature = "tmdb")]
1640		assert_eq!(
1641			Ok(1),
1642			entity::tmdb::seasons::Entity::find().count(&db).await
1643		);
1644		#[cfg(feature = "tmdb")]
1645		assert_eq!(
1646			Ok(1),
1647			entity::tmdb::episodes::Entity::find().count(&db).await
1648		);
1649
1650		assert_eq!(
1651			Ok(1),
1652			entity::content::libraries::Entity::find().count(&db).await
1653		);
1654		assert_eq!(
1655			Ok(1),
1656			entity::content::collections::Entity::find()
1657				.count(&db)
1658				.await
1659		);
1660		assert_eq!(
1661			Ok(1),
1662			entity::content::movies::Entity::find().count(&db).await
1663		);
1664		assert_eq!(
1665			Ok(1),
1666			entity::content::shows::Entity::find().count(&db).await
1667		);
1668		assert_eq!(
1669			Ok(1),
1670			entity::content::seasons::Entity::find().count(&db).await
1671		);
1672		assert_eq!(
1673			Ok(0),
1674			entity::content::episodes::Entity::find().count(&db).await
1675		);
1676
1677		assert_eq!(
1678			Ok(1),
1679			entity::watched::movies::Entity::find().count(&db).await
1680		);
1681		assert_eq!(
1682			Ok(1),
1683			entity::watched::episodes::Entity::find().count(&db).await
1684		);
1685	}
1686
1687	#[cfg(not(miri))]
1688	#[tokio::test]
1689	#[expect(clippy::missing_panics_doc, reason = "unit test")]
1690	async fn delete_watched_movie() {
1691		let id = DbId::default();
1692		let db = initialize_deletion_test_database(&id).await;
1693
1694		_ = entity::watched::movies::Entity::delete_by_id((
1695			seamantic::model::id::Id::from_raw(id.flix.movie),
1696			id.watch.user,
1697		))
1698		.exec(&db)
1699		.await
1700		.expect("Entity::delete_by_id");
1701
1702		assert_eq!(
1703			Ok(1),
1704			entity::info::collections::Entity::find().count(&db).await
1705		);
1706		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
1707		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
1708		assert_eq!(
1709			Ok(1),
1710			entity::info::seasons::Entity::find().count(&db).await
1711		);
1712		assert_eq!(
1713			Ok(1),
1714			entity::info::episodes::Entity::find().count(&db).await
1715		);
1716
1717		#[cfg(feature = "tmdb")]
1718		assert_eq!(
1719			Ok(1),
1720			entity::tmdb::collections::Entity::find().count(&db).await
1721		);
1722		#[cfg(feature = "tmdb")]
1723		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
1724		#[cfg(feature = "tmdb")]
1725		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
1726		#[cfg(feature = "tmdb")]
1727		assert_eq!(
1728			Ok(1),
1729			entity::tmdb::seasons::Entity::find().count(&db).await
1730		);
1731		#[cfg(feature = "tmdb")]
1732		assert_eq!(
1733			Ok(1),
1734			entity::tmdb::episodes::Entity::find().count(&db).await
1735		);
1736
1737		assert_eq!(
1738			Ok(1),
1739			entity::content::libraries::Entity::find().count(&db).await
1740		);
1741		assert_eq!(
1742			Ok(1),
1743			entity::content::collections::Entity::find()
1744				.count(&db)
1745				.await
1746		);
1747		assert_eq!(
1748			Ok(1),
1749			entity::content::movies::Entity::find().count(&db).await
1750		);
1751		assert_eq!(
1752			Ok(1),
1753			entity::content::shows::Entity::find().count(&db).await
1754		);
1755		assert_eq!(
1756			Ok(1),
1757			entity::content::seasons::Entity::find().count(&db).await
1758		);
1759		assert_eq!(
1760			Ok(1),
1761			entity::content::episodes::Entity::find().count(&db).await
1762		);
1763
1764		assert_eq!(
1765			Ok(0),
1766			entity::watched::movies::Entity::find().count(&db).await
1767		);
1768		assert_eq!(
1769			Ok(1),
1770			entity::watched::episodes::Entity::find().count(&db).await
1771		);
1772	}
1773
1774	#[cfg(not(miri))]
1775	#[tokio::test]
1776	#[expect(clippy::missing_panics_doc, reason = "unit test")]
1777	async fn delete_watched_episode() {
1778		let id = DbId::default();
1779		let db = initialize_deletion_test_database(&id).await;
1780
1781		_ = entity::watched::episodes::Entity::delete_by_id((
1782			seamantic::model::id::Id::from_raw(id.flix.show),
1783			SeasonNumber::new(id.flix.season),
1784			EpisodeNumber::new(id.flix.episode),
1785			id.watch.user,
1786		))
1787		.exec(&db)
1788		.await
1789		.expect("Entity::delete_by_id");
1790
1791		assert_eq!(
1792			Ok(1),
1793			entity::info::collections::Entity::find().count(&db).await
1794		);
1795		assert_eq!(Ok(1), entity::info::movies::Entity::find().count(&db).await);
1796		assert_eq!(Ok(1), entity::info::shows::Entity::find().count(&db).await);
1797		assert_eq!(
1798			Ok(1),
1799			entity::info::seasons::Entity::find().count(&db).await
1800		);
1801		assert_eq!(
1802			Ok(1),
1803			entity::info::episodes::Entity::find().count(&db).await
1804		);
1805
1806		#[cfg(feature = "tmdb")]
1807		assert_eq!(
1808			Ok(1),
1809			entity::tmdb::collections::Entity::find().count(&db).await
1810		);
1811		#[cfg(feature = "tmdb")]
1812		assert_eq!(Ok(1), entity::tmdb::movies::Entity::find().count(&db).await);
1813		#[cfg(feature = "tmdb")]
1814		assert_eq!(Ok(1), entity::tmdb::shows::Entity::find().count(&db).await);
1815		#[cfg(feature = "tmdb")]
1816		assert_eq!(
1817			Ok(1),
1818			entity::tmdb::seasons::Entity::find().count(&db).await
1819		);
1820		#[cfg(feature = "tmdb")]
1821		assert_eq!(
1822			Ok(1),
1823			entity::tmdb::episodes::Entity::find().count(&db).await
1824		);
1825
1826		assert_eq!(
1827			Ok(1),
1828			entity::content::libraries::Entity::find().count(&db).await
1829		);
1830		assert_eq!(
1831			Ok(1),
1832			entity::content::collections::Entity::find()
1833				.count(&db)
1834				.await
1835		);
1836		assert_eq!(
1837			Ok(1),
1838			entity::content::movies::Entity::find().count(&db).await
1839		);
1840		assert_eq!(
1841			Ok(1),
1842			entity::content::shows::Entity::find().count(&db).await
1843		);
1844		assert_eq!(
1845			Ok(1),
1846			entity::content::seasons::Entity::find().count(&db).await
1847		);
1848		assert_eq!(
1849			Ok(1),
1850			entity::content::episodes::Entity::find().count(&db).await
1851		);
1852
1853		assert_eq!(
1854			Ok(1),
1855			entity::watched::movies::Entity::find().count(&db).await
1856		);
1857		assert_eq!(
1858			Ok(0),
1859			entity::watched::episodes::Entity::find().count(&db).await
1860		);
1861	}
1862}