watchlist add: event only if inserted; adr 0015 jetstream/relay accuracy; drop vacuous assert
This commit is contained in:
@@ -39,7 +39,7 @@ impl WatchlistRepository for SqliteWatchlistRepository {
|
||||
.begin()
|
||||
.await
|
||||
.map_err(crate::shared::map_sqlx_error)?;
|
||||
sqlx::query(
|
||||
let inserted = sqlx::query(
|
||||
"INSERT OR IGNORE INTO watchlist_entries (id, user_id, movie_id, added_at) \
|
||||
VALUES (?, ?, ?, ?)",
|
||||
)
|
||||
@@ -49,8 +49,13 @@ impl WatchlistRepository for SqliteWatchlistRepository {
|
||||
.bind(&added_at)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(crate::shared::map_sqlx_error)?;
|
||||
enqueue_events(&mut tx, events).await?;
|
||||
.map_err(crate::shared::map_sqlx_error)?
|
||||
.rows_affected()
|
||||
> 0;
|
||||
// A repeat add changed nothing, so it announces nothing.
|
||||
if inserted {
|
||||
enqueue_events(&mut tx, events).await?;
|
||||
}
|
||||
tx.commit().await.map_err(crate::shared::map_sqlx_error)
|
||||
}
|
||||
|
||||
|
||||
@@ -200,6 +200,24 @@ async fn adding_a_watchlist_entry_writes_the_entry_and_its_event_in_one_commit()
|
||||
assert_eq!(count(&pool, "event_queue").await, 1);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn re_adding_a_watchlist_entry_enqueues_no_second_event() {
|
||||
let (pool, user_id, movie) = watchlist_fixture().await;
|
||||
let repo = SqliteWatchlistRepository::new(pool.clone());
|
||||
let first = WatchlistEntry::new(user_id.clone(), movie.id().clone());
|
||||
repo.add(&first, &[watchlist_added(&first, &movie)])
|
||||
.await
|
||||
.unwrap();
|
||||
let again = WatchlistEntry::new(user_id, movie.id().clone());
|
||||
|
||||
repo.add(&again, &[watchlist_added(&again, &movie)])
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(count(&pool, "watchlist_entries").await, 1);
|
||||
assert_eq!(count(&pool, "event_queue").await, 1, "no phantom event");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn a_failing_enqueue_rolls_back_the_watchlist_add() {
|
||||
let (pool, user_id, movie) = watchlist_fixture().await;
|
||||
|
||||
@@ -270,7 +270,6 @@ async fn a_refused_save_propagates_and_records_nothing() {
|
||||
.await;
|
||||
|
||||
assert!(result.is_err());
|
||||
assert_eq!(movies.review_count(), 0);
|
||||
assert!(movies.recorded_events().is_empty());
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,11 @@ async fn adding_a_movie_already_on_the_watchlist_is_idempotent() {
|
||||
add::execute(&deps, make_cmd()).await.unwrap();
|
||||
add::execute(&deps, make_cmd()).await.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
movies.recorded_events().len(),
|
||||
1,
|
||||
"the repeat inserted nothing, so it announces nothing"
|
||||
);
|
||||
assert_eq!(
|
||||
watchlist.watchlist_count(),
|
||||
1,
|
||||
|
||||
@@ -38,7 +38,7 @@ impl EventRelaySink for FakeSink {
|
||||
}
|
||||
let outage = self
|
||||
.fail_first
|
||||
.fetch_update(
|
||||
.try_update(
|
||||
std::sync::atomic::Ordering::SeqCst,
|
||||
std::sync::atomic::Ordering::SeqCst,
|
||||
|n| n.checked_sub(1),
|
||||
|
||||
@@ -16,15 +16,23 @@ use super::InMemoryStore;
|
||||
|
||||
#[async_trait]
|
||||
impl WatchlistRepository for InMemoryStore {
|
||||
/// `INSERT OR IGNORE` on UNIQUE(user_id, movie_id): adding twice is a no-op.
|
||||
/// `INSERT OR IGNORE` on UNIQUE(user_id, movie_id): adding twice is a no-op
|
||||
/// and, like the adapter, records events only for the row it inserted.
|
||||
async fn add(&self, entry: &WatchlistEntry, events: &[DomainEvent]) -> Result<(), DomainError> {
|
||||
let key = (entry.user_id.value(), entry.movie_id.value());
|
||||
self.watchlist
|
||||
.write()
|
||||
.unwrap()
|
||||
.entry(key)
|
||||
.or_insert_with(|| entry.clone());
|
||||
self.record_events(events);
|
||||
let inserted = {
|
||||
let mut entries = self.watchlist.write().unwrap();
|
||||
match entries.entry(key) {
|
||||
std::collections::hash_map::Entry::Vacant(slot) => {
|
||||
slot.insert(entry.clone());
|
||||
true
|
||||
}
|
||||
std::collections::hash_map::Entry::Occupied(_) => false,
|
||||
}
|
||||
};
|
||||
if inserted {
|
||||
self.record_events(events);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user