From 82d81b2f69160936aa8042aebfeb9b59a968e455 Mon Sep 17 00:00:00 2001 From: default Date: Thu, 4 Jun 2026 18:56:20 +0000 Subject: [PATCH] fix(stops): change stops.date from TIMESTAMPTZ to DATE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The stops.date column was created as TIMESTAMPTZ but is used as a calendar date throughout the app. Supabase returned it as a 'YYYY-MM-DD HH:MM:SS+TZ' string, which made the existing 'new Date(s.date + "T00:00:00")' parsing in the client produce Invalid Date objects — leaving the Stops & Routes calendar empty. Changing the column to DATE makes Supabase return a clean 'YYYY-MM-DD' string that the existing local-time parsing handles correctly. - ALTER stops.date TYPE DATE USING date::DATE - Recreate get_public_stops_for_brand with date DATE in RETURNS TABLE (DROP + CREATE required because CREATE OR REPLACE refuses to change the OUT-parameter row type — PostgreSQL error 42P13) The time (TEXT 'HH:MM') and cutoff_time (TIMESTAMPTZ) columns are unchanged — they legitimately carry time-of-day information. --- .../migrations/208_stops_date_to_date.sql | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 supabase/migrations/208_stops_date_to_date.sql diff --git a/supabase/migrations/208_stops_date_to_date.sql b/supabase/migrations/208_stops_date_to_date.sql new file mode 100644 index 0000000..415bf1b --- /dev/null +++ b/supabase/migrations/208_stops_date_to_date.sql @@ -0,0 +1,73 @@ +-- Migration 208: Change stops.date from TIMESTAMPTZ to DATE +-- +-- Why +-- --- +-- The `stops.date` column was created as TIMESTAMPTZ but is used throughout +-- the app as a calendar date (no time-of-day component). The mismatch +-- forces every client consumer to do `new Date(s.date + "T00:00:00")` to +-- coerce the timestamp into a local-midnight Date — and that hack silently +-- produces an Invalid Date when Supabase returns a `2026-06-15 00:00:00+00` +-- style string, leaving the Stops & Routes calendar empty. +-- +-- Storing the column as DATE makes Supabase return a clean `YYYY-MM-DD` +-- string, which the existing `+ "T00:00:00"` parsing handles correctly. +-- +-- The `time` (TEXT, "HH:MM") and `cutoff_time` (TIMESTAMPTZ) columns are +-- unchanged — they legitimately carry time-of-day information. +-- +-- Affected RPC +-- ------------- +-- `get_public_stops_for_brand` declares `date TIMESTAMPTZ` in its +-- RETURNS TABLE. Recreate it with `date DATE` so the return type matches +-- the underlying column. + +-- 1. Drop the existing RPC so we can recreate it with a new return type. +-- PostgreSQL refuses CREATE OR REPLACE when the OUT-parameter row type +-- changes (error 42P13). +DROP FUNCTION IF EXISTS get_public_stops_for_brand(TEXT); + +-- 2. Convert the column. USING date::DATE truncates the time component, +-- which is what we want — all existing rows are stored at 00:00 anyway. +ALTER TABLE public.stops + ALTER COLUMN date TYPE DATE USING date::DATE; + +-- 3. Recreate the public RPC with the corrected return type. +CREATE OR REPLACE FUNCTION get_public_stops_for_brand(p_brand_slug TEXT) +RETURNS TABLE ( + id UUID, + city TEXT, + state TEXT, + date DATE, + "time" TEXT, + location TEXT, + address TEXT, + slug TEXT, + cutoff_time TIMESTAMPTZ +) +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +BEGIN + RETURN QUERY + SELECT + s.id, + s.city, + s.state, + s.date, + s."time", + s.location, + s.address, + s.slug, + s.cutoff_time + FROM stops s + INNER JOIN brands b ON s.brand_id = b.id + WHERE s.active = true + AND b.slug = p_brand_slug + ORDER BY s.date ASC; +END; +$$; + +GRANT EXECUTE ON FUNCTION get_public_stops_for_brand(TEXT) TO anon; +GRANT EXECUTE ON FUNCTION get_public_stops_for_brand(TEXT) TO authenticated; +GRANT EXECUTE ON FUNCTION get_public_stops_for_brand(TEXT) TO service_role;