feat: atomic wrapup, movie, integration writes

Ride writes: WrapUpRequested/Completed (wrapup create/set_complete),
MovieDiscovered (resolve upsert, new+ext id only), PosterSynced (poster
handler upsert), MovieDeleted (delete_movie), WatchEventIngested (save).
Deps drop event_publisher: wrapup, ingest, delete_review, watchlist add,
review logger.

Remaining .publish( sites:
announce-only: users/delete_account UserDeleted, person/get +
get_credits PersonEnrichmentRequested, jobs/enrichment_staleness,
http-axum search, movies/sync_poster + poster_sync_handler +
image-converter backfill + users/update_profile ImageStored (object
storage), activitypub federation_event_bridge (reacting to events).
rides write, deferred: social/execute (see report),
activitypub review_handler MovieEnrichmentRequested (after
save_remote_review).
This commit is contained in:
2026-10-26 01:02:34 +01:00
parent 2f133afb96
commit 6c295866a0
51 changed files with 1281 additions and 329 deletions

View File

@@ -124,7 +124,7 @@ async fn seed_user_with_dependents(
let user_id = user.id().clone();
let movie = test_movie("Heat");
parts.user.save(&user).await.unwrap();
parts.movie_command.upsert_movie(&movie).await.unwrap();
parts.movie_command.upsert_movie(&movie, &[]).await.unwrap();
parts
.watchlist
@@ -165,15 +165,18 @@ async fn seed_user_with_dependents(
.await
.unwrap();
SqliteWatchEventRepository::new(pool.clone())
.save(&WatchEvent::new(
user_id.clone(),
"Heat".into(),
Some(1995),
None,
WatchEventSource::Jellyfin,
test_watched_at(),
None,
))
.save(
&WatchEvent::new(
user_id.clone(),
"Heat".into(),
Some(1995),
None,
WatchEventSource::Jellyfin,
test_watched_at(),
None,
),
&[],
)
.await
.unwrap();
let social = SqliteSocialRepository::new(
@@ -257,7 +260,7 @@ async fn deleting_a_movie_cascades_to_watchlist_entries_and_every_enrichment_tab
let user = test_user("alice");
let movie = test_movie("Heat");
parts.user.save(&user).await.unwrap();
parts.movie_command.upsert_movie(&movie).await.unwrap();
parts.movie_command.upsert_movie(&movie, &[]).await.unwrap();
parts
.watchlist
.add(
@@ -272,22 +275,29 @@ async fn deleting_a_movie_cascades_to_watchlist_entries_and_every_enrichment_tab
.await
.unwrap();
SqliteWatchEventRepository::new(pool.clone())
.save(&WatchEvent::new(
user.id().clone(),
"Heat".into(),
Some(1995),
None,
WatchEventSource::Plex,
test_watched_at(),
Some(movie.id().clone()),
))
.save(
&WatchEvent::new(
user.id().clone(),
"Heat".into(),
Some(1995),
None,
WatchEventSource::Plex,
test_watched_at(),
Some(movie.id().clone()),
),
&[],
)
.await
.unwrap();
for table in MOVIE_CASCADE_TABLES {
assert!(count(&pool, table).await > 0, "{table} should be seeded");
}
parts.movie_command.delete_movie(movie.id()).await.unwrap();
parts
.movie_command
.delete_movie(movie.id(), &[])
.await
.unwrap();
for table in MOVIE_CASCADE_TABLES {
assert_eq!(count(&pool, table).await, 0, "{table} should cascade");
@@ -306,14 +316,14 @@ async fn deleting_a_movie_that_has_reviews_is_refused_because_reviews_do_not_cas
let user = test_user("alice");
let movie = test_movie("Heat");
parts.user.save(&user).await.unwrap();
parts.movie_command.upsert_movie(&movie).await.unwrap();
parts.movie_command.upsert_movie(&movie, &[]).await.unwrap();
parts
.review
.save_review(&test_review(movie.id(), user.id(), 5), &[])
.await
.unwrap();
let result = parts.movie_command.delete_movie(movie.id()).await;
let result = parts.movie_command.delete_movie(movie.id(), &[]).await;
assert!(matches!(
result,