feat: atomic review writes with events
This commit is contained in:
@@ -20,18 +20,15 @@ pub async fn execute(deps: &DeleteReviewDeps, cmd: DeleteReviewCommand) -> Resul
|
||||
}
|
||||
|
||||
let movie_id = review.movie_id().clone();
|
||||
deps.review.delete_review(&review_id).await?;
|
||||
|
||||
if let Err(e) = deps
|
||||
.event_publisher
|
||||
.publish(&DomainEvent::ReviewDeleted {
|
||||
review_id: review_id.clone(),
|
||||
user_id: requesting_user_id.clone(),
|
||||
})
|
||||
.await
|
||||
{
|
||||
tracing::warn!("failed to publish ReviewDeleted: {e}");
|
||||
}
|
||||
deps.review
|
||||
.delete_review(
|
||||
&review_id,
|
||||
&[DomainEvent::ReviewDeleted {
|
||||
review_id: review_id.clone(),
|
||||
user_id: requesting_user_id.clone(),
|
||||
}],
|
||||
)
|
||||
.await?;
|
||||
|
||||
let history = deps.diary.get_review_history(&movie_id).await?;
|
||||
if history.viewings().is_empty() {
|
||||
|
||||
@@ -16,7 +16,6 @@ pub struct DeleteReviewDeps {
|
||||
|
||||
pub struct EditReviewDeps {
|
||||
pub review: Arc<dyn ReviewRepository>,
|
||||
pub event_publisher: Arc<dyn EventPublisher>,
|
||||
}
|
||||
|
||||
pub struct GetMovieSocialPageDeps {
|
||||
|
||||
@@ -37,21 +37,12 @@ pub async fn execute(deps: &EditReviewDeps, cmd: EditReviewCommand) -> Result<()
|
||||
spoilers: cmd.spoilers,
|
||||
});
|
||||
|
||||
deps.review.update_review(&updated).await?;
|
||||
|
||||
if let Err(e) = deps
|
||||
.event_publisher
|
||||
.publish(&DomainEvent::ReviewUpdated {
|
||||
review_id: updated.id().clone(),
|
||||
movie_id: updated.movie_id().clone(),
|
||||
user_id: updated.user_id().clone(),
|
||||
rating: updated.rating().clone(),
|
||||
watched_at: *updated.watched_at(),
|
||||
})
|
||||
.await
|
||||
{
|
||||
tracing::warn!("failed to publish ReviewUpdated: {e}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
let event = DomainEvent::ReviewUpdated {
|
||||
review_id: updated.id().clone(),
|
||||
movie_id: updated.movie_id().clone(),
|
||||
user_id: updated.user_id().clone(),
|
||||
rating: updated.rating().clone(),
|
||||
watched_at: *updated.watched_at(),
|
||||
};
|
||||
deps.review.update_review(&updated, &[event]).await
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@ impl ReviewLogger for DefaultReviewLogger {
|
||||
cmd.watch_medium,
|
||||
cmd.spoilers,
|
||||
)?;
|
||||
self.review_repo.save_review(&review).await?;
|
||||
let review_event = DomainEvent::ReviewLogged {
|
||||
review_id: review.id().clone(),
|
||||
movie_id: review.movie_id().clone(),
|
||||
@@ -84,6 +83,17 @@ impl ReviewLogger for DefaultReviewLogger {
|
||||
watched_at: *review.watched_at(),
|
||||
};
|
||||
|
||||
// Events ride the review save (the decisive write) so they commit with it.
|
||||
let mut events = Vec::with_capacity(2);
|
||||
if let Some(ext_id) = movie.external_metadata_id() {
|
||||
events.push(DomainEvent::MovieEnrichmentRequested {
|
||||
movie_id: movie.id().clone(),
|
||||
external_metadata_id: ext_id.clone(),
|
||||
});
|
||||
}
|
||||
events.push(review_event);
|
||||
self.review_repo.save_review(&review, &events).await?;
|
||||
|
||||
let was_on_watchlist = self
|
||||
.watchlist_repo
|
||||
.remove_if_present(review.user_id(), review.movie_id())
|
||||
@@ -98,15 +108,6 @@ impl ReviewLogger for DefaultReviewLogger {
|
||||
.await;
|
||||
}
|
||||
|
||||
if let Some(ext_id) = movie.external_metadata_id() {
|
||||
self.event_publisher
|
||||
.publish(&DomainEvent::MovieEnrichmentRequested {
|
||||
movie_id: movie.id().clone(),
|
||||
external_metadata_id: ext_id.clone(),
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
|
||||
self.event_publisher.publish(&review_event).await
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user