1pub mod collections {
5 use flix_model::id::CollectionId as FlixId;
6 use flix_tmdb::model::id::CollectionId;
7
8 use chrono::NaiveDate;
9 use sea_orm::entity::prelude::*;
10
11 use crate::entity;
12
13 #[sea_orm::model]
15 #[derive(Debug, Clone, DeriveEntityModel)]
16 #[sea_orm(table_name = "flix_tmdb_collections")]
17 pub struct Model {
18 #[sea_orm(column_type = "Integer", primary_key, nullable, auto_increment = false)]
20 pub tmdb_id: CollectionId,
21 #[sea_orm(unique)]
23 pub flix_id: FlixId,
24 pub last_update: NaiveDate,
26 pub movie_count: u16,
28
29 #[sea_orm(has_many, on_update = "Cascade", on_delete = "Cascade")]
31 pub movies: HasMany<super::movies::Entity>,
32 #[sea_orm(belongs_to, from = "flix_id", to = "id")]
34 pub info: HasOne<entity::info::collections::Entity>,
35 }
36
37 impl ActiveModelBehavior for ActiveModel {}
38}
39
40pub mod movies {
42 use flix_model::id::MovieId as FlixId;
43 use flix_tmdb::model::id::{CollectionId, MovieId};
44
45 use seamantic::model::duration::Seconds;
46
47 use chrono::NaiveDate;
48 use sea_orm::entity::prelude::*;
49
50 use crate::entity;
51
52 #[sea_orm::model]
54 #[derive(Debug, Clone, DeriveEntityModel)]
55 #[sea_orm(table_name = "flix_tmdb_movies")]
56 pub struct Model {
57 #[sea_orm(column_type = "Integer", primary_key, nullable, auto_increment = false)]
59 pub tmdb_id: MovieId,
60 #[sea_orm(unique)]
62 pub flix_id: FlixId,
63 pub last_update: NaiveDate,
65 pub runtime: Seconds,
67 #[sea_orm(indexed)]
69 pub collection_id: Option<CollectionId>,
70
71 #[sea_orm(belongs_to, from = "collection_id", to = "tmdb_id")]
73 pub collection: HasOne<super::collections::Entity>,
74 #[sea_orm(belongs_to, from = "flix_id", to = "id")]
76 pub info: HasOne<entity::info::movies::Entity>,
77 }
78
79 impl ActiveModelBehavior for ActiveModel {}
80}
81
82pub mod shows {
84 use flix_model::id::ShowId as FlixId;
85 use flix_tmdb::model::id::ShowId;
86
87 use chrono::NaiveDate;
88 use sea_orm::entity::prelude::*;
89
90 use crate::entity;
91
92 #[sea_orm::model]
94 #[derive(Debug, Clone, DeriveEntityModel)]
95 #[sea_orm(table_name = "flix_tmdb_shows")]
96 pub struct Model {
97 #[sea_orm(column_type = "Integer", primary_key, nullable, auto_increment = false)]
99 pub tmdb_id: ShowId,
100 #[sea_orm(unique)]
102 pub flix_id: FlixId,
103 pub last_update: NaiveDate,
105 pub number_of_seasons: u32,
107
108 #[sea_orm(has_many, on_update = "Cascade", on_delete = "Cascade")]
110 pub seasons: HasMany<super::seasons::Entity>,
111 #[sea_orm(has_many, on_update = "Cascade", on_delete = "Cascade")]
113 pub episodes: HasMany<super::episodes::Entity>,
114 #[sea_orm(belongs_to, from = "flix_id", to = "id")]
116 pub info: HasOne<entity::info::shows::Entity>,
117 }
118
119 impl ActiveModelBehavior for ActiveModel {}
120}
121
122pub mod seasons {
124 use flix_model::id::ShowId as FlixId;
125 use flix_model::numbers::SeasonNumber;
126 use flix_tmdb::model::id::ShowId;
127
128 use chrono::NaiveDate;
129 use sea_orm::entity::prelude::*;
130
131 use crate::entity;
132
133 #[sea_orm::model]
135 #[derive(Debug, Clone, DeriveEntityModel)]
136 #[sea_orm(table_name = "flix_tmdb_seasons")]
137 pub struct Model {
138 #[sea_orm(primary_key, auto_increment = false)]
140 pub tmdb_show: ShowId,
141 #[sea_orm(primary_key, auto_increment = false)]
143 pub tmdb_season: SeasonNumber,
144 #[sea_orm(unique_key = "flix")]
146 pub flix_show: FlixId,
147 #[sea_orm(unique_key = "flix")]
149 pub flix_season: SeasonNumber,
150 pub last_update: NaiveDate,
152
153 #[sea_orm(belongs_to, from = "tmdb_show", to = "tmdb_id")]
155 pub show: HasOne<super::shows::Entity>,
156 #[sea_orm(
158 belongs_to,
159 from = "(flix_show, flix_season)",
160 to = "(show_id, season_number)"
161 )]
162 pub info: HasOne<entity::info::seasons::Entity>,
163 }
164
165 impl ActiveModelBehavior for ActiveModel {}
166}
167
168pub mod episodes {
170 use flix_model::id::ShowId as FlixId;
171 use flix_model::numbers::{EpisodeNumber, SeasonNumber};
172 use flix_tmdb::model::id::ShowId;
173 use seamantic::model::duration::Seconds;
174
175 use chrono::NaiveDate;
176 use sea_orm::entity::prelude::*;
177
178 use crate::entity;
179
180 #[sea_orm::model]
182 #[derive(Debug, Clone, DeriveEntityModel)]
183 #[sea_orm(table_name = "flix_tmdb_episodes")]
184 pub struct Model {
185 #[sea_orm(primary_key, auto_increment = false)]
187 pub tmdb_show: ShowId,
188 #[sea_orm(primary_key, auto_increment = false)]
190 pub tmdb_season: SeasonNumber,
191 #[sea_orm(primary_key, auto_increment = false)]
193 pub tmdb_episode: EpisodeNumber,
194 #[sea_orm(unique_key = "flix")]
196 pub flix_show: FlixId,
197 #[sea_orm(unique_key = "flix")]
199 pub flix_season: SeasonNumber,
200 #[sea_orm(unique_key = "flix")]
202 pub flix_episode: EpisodeNumber,
203 pub last_update: NaiveDate,
205 pub runtime: Seconds,
207
208 #[sea_orm(belongs_to, from = "tmdb_show", to = "tmdb_id")]
210 pub show: HasOne<super::shows::Entity>,
211 #[sea_orm(
213 belongs_to,
214 from = "(tmdb_show, tmdb_season)",
215 to = "(tmdb_show, tmdb_season)"
216 )]
217 pub season: HasOne<super::seasons::Entity>,
218 #[sea_orm(
220 belongs_to,
221 from = "(flix_show, flix_season, flix_episode)",
222 to = "(show_id, season_number, episode_number)"
223 )]
224 pub info: HasOne<entity::info::episodes::Entity>,
225 }
226
227 impl ActiveModelBehavior for ActiveModel {}
228}
229
230#[cfg(test)]
232pub mod test {
233 macro_rules! make_tmdb_collection {
234 ($db:expr, $id:literal, $flix_id:literal) => {
235 $crate::entity::tmdb::collections::ActiveModel {
236 tmdb_id: Set(::flix_tmdb::model::id::CollectionId::from_raw($id)),
237 flix_id: Set(::flix_model::id::CollectionId::from_raw($flix_id)),
238 last_update: Set(::chrono::NaiveDate::from_yo_opt(1, 1).expect("from_yo_opt")),
239 movie_count: Set(::core::default::Default::default()),
240 }
241 .insert($db)
242 .await
243 .expect("insert");
244 };
245 }
246 pub(crate) use make_tmdb_collection;
247
248 macro_rules! make_tmdb_movie {
249 ($db:expr, $id:literal, $flix_id:literal) => {
250 $crate::entity::tmdb::movies::ActiveModel {
251 tmdb_id: Set(::flix_tmdb::model::id::MovieId::from_raw($id)),
252 flix_id: Set(::flix_model::id::MovieId::from_raw($flix_id)),
253 last_update: Set(::chrono::NaiveDate::from_yo_opt(1, 1).expect("from_yo_opt")),
254 runtime: Set(::core::default::Default::default()),
255 collection_id: Set(None),
256 }
257 .insert($db)
258 .await
259 .expect("insert");
260 };
261 }
262 pub(crate) use make_tmdb_movie;
263
264 macro_rules! make_tmdb_show {
265 ($db:expr, $id:literal, $flix_id:literal) => {
266 $crate::entity::tmdb::shows::ActiveModel {
267 tmdb_id: Set(::flix_tmdb::model::id::ShowId::from_raw($id)),
268 flix_id: Set(::flix_model::id::ShowId::from_raw($flix_id)),
269 last_update: Set(::chrono::NaiveDate::from_yo_opt(1, 1).expect("from_yo_opt")),
270 number_of_seasons: Set(::core::default::Default::default()),
271 }
272 .insert($db)
273 .await
274 .expect("insert");
275 };
276 }
277 pub(crate) use make_tmdb_show;
278
279 macro_rules! make_tmdb_season {
280 ($db:expr, $show:literal, $season:literal, $flix_show:literal, $flix_season:literal) => {
281 $crate::entity::tmdb::seasons::ActiveModel {
282 tmdb_show: Set(::flix_tmdb::model::id::ShowId::from_raw($show)),
283 tmdb_season: Set($season),
284 flix_show: Set(::flix_model::id::ShowId::from_raw($flix_show)),
285 flix_season: Set($flix_season),
286 last_update: Set(::chrono::NaiveDate::from_yo_opt(1, 1).expect("from_yo_opt")),
287 }
288 .insert($db)
289 .await
290 .expect("insert");
291 };
292 }
293 pub(crate) use make_tmdb_season;
294
295 macro_rules! make_tmdb_episode {
296 ($db:expr, $show:literal, $season:literal, $episode:literal, $flix_show:literal, $flix_season:literal, $flix_episode:literal) => {
297 $crate::entity::tmdb::episodes::ActiveModel {
298 tmdb_show: Set(::flix_tmdb::model::id::ShowId::from_raw($show)),
299 tmdb_season: Set($season),
300 tmdb_episode: Set($episode),
301 flix_show: Set(::flix_model::id::ShowId::from_raw($flix_show)),
302 flix_season: Set($flix_season),
303 flix_episode: Set($flix_episode),
304 last_update: Set(::chrono::NaiveDate::from_yo_opt(1, 1).expect("from_yo_opt")),
305 runtime: Set(::core::default::Default::default()),
306 }
307 .insert($db)
308 .await
309 .expect("insert");
310 };
311 }
312 pub(crate) use make_tmdb_episode;
313}
314
315#[cfg(test)]
316mod tests {
317 use core::time::Duration;
318
319 use flix_model::id::{CollectionId, MovieId, ShowId};
320 use flix_tmdb::model::id::{
321 CollectionId as TmdbCollectionId, MovieId as TmdbMovieId, ShowId as TmdbShowId,
322 };
323
324 use chrono::NaiveDate;
325 use sea_orm::ActiveValue::{NotSet, Set};
326 use sea_orm::entity::prelude::*;
327 use sea_orm::sqlx::error::ErrorKind;
328
329 use crate::entity::info::test::{
330 make_info_collection, make_info_episode, make_info_movie, make_info_season, make_info_show,
331 };
332 use crate::tests::new_initialized_memory_db;
333
334 use super::super::tests::get_error_kind;
335 use super::super::tests::notsettable;
336 use super::test::{
337 make_tmdb_collection, make_tmdb_episode, make_tmdb_movie, make_tmdb_season, make_tmdb_show,
338 };
339
340 #[tokio::test]
341 async fn use_test_macros() {
342 let db = new_initialized_memory_db().await;
343
344 make_info_collection!(&db, 1);
345 make_info_movie!(&db, 1);
346 make_info_show!(&db, 1);
347 make_info_season!(&db, 1, 1);
348 make_info_episode!(&db, 1, 1, 1);
349
350 make_tmdb_collection!(&db, 1, 1);
351 make_tmdb_movie!(&db, 1, 1);
352 make_tmdb_show!(&db, 1, 1);
353 make_tmdb_season!(&db, 1, 1, 1, 1);
354 make_tmdb_episode!(&db, 1, 1, 1, 1, 1, 1);
355 }
356
357 #[tokio::test]
358 async fn test_round_trip_collections() {
359 let db = new_initialized_memory_db().await;
360
361 macro_rules! assert_collection {
362 ($db:expr, $id:literal, $tid:literal, Success $(; $($skip:ident),+)?) => {
363 let model = assert_collection!(@insert, $db, $id, $tid $(; $($skip),+)?)
364 .expect("insert");
365
366 assert_eq!(model.tmdb_id, TmdbCollectionId::from_raw($tid));
367 assert_eq!(model.flix_id, CollectionId::from_raw($id));
368 assert_eq!(model.last_update, NaiveDate::from_yo_opt($id, 1).expect("from_yo_opt"));
369 assert_eq!(model.movie_count, $id);
370 };
371 ($db:expr, $id:literal, $tid:literal, $error:ident $(; $($skip:ident),+)?) => {
372 let model = assert_collection!(@insert, $db, $id, $tid $(; $($skip),+)?)
373 .expect_err("insert");
374
375 assert_eq!(get_error_kind(model).expect("get_error_kind"), ErrorKind::$error);
376 };
377 (@insert, $db:expr, $id:literal, $tid:literal $(; $($skip:ident),+)?) => {
378 super::collections::ActiveModel {
379 tmdb_id: notsettable!(tmdb_id, TmdbCollectionId::from_raw($tid) $(, $($skip),+)?),
380 flix_id: notsettable!(flix_id, CollectionId::from_raw($id) $(, $($skip),+)?),
381 last_update: notsettable!(last_update, NaiveDate::from_yo_opt($id, 1).expect("from_yo_opt") $(, $($skip),+)?),
382 movie_count: notsettable!(movie_count, $id $(, $($skip),+)?),
383 }.insert($db).await
384 };
385 }
386
387 assert_collection!(&db, 1, 1, ForeignKeyViolation);
388 make_info_collection!(&db, 1);
389 assert_collection!(&db, 1, 1, Success);
390 assert_collection!(&db, 1, 1, UniqueViolation);
391
392 assert_collection!(&db, 1, 2, UniqueViolation);
393 assert_collection!(&db, 2, 1, UniqueViolation);
394 make_info_collection!(&db, 2);
395 assert_collection!(&db, 2, 2, Success);
396
397 make_info_collection!(&db, 3);
398 assert_collection!(&db, 3, 3, Success; tmdb_id);
399 assert_collection!(&db, 4, 4, NotNullViolation; flix_id);
400 assert_collection!(&db, 5, 5, NotNullViolation; last_update);
401 assert_collection!(&db, 6, 6, NotNullViolation; movie_count);
402 }
403
404 #[tokio::test]
405 async fn test_round_trip_movies() {
406 let db = new_initialized_memory_db().await;
407
408 macro_rules! assert_movie {
409 ($db:expr, $id:literal, $tid:literal, $cid:expr, Success $(; $($skip:ident),+)?) => {
410 let model = assert_movie!(@insert, $db, $id, $tid, $cid $(; $($skip),+)?)
411 .expect("insert");
412
413 assert_eq!(model.tmdb_id, TmdbMovieId::from_raw($tid));
414 assert_eq!(model.flix_id, MovieId::from_raw($id));
415 assert_eq!(model.last_update, NaiveDate::from_yo_opt($id, 1).expect("from_yo_opt"));
416 assert_eq!(model.runtime, Duration::from_secs($tid).into());
417 assert_eq!(model.collection_id, $cid.map(TmdbCollectionId::from_raw));
418 };
419 ($db:expr, $id:literal, $tid:literal, $cid:expr, $error:ident $(; $($skip:ident),+)?) => {
420 let model = assert_movie!(@insert, $db, $id, $tid, $cid $(; $($skip),+)?)
421 .expect_err("insert");
422
423 assert_eq!(get_error_kind(model).expect("get_error_kind"), ErrorKind::$error);
424 };
425 (@insert, $db:expr, $id:literal, $tid:literal, $cid:expr $(; $($skip:ident),+)?) => {
426 super::movies::ActiveModel {
427 tmdb_id: notsettable!(tmdb_id, TmdbMovieId::from_raw($tid) $(, $($skip),+)?),
428 flix_id: notsettable!(flix_id, MovieId::from_raw($id) $(, $($skip),+)?),
429 last_update: notsettable!(last_update, NaiveDate::from_yo_opt($id, 1).expect("from_yo_opt") $(, $($skip),+)?),
430 runtime: notsettable!(runtime, Duration::from_secs($tid).into() $(, $($skip),+)?),
431 collection_id: notsettable!(collection_id, $cid.map(TmdbCollectionId::from_raw) $(, $($skip),+)?),
432 }.insert($db).await
433 };
434 }
435
436 assert_movie!(&db, 1, 1, None, ForeignKeyViolation);
437 make_info_movie!(&db, 1);
438 assert_movie!(&db, 1, 1, None, Success);
439 assert_movie!(&db, 1, 1, None, UniqueViolation);
440
441 make_info_movie!(&db, 2);
442 assert_movie!(&db, 2, 2, Some(2), ForeignKeyViolation);
443 make_info_collection!(&db, 2);
444 make_tmdb_collection!(&db, 2, 2);
445 assert_movie!(&db, 2, 2, Some(2), Success);
446 assert_movie!(&db, 1, 2, None, UniqueViolation);
447 assert_movie!(&db, 2, 1, None, UniqueViolation);
448
449 make_info_movie!(&db, 3);
450 assert_movie!(&db, 3, 3, None, Success; tmdb_id);
451 assert_movie!(&db, 4, 4, None, NotNullViolation; flix_id);
452 assert_movie!(&db, 5, 5, None, NotNullViolation; last_update);
453 assert_movie!(&db, 6, 6, None, NotNullViolation; runtime);
454 assert_movie!(&db, 7, 7, None, ForeignKeyViolation; collection_id);
455 }
456
457 #[tokio::test]
458 async fn test_round_trip_shows() {
459 let db = new_initialized_memory_db().await;
460
461 macro_rules! assert_show {
462 ($db:expr, $id:literal, $tid:literal, Success $(; $($skip:ident),+)?) => {
463 let model = assert_show!(@insert, $db, $id, $tid $(; $($skip),+)?)
464 .expect("insert");
465
466 assert_eq!(model.tmdb_id, TmdbShowId::from_raw($tid));
467 assert_eq!(model.flix_id, ShowId::from_raw($id));
468 assert_eq!(model.last_update, NaiveDate::from_yo_opt(2000, $tid).expect("NaiveDate::from_yo_opt"));
469 assert_eq!(model.number_of_seasons, $id);
470 };
471 ($db:expr, $id:literal, $tid:literal, $error:ident $(; $($skip:ident),+)?) => {
472 let model = assert_show!(@insert, $db, $id, $tid $(; $($skip),+)?)
473 .expect_err("insert");
474
475 assert_eq!(
476 get_error_kind(model).expect("get_error_kind"),
477 ErrorKind::$error
478 );
479 };
480 (@insert, $db:expr, $id:literal, $tid:literal $(; $($skip:ident),+)?) => {
481 super::shows::ActiveModel {
482 tmdb_id: notsettable!(tmdb_id, TmdbShowId::from_raw($tid) $(, $($skip),+)?),
483 flix_id: notsettable!(flix_id, ShowId::from_raw($id) $(, $($skip),+)?),
484 last_update: notsettable!(last_update, NaiveDate::from_yo_opt(2000, $tid).expect("NaiveDate::from_yo_opt") $(, $($skip),+)?),
485 number_of_seasons: notsettable!(number_of_seasons, $id $(, $($skip),+)?),
486 }.insert($db).await
487 };
488 }
489
490 assert_show!(&db, 1, 1, ForeignKeyViolation);
491 make_info_show!(&db, 1);
492 assert_show!(&db, 1, 1, Success);
493 assert_show!(&db, 1, 1, UniqueViolation);
494
495 assert_show!(&db, 1, 2, UniqueViolation);
496 assert_show!(&db, 2, 1, UniqueViolation);
497 make_info_show!(&db, 2);
498 assert_show!(&db, 2, 2, Success);
499
500 make_info_show!(&db, 3);
501 assert_show!(&db, 3, 3, Success; tmdb_id);
502 assert_show!(&db, 4, 4, NotNullViolation; flix_id);
503 assert_show!(&db, 5, 5, NotNullViolation; last_update);
504 assert_show!(&db, 6, 6, NotNullViolation; number_of_seasons);
505 }
506
507 #[tokio::test]
508 async fn test_round_trip_seasons() {
509 let db = new_initialized_memory_db().await;
510
511 macro_rules! assert_season {
512 ($db:expr, $show:literal, $season:literal, $tshow:literal, $tseason:literal, Success $(; $($skip:ident),+)?) => {
513 let model = assert_season!(@insert, $db, $show, $season, $tshow, $tseason $(; $($skip),+)?)
514 .expect("insert");
515
516 assert_eq!(model.tmdb_show, TmdbShowId::from_raw($tshow));
517 assert_eq!(model.tmdb_season, $tseason);
518 assert_eq!(model.flix_show, ShowId::from_raw($show));
519 assert_eq!(model.flix_season, $season);
520 assert_eq!(model.last_update, NaiveDate::from_yo_opt(2000, $tshow).expect("NaiveDate::from_yo_opt"));
521 };
522 ($db:expr, $show:literal, $season:literal, $tshow:literal, $tseason:literal, $error:ident $(; $($skip:ident),+)?) => {
523 let model = assert_season!(@insert, $db, $show, $season, $tshow, $tseason $(; $($skip),+)?)
524 .expect_err("insert");
525
526 assert_eq!(
527 get_error_kind(model).expect("get_error_kind"),
528 ErrorKind::$error
529 );
530 };
531 (@insert, $db:expr, $show:literal, $season:literal, $tshow:literal, $tseason:literal $(; $($skip:ident),+)?) => {
532 super::seasons::ActiveModel {
533 tmdb_show: notsettable!(tmdb_show, TmdbShowId::from_raw($tshow) $(, $($skip),+)?),
534 tmdb_season: notsettable!(tmdb_season, $tseason $(, $($skip),+)?),
535 flix_show: notsettable!(flix_show, ShowId::from_raw($show) $(, $($skip),+)?),
536 flix_season: notsettable!(flix_season, $season $(, $($skip),+)?),
537 last_update: notsettable!(last_update, NaiveDate::from_yo_opt(2000, $tshow).expect("NaiveDate::from_yo_opt") $(, $($skip),+)?),
538 }.insert($db).await
539 };
540 }
541
542 make_info_show!(&db, 1);
543 make_tmdb_show!(&db, 1, 1);
544
545 assert_season!(&db, 1, 1, 1, 1, ForeignKeyViolation);
546 make_info_season!(&db, 1, 1);
547 assert_season!(&db, 1, 1, 1, 1, Success);
548
549 assert_season!(&db, 1, 1, 1, 1, UniqueViolation);
550 assert_season!(&db, 1, 1, 2, 1, UniqueViolation);
551 assert_season!(&db, 2, 1, 1, 1, UniqueViolation);
552 make_info_season!(&db, 1, 2);
553 assert_season!(&db, 1, 2, 1, 2, Success);
554
555 assert_season!(&db, 1, 3, 1, 3, NotNullViolation; tmdb_show);
556 assert_season!(&db, 1, 4, 1, 4, NotNullViolation; tmdb_season);
557 assert_season!(&db, 1, 5, 1, 5, NotNullViolation; flix_show);
558 assert_season!(&db, 1, 6, 1, 6, NotNullViolation; flix_season);
559 assert_season!(&db, 1, 7, 1, 7, NotNullViolation; last_update);
560 }
561
562 #[tokio::test]
563 async fn test_round_trip_episodes() {
564 let db = new_initialized_memory_db().await;
565
566 macro_rules! assert_episode {
567 ($db:expr, $show:literal, $season:literal, $episode:literal, $tshow:literal, $tseason:literal, $tepisode:literal, Success $(; $($skip:ident),+)?) => {
568 let model = assert_episode!(@insert, $db, $show, $season, $episode, $tshow, $tseason, $tepisode $(; $($skip),+)?)
569 .expect("insert");
570
571 assert_eq!(model.tmdb_show, TmdbShowId::from_raw($tshow));
572 assert_eq!(model.tmdb_season, $tseason);
573 assert_eq!(model.tmdb_episode, $tepisode);
574 assert_eq!(model.flix_show, ShowId::from_raw($show));
575 assert_eq!(model.flix_season, $season);
576 assert_eq!(model.flix_episode, $episode);
577 assert_eq!(model.last_update, NaiveDate::from_yo_opt(2000, $tshow).expect("NaiveDate::from_yo_opt"));
578 assert_eq!(model.runtime, Duration::from_secs($tshow).into());
579 };
580 ($db:expr, $show:literal, $season:literal, $episode:literal, $tshow:literal, $tseason:literal, $tepisode:literal, $error:ident $(; $($skip:ident),+)?) => {
581 let model = assert_episode!(@insert, $db, $show, $season, $episode, $tshow, $tseason, $tepisode $(; $($skip),+)?)
582 .expect_err("insert");
583
584 assert_eq!(
585 get_error_kind(model).expect("get_error_kind"),
586 ErrorKind::$error
587 );
588 };
589 (@insert, $db:expr, $show:literal, $season:literal, $episode:literal, $tshow:literal, $tseason:literal, $tepisode:literal $(; $($skip:ident),+)?) => {
590 super::episodes::ActiveModel {
591 tmdb_show: notsettable!(tmdb_show, TmdbShowId::from_raw($tshow) $(, $($skip),+)?),
592 tmdb_season: notsettable!(tmdb_season, $tseason $(, $($skip),+)?),
593 tmdb_episode: notsettable!(tmdb_episode, $tepisode $(, $($skip),+)?),
594 flix_show: notsettable!(flix_show, ShowId::from_raw($show) $(, $($skip),+)?),
595 flix_season: notsettable!(flix_season, $season $(, $($skip),+)?),
596 flix_episode: notsettable!(flix_episode, $episode $(, $($skip),+)?),
597 last_update: notsettable!(last_update, NaiveDate::from_yo_opt(2000, $tshow).expect("NaiveDate::from_yo_opt") $(, $($skip),+)?),
598 runtime: notsettable!(runtime, Duration::from_secs($tshow).into() $(, $($skip),+)?),
599 }.insert($db).await
600 };
601 }
602
603 make_info_show!(&db, 1);
604 make_info_season!(&db, 1, 1);
605 make_tmdb_show!(&db, 1, 1);
606 make_tmdb_season!(&db, 1, 1, 1, 1);
607
608 assert_episode!(&db, 1, 1, 1, 1, 1, 1, ForeignKeyViolation);
609 make_info_episode!(&db, 1, 1, 1);
610 assert_episode!(&db, 1, 1, 1, 1, 1, 1, Success);
611
612 assert_episode!(&db, 1, 1, 1, 1, 1, 1, UniqueViolation);
613 assert_episode!(&db, 1, 1, 1, 1, 2, 1, UniqueViolation);
614 assert_episode!(&db, 1, 1, 1, 2, 1, 1, UniqueViolation);
615 assert_episode!(&db, 1, 2, 1, 1, 1, 1, UniqueViolation);
616 assert_episode!(&db, 2, 1, 1, 1, 1, 1, UniqueViolation);
617 make_info_episode!(&db, 1, 1, 2);
618 assert_episode!(&db, 1, 1, 2, 1, 1, 2, Success);
619
620 assert_episode!(&db, 1, 1, 3, 1, 1, 3, NotNullViolation; tmdb_show);
621 assert_episode!(&db, 1, 1, 3, 1, 1, 4, NotNullViolation; tmdb_season);
622 assert_episode!(&db, 1, 1, 3, 1, 1, 5, NotNullViolation; tmdb_episode);
623 assert_episode!(&db, 1, 1, 3, 1, 1, 6, NotNullViolation; flix_show);
624 assert_episode!(&db, 1, 1, 3, 1, 1, 7, NotNullViolation; flix_season);
625 assert_episode!(&db, 1, 1, 3, 1, 1, 8, NotNullViolation; flix_episode);
626 assert_episode!(&db, 1, 1, 3, 1, 1, 9, NotNullViolation; last_update);
627 assert_episode!(&db, 1, 1, 3, 1, 1, 10, NotNullViolation; runtime);
628 }
629}