Event API — Real Implementations (feat/event-api-stubs)
Branch: feat/event-api-stubs
File: lib/core/network/event_api_service.dart
Background
Before this feature, three core EventApiService methods were stubs that returned hardcoded mock data:
| Method | Old behaviour |
|---|---|
getNearbyEvents() | returned hardcoded mock list |
getTrendingEvents() | returned hardcoded mock list |
searchEvents() | returned hardcoded mock list |
This meant the event discovery screen, the radar map, and search results never showed real events from Supabase.
What Changed
getNearbyEvents(lat, lon, radiusKm)
Three-tier fallback chain:
- RPC first — calls
get_nearby_events(p_lat, p_lon, p_radius_km, p_limit, p_offset)(Haversine in SQL, no PostGIS required). - Bounding-box fallback — if RPC throws (e.g. function not deployed), fetches up to 200 active future events inside an approximate bounding box and filters them client-side using an inline Taylor-series cosine approximation.
- Empty list — on all other failures, returns
[]silently (error reported toIssueReportService).
// Haversine distance (km) — computed in SQL or client-side
6371 × acos(cos(lat1) × cos(lat2) × cos(lon2 - lon1) + sin(lat1) × sin(lat2))SQL migration required: supabase/migrations/20260318000001_get_nearby_events_rpc.sql
getTrendingEvents(limit, timeframeDays)
Queries the events table directly, ordering by view_count DESC, share_count DESC, filtered to:
status = 'active'start_date >= NOW()start_date <= NOW() + timeframeDays
Falls back to [] on error.
searchEvents(query, category, type, limit, offset)
Uses PostgREST’s .or() filter to search across title and description with ilike:
title.ilike.%query%,description.ilike.%query%
Optional category and type filters add .eq() clauses. Falls back to [] on error.
Supabase Migration
20260318000001_get_nearby_events_rpc.sql — creates the get_nearby_events PostgreSQL function:
CREATE OR REPLACE FUNCTION public.get_nearby_events(
p_lat FLOAT, p_lon FLOAT,
p_radius_km FLOAT DEFAULT 10.0,
p_limit INT DEFAULT 20, p_offset INT DEFAULT 0
)
RETURNS SETOF public.events
LANGUAGE sql STABLE SECURITY DEFINER
AS $$
SELECT e.* FROM public.events e
WHERE e.status = 'active'
AND e.start_date >= NOW()
AND (
6371.0 * ACOS(LEAST(1.0,
COS(RADIANS(p_lat)) * COS(RADIANS((e.location->>'latitude')::FLOAT))
* COS(RADIANS((e.location->>'longitude')::FLOAT) - RADIANS(p_lon))
+ SIN(RADIANS(p_lat)) * SIN(RADIANS((e.location->>'latitude')::FLOAT))
))
) <= p_radius_km
ORDER BY /* same expression */ ASC
LIMIT p_limit OFFSET p_offset;
$$;
GRANT EXECUTE ON FUNCTION public.get_nearby_events TO authenticated, anon;Run with: supabase db push or paste into the Supabase SQL editor.
Design Decisions
- No PostGIS required — the Haversine formula is implemented in pure SQL using standard trig functions, making it portable to any Postgres instance.
- Client-side fallback — the bounding-box + inline cosine approach avoids an import of
dart:mathfor a one-off calculation; it uses a Taylor series (cos(x) ≈ 1 - x²/2 + x⁴/24) accurate enough for small distances. - Silent failures — all three methods return empty lists on error rather than propagating exceptions, since the event discovery UI handles empty state gracefully.