add fixture-backed admin and ios scaffold
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
pub use crate::events::{
|
||||
EventManifestSnapshot, EventMediaSnapshot, EventSnapshot, MarketSnapshot, OutcomeSnapshot,
|
||||
};
|
||||
pub use crate::markets::{OddsVersionSnapshot, OutcomeOddsSnapshot};
|
||||
pub use crate::settlement::SettlementSnapshot;
|
||||
@@ -9,10 +9,9 @@ pub use crate::analytics::{AnalyticsBatchRequest, AnalyticsEventInput, Attribute
|
||||
pub use crate::bets::{BetIntentRecord, BetIntentRequest, BetIntentResponse};
|
||||
pub use crate::events::{EventManifestSnapshot, EventSnapshot};
|
||||
pub use crate::events::{MarketSnapshot, OutcomeSnapshot};
|
||||
pub use crate::admin::{EventMediaSnapshot, OddsVersionSnapshot, OutcomeOddsSnapshot, SettlementSnapshot};
|
||||
pub use crate::experiments::ExperimentConfigSnapshot;
|
||||
pub use crate::localization::LocalizationBundleSnapshot;
|
||||
pub use crate::markets::{OddsVersionSnapshot, OutcomeOddsSnapshot};
|
||||
pub use crate::settlement::SettlementSnapshot;
|
||||
pub use crate::sessions::{SessionSnapshot, SessionStartRequest};
|
||||
|
||||
use crate::{
|
||||
@@ -257,6 +256,54 @@ impl AppState {
|
||||
.map_err(|_| AppError::not_found("No active session"))
|
||||
}
|
||||
|
||||
pub async fn admin_create_event_manifest(
|
||||
&self,
|
||||
manifest: EventManifestSnapshot,
|
||||
) -> Result<EventManifestSnapshot, AppError> {
|
||||
let created = self.events.insert_manifest(manifest.clone()).await;
|
||||
|
||||
for market in &created.markets {
|
||||
self.markets.insert_market(market.clone()).await;
|
||||
}
|
||||
|
||||
Ok(created)
|
||||
}
|
||||
|
||||
pub async fn admin_create_market(
|
||||
&self,
|
||||
market: MarketSnapshot,
|
||||
) -> Result<MarketSnapshot, AppError> {
|
||||
let Some(_) = self.event(market.event_id).await else {
|
||||
return Err(AppError::not_found("Event not found"));
|
||||
};
|
||||
|
||||
self.markets.insert_market(market.clone()).await;
|
||||
let _ = self.events.insert_market(market.event_id, market.clone()).await;
|
||||
Ok(market)
|
||||
}
|
||||
|
||||
pub async fn admin_publish_odds(
|
||||
&self,
|
||||
odds: OddsVersionSnapshot,
|
||||
) -> Result<OddsVersionSnapshot, AppError> {
|
||||
let Some(_) = self.markets.market(odds.market_id).await else {
|
||||
return Err(AppError::not_found("Market not found"));
|
||||
};
|
||||
|
||||
Ok(self.markets.publish_odds(odds).await)
|
||||
}
|
||||
|
||||
pub async fn admin_publish_settlement(
|
||||
&self,
|
||||
settlement: SettlementSnapshot,
|
||||
) -> Result<SettlementSnapshot, AppError> {
|
||||
let Some(market) = self.markets.market(settlement.market_id).await else {
|
||||
return Err(AppError::not_found("Market not found"));
|
||||
};
|
||||
|
||||
Ok(self.settlements.upsert(market.event_id, settlement).await)
|
||||
}
|
||||
|
||||
pub async fn next_event(&self) -> Option<EventSnapshot> {
|
||||
self.events.next_event().await
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use serde_json as json;
|
||||
|
||||
fn main() {
|
||||
let fixture = hermes_backend::fixtures::build_sample_study_fixture();
|
||||
let output = json::to_string_pretty(&fixture).expect("valid test event fixture");
|
||||
println!("{output}");
|
||||
}
|
||||
@@ -5,6 +5,8 @@ use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::RwLock;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::fixtures::SampleStudyFixture;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct EventSnapshot {
|
||||
pub id: Uuid,
|
||||
@@ -76,9 +78,22 @@ struct EventsState {
|
||||
|
||||
impl EventsStore {
|
||||
pub fn new() -> Self {
|
||||
Self::with_sample_data()
|
||||
Self::from_fixture(&crate::fixtures::load_sample_study_fixture())
|
||||
}
|
||||
|
||||
pub fn from_fixture(fixture: &SampleStudyFixture) -> Self {
|
||||
let mut manifests_by_event_id = HashMap::new();
|
||||
manifests_by_event_id.insert(fixture.manifest.event.id, fixture.manifest.clone());
|
||||
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(EventsState {
|
||||
feed_order: vec![fixture.manifest.event.id],
|
||||
manifests_by_event_id,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code, unused_variables)]
|
||||
pub fn with_sample_data() -> Self {
|
||||
let event_id = Uuid::parse_str("11111111-1111-1111-1111-111111111111").expect("valid uuid");
|
||||
let market_id = Uuid::parse_str("22222222-2222-2222-2222-222222222222").expect("valid uuid");
|
||||
@@ -152,12 +167,32 @@ impl EventsStore {
|
||||
let mut manifests_by_event_id = HashMap::new();
|
||||
manifests_by_event_id.insert(event_id, manifest);
|
||||
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(EventsState {
|
||||
feed_order: vec![event_id],
|
||||
manifests_by_event_id,
|
||||
})),
|
||||
Self::from_fixture(&crate::fixtures::load_sample_study_fixture())
|
||||
}
|
||||
|
||||
pub async fn insert_manifest(&self, manifest: EventManifestSnapshot) -> EventManifestSnapshot {
|
||||
let mut state = self.inner.write().await;
|
||||
let event_id = manifest.event.id;
|
||||
if !state.manifests_by_event_id.contains_key(&event_id) {
|
||||
state.feed_order.push(event_id);
|
||||
}
|
||||
state.manifests_by_event_id.insert(event_id, manifest.clone());
|
||||
manifest
|
||||
}
|
||||
|
||||
pub async fn insert_market(&self, event_id: Uuid, market: MarketSnapshot) -> bool {
|
||||
let mut state = self.inner.write().await;
|
||||
let Some(manifest) = state.manifests_by_event_id.get_mut(&event_id) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(existing) = manifest.markets.iter_mut().find(|existing| existing.id == market.id) else {
|
||||
manifest.markets.push(market);
|
||||
return true;
|
||||
};
|
||||
|
||||
*existing = market;
|
||||
true
|
||||
}
|
||||
|
||||
pub async fn next_event(&self) -> Option<EventSnapshot> {
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json as json;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
events::{
|
||||
EventManifestSnapshot, EventMediaSnapshot, EventSnapshot, MarketSnapshot, OutcomeSnapshot,
|
||||
},
|
||||
markets::{OddsVersionSnapshot, OutcomeOddsSnapshot},
|
||||
settlement::SettlementSnapshot,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SettlementFixture {
|
||||
pub event_id: Uuid,
|
||||
pub settlement: SettlementSnapshot,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SampleStudyFixture {
|
||||
pub manifest: EventManifestSnapshot,
|
||||
pub odds_versions: Vec<OddsVersionSnapshot>,
|
||||
pub settlement: SettlementFixture,
|
||||
}
|
||||
|
||||
pub fn load_sample_study_fixture() -> SampleStudyFixture {
|
||||
let raw = include_str!("../../../fixtures/manifests/sample_event.json");
|
||||
json::from_str(raw).expect("valid sample study fixture")
|
||||
}
|
||||
|
||||
pub fn build_sample_study_fixture() -> SampleStudyFixture {
|
||||
let event_id = Uuid::parse_str("11111111-1111-1111-1111-111111111111").expect("valid uuid");
|
||||
let market_id = Uuid::parse_str("22222222-2222-2222-2222-222222222222").expect("valid uuid");
|
||||
let odds_version_id =
|
||||
Uuid::parse_str("66666666-6666-6666-6666-666666666666").expect("valid uuid");
|
||||
let lock_at = parse_ts("2099-01-01T00:10:00Z");
|
||||
let settle_at = parse_ts("2099-01-01T00:25:00Z");
|
||||
let created_at = parse_ts("2099-01-01T00:00:00Z");
|
||||
|
||||
let home_outcome_id =
|
||||
Uuid::parse_str("44444444-4444-4444-4444-444444444444").expect("valid uuid");
|
||||
let away_outcome_id =
|
||||
Uuid::parse_str("55555555-5555-5555-5555-555555555555").expect("valid uuid");
|
||||
|
||||
let event = EventSnapshot {
|
||||
id: event_id,
|
||||
sport_type: "football".to_string(),
|
||||
source_ref: "sample-event-001".to_string(),
|
||||
title_en: "Late winner chance".to_string(),
|
||||
title_sv: "Möjlighet till segermål".to_string(),
|
||||
status: "prefetch_ready".to_string(),
|
||||
preview_start_ms: 0,
|
||||
preview_end_ms: 45_000,
|
||||
reveal_start_ms: 50_000,
|
||||
reveal_end_ms: 90_000,
|
||||
lock_at,
|
||||
settle_at,
|
||||
};
|
||||
|
||||
let media = EventMediaSnapshot {
|
||||
id: Uuid::parse_str("33333333-3333-3333-3333-333333333333").expect("valid uuid"),
|
||||
event_id,
|
||||
media_type: "hls_main".to_string(),
|
||||
hls_master_url: "https://cdn.example.com/hermes/sample-event/master.m3u8".to_string(),
|
||||
poster_url: Some("https://cdn.example.com/hermes/sample-event/poster.jpg".to_string()),
|
||||
duration_ms: 90_000,
|
||||
preview_start_ms: 0,
|
||||
preview_end_ms: 45_000,
|
||||
reveal_start_ms: 50_000,
|
||||
reveal_end_ms: 90_000,
|
||||
};
|
||||
|
||||
let outcomes = vec![
|
||||
OutcomeSnapshot {
|
||||
id: home_outcome_id,
|
||||
market_id,
|
||||
outcome_code: "home".to_string(),
|
||||
label_key: "outcome.home".to_string(),
|
||||
sort_order: 1,
|
||||
},
|
||||
OutcomeSnapshot {
|
||||
id: away_outcome_id,
|
||||
market_id,
|
||||
outcome_code: "away".to_string(),
|
||||
label_key: "outcome.away".to_string(),
|
||||
sort_order: 2,
|
||||
},
|
||||
];
|
||||
|
||||
let market = MarketSnapshot {
|
||||
id: market_id,
|
||||
event_id,
|
||||
question_key: "market.sample.winner".to_string(),
|
||||
market_type: "winner".to_string(),
|
||||
status: "open".to_string(),
|
||||
lock_at,
|
||||
settlement_rule_key: "settle_on_match_winner".to_string(),
|
||||
outcomes,
|
||||
};
|
||||
|
||||
let odds_version = OddsVersionSnapshot {
|
||||
id: odds_version_id,
|
||||
market_id,
|
||||
version_no: 1,
|
||||
created_at,
|
||||
is_current: true,
|
||||
odds: vec![
|
||||
OutcomeOddsSnapshot {
|
||||
id: Uuid::parse_str("77777777-7777-7777-7777-777777777777").expect("valid uuid"),
|
||||
odds_version_id,
|
||||
outcome_id: home_outcome_id,
|
||||
decimal_odds: 1.85,
|
||||
fractional_num: 17,
|
||||
fractional_den: 20,
|
||||
},
|
||||
OutcomeOddsSnapshot {
|
||||
id: Uuid::parse_str("88888888-8888-8888-8888-888888888888").expect("valid uuid"),
|
||||
odds_version_id,
|
||||
outcome_id: away_outcome_id,
|
||||
decimal_odds: 2.05,
|
||||
fractional_num: 21,
|
||||
fractional_den: 20,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
let settlement = SettlementFixture {
|
||||
event_id,
|
||||
settlement: SettlementSnapshot {
|
||||
id: Uuid::parse_str("99999999-9999-9999-9999-999999999999").expect("valid uuid"),
|
||||
market_id,
|
||||
settled_at: settle_at,
|
||||
winning_outcome_id: home_outcome_id,
|
||||
},
|
||||
};
|
||||
|
||||
SampleStudyFixture {
|
||||
manifest: EventManifestSnapshot {
|
||||
event,
|
||||
media: vec![media],
|
||||
markets: vec![market],
|
||||
},
|
||||
odds_versions: vec![odds_version],
|
||||
settlement,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_ts(value: &str) -> DateTime<Utc> {
|
||||
DateTime::parse_from_rfc3339(value)
|
||||
.expect("valid timestamp")
|
||||
.with_timezone(&Utc)
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
pub mod analytics;
|
||||
pub mod admin;
|
||||
pub mod bets;
|
||||
pub mod app_state;
|
||||
pub mod config;
|
||||
@@ -8,6 +9,7 @@ pub mod db;
|
||||
pub mod events;
|
||||
pub mod error;
|
||||
pub mod experiments;
|
||||
pub mod fixtures;
|
||||
pub mod localization;
|
||||
pub mod markets;
|
||||
pub mod settlement;
|
||||
|
||||
@@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::RwLock;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::fixtures::SampleStudyFixture;
|
||||
use crate::events::{MarketSnapshot, OutcomeSnapshot};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
@@ -42,9 +43,46 @@ struct MarketsState {
|
||||
|
||||
impl MarketsStore {
|
||||
pub fn new() -> Self {
|
||||
Self::with_sample_data()
|
||||
Self::from_fixture(&crate::fixtures::load_sample_study_fixture())
|
||||
}
|
||||
|
||||
pub fn from_fixture(fixture: &SampleStudyFixture) -> Self {
|
||||
let mut markets_by_event_id: HashMap<Uuid, Vec<MarketSnapshot>> = HashMap::new();
|
||||
let mut markets_by_id = HashMap::new();
|
||||
let mut outcomes_by_id = HashMap::new();
|
||||
let mut current_odds_by_market_id = HashMap::new();
|
||||
|
||||
for market_fixture in &fixture.manifest.markets {
|
||||
let market = market_fixture.clone();
|
||||
markets_by_event_id.entry(market.event_id).or_default().push(market.clone());
|
||||
markets_by_id.insert(market.id, market.clone());
|
||||
|
||||
for outcome in &market.outcomes {
|
||||
outcomes_by_id.insert(outcome.id, outcome.clone());
|
||||
}
|
||||
|
||||
let Some(odds_version) = fixture
|
||||
.odds_versions
|
||||
.iter()
|
||||
.find(|odds_version| odds_version.market_id == market.id)
|
||||
.cloned() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
current_odds_by_market_id.insert(market.id, odds_version);
|
||||
}
|
||||
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(MarketsState {
|
||||
markets_by_event_id,
|
||||
markets_by_id,
|
||||
outcomes_by_id,
|
||||
current_odds_by_market_id,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code, unused_variables)]
|
||||
pub fn with_sample_data() -> Self {
|
||||
let event_id = Uuid::parse_str("11111111-1111-1111-1111-111111111111").expect("valid uuid");
|
||||
let market_id = Uuid::parse_str("22222222-2222-2222-2222-222222222222").expect("valid uuid");
|
||||
@@ -123,14 +161,35 @@ impl MarketsStore {
|
||||
let mut current_odds_by_market_id = HashMap::new();
|
||||
current_odds_by_market_id.insert(market_id, odds_version);
|
||||
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(MarketsState {
|
||||
markets_by_event_id,
|
||||
markets_by_id,
|
||||
outcomes_by_id,
|
||||
current_odds_by_market_id,
|
||||
})),
|
||||
Self::from_fixture(&crate::fixtures::load_sample_study_fixture())
|
||||
}
|
||||
|
||||
pub async fn insert_market(&self, market: MarketSnapshot) -> MarketSnapshot {
|
||||
let mut state = self.inner.write().await;
|
||||
|
||||
state
|
||||
.markets_by_event_id
|
||||
.entry(market.event_id)
|
||||
.or_default()
|
||||
.retain(|existing| existing.id != market.id);
|
||||
state
|
||||
.markets_by_event_id
|
||||
.entry(market.event_id)
|
||||
.or_default()
|
||||
.push(market.clone());
|
||||
state.markets_by_id.insert(market.id, market.clone());
|
||||
|
||||
for outcome in &market.outcomes {
|
||||
state.outcomes_by_id.insert(outcome.id, outcome.clone());
|
||||
}
|
||||
|
||||
market
|
||||
}
|
||||
|
||||
pub async fn publish_odds(&self, odds: OddsVersionSnapshot) -> OddsVersionSnapshot {
|
||||
let mut state = self.inner.write().await;
|
||||
state.current_odds_by_market_id.insert(odds.market_id, odds.clone());
|
||||
odds
|
||||
}
|
||||
|
||||
pub async fn markets_for_event(&self, event_id: Uuid) -> Option<Vec<MarketSnapshot>> {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
use axum::{extract::{Extension, Json}, http::StatusCode};
|
||||
|
||||
use crate::{
|
||||
app_state::{AppState, EventManifestSnapshot, MarketSnapshot, OddsVersionSnapshot, SettlementSnapshot},
|
||||
error::AppError,
|
||||
};
|
||||
|
||||
pub async fn create_event(
|
||||
Extension(state): Extension<AppState>,
|
||||
Json(payload): Json<EventManifestSnapshot>,
|
||||
) -> Result<(StatusCode, Json<EventManifestSnapshot>), AppError> {
|
||||
let created = state.admin_create_event_manifest(payload).await?;
|
||||
Ok((StatusCode::CREATED, Json(created)))
|
||||
}
|
||||
|
||||
pub async fn create_market(
|
||||
Extension(state): Extension<AppState>,
|
||||
Json(payload): Json<MarketSnapshot>,
|
||||
) -> Result<(StatusCode, Json<MarketSnapshot>), AppError> {
|
||||
let created = state.admin_create_market(payload).await?;
|
||||
Ok((StatusCode::CREATED, Json(created)))
|
||||
}
|
||||
|
||||
pub async fn create_odds(
|
||||
Extension(state): Extension<AppState>,
|
||||
Json(payload): Json<OddsVersionSnapshot>,
|
||||
) -> Result<(StatusCode, Json<OddsVersionSnapshot>), AppError> {
|
||||
let created = state.admin_publish_odds(payload).await?;
|
||||
Ok((StatusCode::CREATED, Json(created)))
|
||||
}
|
||||
|
||||
pub async fn create_settlement(
|
||||
Extension(state): Extension<AppState>,
|
||||
Json(payload): Json<SettlementSnapshot>,
|
||||
) -> Result<(StatusCode, Json<SettlementSnapshot>), AppError> {
|
||||
let created = state.admin_publish_settlement(payload).await?;
|
||||
Ok((StatusCode::CREATED, Json(created)))
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod health;
|
||||
pub mod admin;
|
||||
pub mod analytics;
|
||||
pub mod bets;
|
||||
pub mod events;
|
||||
@@ -19,6 +20,10 @@ pub fn router() -> Router {
|
||||
.route("/api/v1/events/{event_id}/markets", get(markets::list_for_event))
|
||||
.route("/api/v1/events/{event_id}/result", get(results::show))
|
||||
.route("/api/v1/markets/{market_id}/odds/current", get(markets::current_odds))
|
||||
.route("/api/v1/admin/events", post(admin::create_event))
|
||||
.route("/api/v1/admin/markets", post(admin::create_market))
|
||||
.route("/api/v1/admin/odds", post(admin::create_odds))
|
||||
.route("/api/v1/admin/settlements", post(admin::create_settlement))
|
||||
.route("/api/v1/bets/intent", post(bets::submit))
|
||||
.route("/api/v1/bets/{bet_intent_id}", get(bets::show))
|
||||
.route("/api/v1/analytics/batch", post(analytics::batch))
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use chrono::{DateTime, Duration as ChronoDuration, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::RwLock;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::fixtures::SampleStudyFixture;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SettlementSnapshot {
|
||||
pub id: Uuid,
|
||||
@@ -14,15 +17,39 @@ pub struct SettlementSnapshot {
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct SettlementsStore {
|
||||
inner: Arc<RwLock<SettlementsState>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct SettlementsState {
|
||||
settlements_by_event_id: HashMap<Uuid, SettlementSnapshot>,
|
||||
settlements_by_market_id: HashMap<Uuid, SettlementSnapshot>,
|
||||
}
|
||||
|
||||
impl SettlementsStore {
|
||||
pub fn new() -> Self {
|
||||
Self::with_sample_data()
|
||||
Self::from_fixture(&crate::fixtures::load_sample_study_fixture())
|
||||
}
|
||||
|
||||
pub fn from_fixture(fixture: &SampleStudyFixture) -> Self {
|
||||
let mut settlements_by_event_id = HashMap::new();
|
||||
settlements_by_event_id.insert(fixture.settlement.event_id, fixture.settlement.settlement.clone());
|
||||
|
||||
let mut settlements_by_market_id = HashMap::new();
|
||||
settlements_by_market_id.insert(
|
||||
fixture.settlement.settlement.market_id,
|
||||
fixture.settlement.settlement.clone(),
|
||||
);
|
||||
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(SettlementsState {
|
||||
settlements_by_event_id,
|
||||
settlements_by_market_id,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code, unused_variables)]
|
||||
pub fn with_sample_data() -> Self {
|
||||
let event_id = Uuid::parse_str("11111111-1111-1111-1111-111111111111").expect("valid uuid");
|
||||
let market_id = Uuid::parse_str("22222222-2222-2222-2222-222222222222").expect("valid uuid");
|
||||
@@ -41,23 +68,31 @@ impl SettlementsStore {
|
||||
let mut settlements_by_market_id = HashMap::new();
|
||||
settlements_by_market_id.insert(market_id, settlement.clone());
|
||||
|
||||
Self {
|
||||
settlements_by_event_id,
|
||||
settlements_by_market_id,
|
||||
}
|
||||
Self::from_fixture(&crate::fixtures::load_sample_study_fixture())
|
||||
}
|
||||
|
||||
pub async fn settlement_for_event(&self, event_id: Uuid) -> Option<SettlementSnapshot> {
|
||||
let Some(settlement) = self.settlements_by_event_id.get(&event_id) else {
|
||||
let state = self.inner.read().await;
|
||||
let Some(settlement) = state.settlements_by_event_id.get(&event_id) else {
|
||||
return None;
|
||||
};
|
||||
Some(settlement.clone())
|
||||
}
|
||||
|
||||
pub async fn settlement_for_market(&self, market_id: Uuid) -> Option<SettlementSnapshot> {
|
||||
let Some(settlement) = self.settlements_by_market_id.get(&market_id) else {
|
||||
let state = self.inner.read().await;
|
||||
let Some(settlement) = state.settlements_by_market_id.get(&market_id) else {
|
||||
return None;
|
||||
};
|
||||
Some(settlement.clone())
|
||||
}
|
||||
|
||||
pub async fn upsert(&self, event_id: Uuid, settlement: SettlementSnapshot) -> SettlementSnapshot {
|
||||
let mut state = self.inner.write().await;
|
||||
state.settlements_by_event_id.insert(event_id, settlement.clone());
|
||||
state
|
||||
.settlements_by_market_id
|
||||
.insert(settlement.market_id, settlement.clone());
|
||||
settlement
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user