deckgl_tracksolid/db/migrations/003_trips_for_day_rpc.sql

63 lines
2.1 KiB
MySQL
Raw Permalink Normal View History

-- 003_trips_for_day_rpc.sql
-- Returns one row per trip on p_date, with the path reconstructed from
-- tracksolid.position_history points falling inside the trip window.
--
-- path_geojson : LineString GeoJSON, deck.gl reads {type, coordinates} directly.
-- timestamps_rel: integer seconds elapsed since trip start, one per vertex.
-- Frontend offsets these to "seconds since 00:00 of selected date"
-- so a single TripsLayer can animate every trip on one timeline.
--
-- HAVING count >= 2 drops trips with too few points to draw a line (rare,
-- but happens for very short trips that started/ended between GPS pings).
CREATE OR REPLACE FUNCTION public.trips_for_day(
p_date date,
p_cost_centres text[] DEFAULT NULL
) RETURNS TABLE (
trip_id bigint,
imei text,
vehicle_name text,
vehicle_number text,
cost_centre text,
start_time timestamptz,
end_time timestamptz,
distance_km numeric,
path_geojson json,
timestamps_rel int[]
)
LANGUAGE sql STABLE
SECURITY DEFINER
SET search_path = public, tracksolid
AS $$
WITH day_trips AS (
SELECT v.*
FROM public.trips_viz_v1 v
WHERE v.start_time::date = p_date
AND (p_cost_centres IS NULL OR v.cost_centre = ANY(p_cost_centres))
)
SELECT
dt.trip_id,
dt.imei,
dt.vehicle_name,
dt.vehicle_number,
dt.cost_centre,
dt.start_time,
dt.end_time,
dt.distance_km,
ST_AsGeoJSON(ST_MakeLine(ph.geom ORDER BY ph.gps_time))::json AS path_geojson,
array_agg(
EXTRACT(EPOCH FROM ph.gps_time - dt.start_time)::int
ORDER BY ph.gps_time
) AS timestamps_rel
FROM day_trips dt
JOIN tracksolid.position_history ph
ON ph.imei = dt.imei
AND ph.gps_time BETWEEN dt.start_time AND dt.end_time
AND ph.geom IS NOT NULL
GROUP BY dt.trip_id, dt.imei, dt.vehicle_name, dt.vehicle_number,
dt.cost_centre, dt.start_time, dt.end_time, dt.distance_km
HAVING count(ph.geom) >= 2;
$$;
GRANT EXECUTE ON FUNCTION public.trips_for_day(date, text[]) TO viz_anon;