diff --git a/contracts/creator-event-manager/src/lib.rs b/contracts/creator-event-manager/src/lib.rs index aab3a405..efe5f425 100644 --- a/contracts/creator-event-manager/src/lib.rs +++ b/contracts/creator-event-manager/src/lib.rs @@ -17,7 +17,7 @@ use soroban_sdk::{contract, contractimpl, Address, Env, String, Symbol, Vec}; use admin::AdminError; use event::EventError; -use storage_types::{Event, Prediction, Winner}; +use storage_types::{Event, Match, Prediction, Winner}; use verification::VerificationError; use views::EventStatistics; @@ -328,6 +328,22 @@ impl CreatorEventManagerContract { } } + /// Retrieve all matches for an event, sorted by `match_time` ascending. + /// + /// Returns a `Vec` containing every match that belongs to the given + /// event, ordered from earliest to latest scheduled start time. Returns an + /// empty `Vec` when the event exists but has no matches. + /// + /// # Panics + /// * `"event_not_found"` — no event exists with the given ID. + pub fn list_event_matches(env: Env, event_id: u64) -> Vec { + match r#match::list_event_matches(&env, event_id) { + Ok(matches) => matches, + Err(EventError::EventNotFound) => panic!("event_not_found"), + Err(_) => panic!("unexpected_error"), + } + } + /// Return a snapshot of the contract configuration. pub fn get_config(env: Env) -> views::Config { match views::get_config(&env) { diff --git a/contracts/creator-event-manager/src/match.rs b/contracts/creator-event-manager/src/match.rs index 9078838c..289beaca 100644 --- a/contracts/creator-event-manager/src/match.rs +++ b/contracts/creator-event-manager/src/match.rs @@ -1,6 +1,8 @@ -use soroban_sdk::Env; +use soroban_sdk::{Env, Vec}; use crate::event::{self, EventError}; +use crate::storage::{self}; +use crate::storage_types::Match; /// Return the number of matches currently stored for an event. /// @@ -10,3 +12,48 @@ pub fn get_match_count(env: &Env, event_id: u64) -> Result { let event = event::get_event(env, event_id)?; Ok(event.match_count) } + +/// Retrieve all matches for a specific event, sorted by `match_time` ascending. +/// +/// Looks up the `EventMatches(event_id)` index, fetches each [`Match`] struct, +/// and returns them in chronological order (earliest match first). +/// +/// # Sorting behaviour +/// Results are sorted by `match_time` ascending using an insertion sort. +/// Matches are appended in creation order, which may differ from schedule +/// order; the explicit sort guarantees correct ordering regardless. +/// +/// # Errors +/// Returns [`EventError::EventNotFound`] when `event_id` does not exist. +pub fn list_event_matches(env: &Env, event_id: u64) -> Result, EventError> { + // Verify the event exists before reading its match list. + event::get_event(env, event_id)?; + + let match_ids = storage::get_event_matches(env, event_id); + + let mut matches: Vec = Vec::new(env); + for match_id in match_ids.iter() { + if let Ok(m) = storage::get_match(env, match_id) { + matches.push_back(m); + } + } + + // Sort by match_time ascending (insertion sort — list is typically small). + let len = matches.len(); + for i in 1..len { + let mut j = i; + while j > 0 { + let prev = matches.get(j - 1).unwrap(); + let curr = matches.get(j).unwrap(); + if prev.match_time > curr.match_time { + matches.set(j - 1, curr); + matches.set(j, prev); + j -= 1; + } else { + break; + } + } + } + + Ok(matches) +} diff --git a/contracts/creator-event-manager/tests/match_tests.rs b/contracts/creator-event-manager/tests/match_tests.rs index c89a5952..7442600c 100644 --- a/contracts/creator-event-manager/tests/match_tests.rs +++ b/contracts/creator-event-manager/tests/match_tests.rs @@ -93,3 +93,91 @@ fn test_get_match_count_missing_event_panics() { let (_env, client, _contract_id, _admin, _xlm_token) = setup(); client.get_match_count(&999u64); } + +// --------------------------------------------------------------------------- +// list_event_matches tests +// --------------------------------------------------------------------------- + +fn add_match( + env: &Env, + contract_id: &Address, + event_id: u64, + team_a: &str, + team_b: &str, + match_time: u64, +) -> u64 { + env.as_contract(contract_id, || { + let mut event = storage::get_event(env, event_id).expect("event exists"); + event.add_match(); + storage::set_event(env, event_id, &event); + + let match_id = storage::next_match_id(env); + let match_record = creator_event_manager::storage_types::Match::new( + match_id, + event_id, + String::from_str(env, team_a), + String::from_str(env, team_b), + match_time, + ); + storage::set_match(env, match_id, &match_record); + storage::add_event_match(env, event_id, match_id); + match_id + }) +} + +#[test] +fn test_list_event_matches_returns_all_matches() { + let (env, client, contract_id, _admin, xlm_token) = setup(); + let creator = Address::generate(&env); + fund(&env, &xlm_token, &creator, FEE); + + let (event_id, _) = client.create_event(&creator, &title(&env), &desc(&env), &5u32); + + let base_time = 1_000_000u64; + add_match(&env, &contract_id, event_id, "Team A", "Team B", base_time + 3000); + add_match(&env, &contract_id, event_id, "Team C", "Team D", base_time + 1000); + add_match(&env, &contract_id, event_id, "Team E", "Team F", base_time + 2000); + + let matches = client.list_event_matches(&event_id); + assert_eq!(matches.len(), 3); +} + +#[test] +fn test_list_event_matches_empty_for_new_event() { + let (env, client, _contract_id, _admin, xlm_token) = setup(); + let creator = Address::generate(&env); + fund(&env, &xlm_token, &creator, FEE); + + let (event_id, _) = client.create_event(&creator, &title(&env), &desc(&env), &5u32); + + let matches = client.list_event_matches(&event_id); + assert_eq!(matches.len(), 0); +} + +#[test] +fn test_list_event_matches_sorted_by_match_time_ascending() { + let (env, client, contract_id, _admin, xlm_token) = setup(); + let creator = Address::generate(&env); + fund(&env, &xlm_token, &creator, FEE); + + let (event_id, _) = client.create_event(&creator, &title(&env), &desc(&env), &5u32); + + let base_time = 2_000_000u64; + // Insert in reverse order to ensure sort is applied. + add_match(&env, &contract_id, event_id, "Team A", "Team B", base_time + 3000); + add_match(&env, &contract_id, event_id, "Team C", "Team D", base_time + 1000); + add_match(&env, &contract_id, event_id, "Team E", "Team F", base_time + 2000); + + let matches = client.list_event_matches(&event_id); + assert_eq!(matches.len(), 3); + assert_eq!(matches.get(0).unwrap().match_time, base_time + 1000); + assert_eq!(matches.get(1).unwrap().match_time, base_time + 2000); + assert_eq!(matches.get(2).unwrap().match_time, base_time + 3000); +} + +#[test] +#[should_panic(expected = "event_not_found")] +fn test_list_event_matches_nonexistent_event_panics() { + let (_env, client, _contract_id, _admin, _xlm_token) = setup(); + client.list_event_matches(&999u64); +}