Skip to content

GetSportingEventsQuery — Filter Mode Reference

GetSportingEventsQuery supports three mutually exclusive filter modes resolved by a fixed priority ladder. The handler picks exactly one mode per request; parameters that don't apply to the selected mode are ignored.


Priority Order

Priority Mode Fires when
1 (highest) CurrentGroup CurrentGroupOnly = true AND Sport is set
2 DateRange StartDate or EndDate is set
3 (lowest) NamedGroup Group AND Sport are set, no dates provided
default DateRange None of the above — today +/- 2 days

Group is only used as a filter in NamedGroup mode. If StartDate or EndDate is also provided, DateRange takes priority and Group is ignored entirely.


Decision Flowchart

CurrentGroupOnly = true AND Sport set?
  YES → CurrentGroup (resolve CurrentGroupName from SeasonContract)
  NO  ↓

StartDate OR EndDate set?
  YES → DateRange (Group is ignored even if set)
  NO  ↓

Group set AND Sport set?
  YES → NamedGroup (SeasonId-scoped, Group filter applied)
  NO  ↓

Default → DateRange with today ± 2 days

Mode Details

1. CurrentGroup (highest priority)

Resolves the active group name from SeasonContract and returns all events in that group for the current season.

Requires: CurrentGroupOnly = true, Sport set
Ignores: StartDate, EndDate, Group

How it works: 1. Queries all SeasonContract records filtered by sport, CurrentSeason = true, and non-empty CurrentGroupName, ordered by SeasonYear descending. Multiple competitions within the same sport (e.g., NRL and Super League for Rugby League) can each have their own current season. 2. If no matching seasons are found, returns an empty result. 3. Scopes the sporting events query to all matching SeasonIds using an IN clause, then applies per-season group filtering in memory — each season's events are filtered to only include its own CurrentGroupName (e.g., NRL "Round 15" and Super League "Round 18" can coexist in the same result).

Returns empty when: No SeasonContract exists with CurrentSeason = true and a non-empty CurrentGroupName for the given sport.

Examples:

// Fires CurrentGroup — resolves the active group name from SeasonContract
Sport: "NRL", CurrentGroupOnly: true

// Also fires CurrentGroup — StartDate/EndDate are present but ignored
Sport: "NRL", CurrentGroupOnly: true, StartDate: "2026-06-01", EndDate: "2026-06-30"

// Falls through to default DateRange — CurrentGroupOnly requires Sport to be set
CurrentGroupOnly: true

2. DateRange

Returns events within a date window. This is both the explicit date filter and the default fallback.

Requires: StartDate or EndDate set (or neither — falls back to today +/- 2 days)
Ignores: Group (even if set)

How it works: 1. Queries SportingEventContract where StartTimeUtc falls within [startDate, endDate]. 2. Applies the sport filter if Sport is set. 3. If IsInitialLoad = true and no results are found in the window, jumps to the nearest future date with events and re-queries a 5-day span from that date.

Default dates (when neither StartDate nor EndDate provided):
filterStartDate = today - 2 days
filterEndDate = today + 2 days

Examples:

// Explicit DateRange
Sport: "NRL", StartDate: "2026-06-20", EndDate: "2026-06-27"

// Default DateRange — no params, returns today ± 2 days across all sports
(empty query)

// Default DateRange with sport filter
Sport: "NRL"

// DateRange wins over NamedGroup — StartDate takes priority even when Group is set
Sport: "NRL", Group: "Round 5", StartDate: "2026-06-20"

// DateRange with IsInitialLoad — jumps to the nearest future round when today ± 2 is empty
Sport: "NRL", IsInitialLoad: true

3. NamedGroup (lowest priority)

Returns events for a specific named group within the current season, scoped by SeasonId. Only fires when no date parameters are provided.

Requires: Group set, Sport set, StartDate not set, EndDate not set
Ignores: Nothing — if dates were set, DateRange would fire instead

How it works: 1. Queries all SeasonContract records filtered by sport and CurrentSeason = true, ordered by SeasonYear descending. Multiple competitions within the same sport can each have their own current season. 2. If no current seasons are found, returns an empty result. 3. Scopes the sporting events query to all matching SeasonIds using an IN clause and filters by Group == query.Group.

Returns empty when: No SeasonContract exists with CurrentSeason = true for the given sport.

Examples:

// Fires NamedGroup — no dates, group + sport set
Sport: "NRL", Group: "Round 5"

// Also fires NamedGroup
Sport: "AFL", Group: "Semi Final"

// Falls through to default DateRange — Group requires Sport
Group: "Round 5"

// Fires DateRange, NOT NamedGroup — StartDate takes priority
Sport: "NRL", Group: "Round 5", StartDate: "2026-06-20"

// Fires CurrentGroup, NOT NamedGroup — CurrentGroupOnly wins
Sport: "NRL", Group: "Round 5", CurrentGroupOnly: true

Cache Key Format

Mode Key format
CurrentGroup sporting-events:{Sport}:current-group
DateRange (explicit) sporting-events:{Sport\|all}:{startDate:yyyy-MM-dd}:{endDate:yyyy-MM-dd}
DateRange (default) sporting-events:{Sport\|all}:{today-2:yyyy-MM-dd}:{today+2:yyyy-MM-dd}
NamedGroup sporting-events:{Sport}:group:{Group}

The cache key is resolved in GetSportingEventsQuery.CacheKey using the same priority logic as the handler, so cache lookups are always consistent with what the handler would execute.


Cache TTL

CurrentGroup and NamedGroup are always treated as small-range regardless of any date values, because they scope by SeasonId rather than a date window.

Condition TTL
Small-range (group mode or date span <= 10 days) with live match 10 seconds
Small-range with match starting within 10 minutes 10 seconds
Small-range, no live or imminent match 30 seconds
Large-range (date span > 10 days) 10 minutes

ETag Format

Mode ETag input string
CurrentGroup {Sport}-CurrentGroup-{group1\|group2\|...}-{count} (sorted, deduplicated)
NamedGroup {Sport}-NamedGroup-{groupName}-{count}
DateRange {Sport\|all}-{effectiveStartDate:yyyy-MM-dd}-{effectiveEndDate:yyyy-MM-dd}-{count}

The ETag is the hex hash (ToString("x8")) of the input string. For DateRange with IsInitialLoad, effectiveStartDate/effectiveEndDate reflect the jumped-to window rather than the original query dates.


Cache Tags

The response is tagged for granular invalidation. Tags emitted per request:

Tag Always emitted Conditionally emitted
sportingevents Yes
{Sport} When Sport is set
se:{EventId} One per sporting event in result
group:{GroupName} One per distinct group name in result