From 95c352af48d9640a5c39a65dc217f6800bfbe66d Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 20:13:27 +0000 Subject: [PATCH] Connect to Lovable Cloud Approve and apply migration to fix RPC for park location data - Update TypeScript types to remove temp_location_data - Create migration to fix create_submission_with_items by using relational park_submission_locations - Ensure _temp_location is extracted and stored properly --- ...2_df5a3cc0-baac-40da-a74f-d43110b9ba2b.sql | 336 ++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 supabase/migrations/20251110201312_df5a3cc0-baac-40da-a74f-d43110b9ba2b.sql diff --git a/supabase/migrations/20251110201312_df5a3cc0-baac-40da-a74f-d43110b9ba2b.sql b/supabase/migrations/20251110201312_df5a3cc0-baac-40da-a74f-d43110b9ba2b.sql new file mode 100644 index 00000000..35c9b2c0 --- /dev/null +++ b/supabase/migrations/20251110201312_df5a3cc0-baac-40da-a74f-d43110b9ba2b.sql @@ -0,0 +1,336 @@ +-- Fix create_submission_with_items to use relational park_submission_locations +-- Removes temp_location_data column reference and properly stores location data + +DROP FUNCTION IF EXISTS public.create_submission_with_items(uuid, text, jsonb, jsonb[]); + +CREATE FUNCTION public.create_submission_with_items( + p_user_id uuid, + p_submission_type text, + p_content jsonb, + p_items jsonb[] +) +RETURNS uuid +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path TO 'public' +AS $$ +DECLARE + v_submission_id UUID; + v_item JSONB; + v_item_data JSONB; + v_item_type TEXT; + v_action_type TEXT; + v_park_submission_id UUID; + v_company_submission_id UUID; + v_ride_submission_id UUID; + v_ride_model_submission_id UUID; + v_photo_submission_id UUID; + v_timeline_event_submission_id UUID; + v_submission_item_id UUID; + v_temp_ref_key TEXT; + v_temp_ref_value TEXT; + v_ref_type TEXT; + v_ref_order_index INTEGER; + v_existing_user_id TEXT; + v_existing_submission_id TEXT; + v_temp_location JSONB; +BEGIN + -- DEFENSIVE CHECK: Warn if variables are already set + BEGIN + v_existing_user_id := current_setting('app.current_user_id', true); + v_existing_submission_id := current_setting('app.submission_id', true); + + IF v_existing_user_id IS NOT NULL AND v_existing_user_id != '' THEN + RAISE WARNING 'Session variable app.current_user_id already set to: % (expected clean state)', v_existing_user_id; + END IF; + + IF v_existing_submission_id IS NOT NULL AND v_existing_submission_id != '' THEN + RAISE WARNING 'Session variable app.submission_id already set to: % (expected clean state)', v_existing_submission_id; + END IF; + EXCEPTION WHEN OTHERS THEN + NULL; + END; + + PERFORM set_config('app.current_user_id', p_user_id::text, true); + PERFORM set_config('app.submission_id', '', true); + + INSERT INTO content_submissions (user_id, submission_type, status, approval_mode) + VALUES (p_user_id, p_submission_type, 'pending', 'full') + RETURNING id INTO v_submission_id; + + PERFORM set_config('app.submission_id', v_submission_id::text, true); + + IF array_length(p_items, 1) IS NULL OR array_length(p_items, 1) = 0 THEN + RAISE EXCEPTION 'Cannot create submission without items'; + END IF; + + FOREACH v_item IN ARRAY p_items + LOOP + v_item_type := (v_item->>'item_type')::TEXT; + v_action_type := (v_item->>'action_type')::TEXT; + v_item_data := v_item->'item_data'; + + v_park_submission_id := NULL; + v_company_submission_id := NULL; + v_ride_submission_id := NULL; + v_ride_model_submission_id := NULL; + v_photo_submission_id := NULL; + v_timeline_event_submission_id := NULL; + v_temp_location := NULL; + + IF v_item_type = 'park' THEN + v_temp_location := v_item_data->'_temp_location'; + + INSERT INTO park_submissions ( + submission_id, name, slug, description, park_type, status, + opening_date, opening_date_precision, closing_date, closing_date_precision, + location_id, operator_id, property_owner_id, + website_url, phone, email, + banner_image_url, banner_image_id, card_image_url, card_image_id + ) VALUES ( + v_submission_id, + v_item_data->>'name', + v_item_data->>'slug', + v_item_data->>'description', + v_item_data->>'park_type', + v_item_data->>'status', + (v_item_data->>'opening_date')::DATE, + v_item_data->>'opening_date_precision', + (v_item_data->>'closing_date')::DATE, + v_item_data->>'closing_date_precision', + (v_item_data->>'location_id')::UUID, + (v_item_data->>'operator_id')::UUID, + (v_item_data->>'property_owner_id')::UUID, + v_item_data->>'website_url', + v_item_data->>'phone', + v_item_data->>'email', + v_item_data->>'banner_image_url', + v_item_data->>'banner_image_id', + v_item_data->>'card_image_url', + v_item_data->>'card_image_id' + ) RETURNING id INTO v_park_submission_id; + + IF v_temp_location IS NOT NULL AND jsonb_typeof(v_temp_location) = 'object' THEN + INSERT INTO park_submission_locations ( + park_submission_id, + name, + street_address, + city, + state_province, + country, + postal_code, + latitude, + longitude, + timezone, + display_name + ) VALUES ( + v_park_submission_id, + v_temp_location->>'name', + v_temp_location->>'street_address', + v_temp_location->>'city', + v_temp_location->>'state_province', + v_temp_location->>'country', + v_temp_location->>'postal_code', + (v_temp_location->>'latitude')::NUMERIC, + (v_temp_location->>'longitude')::NUMERIC, + v_temp_location->>'timezone', + v_temp_location->>'display_name' + ); + + RAISE NOTICE 'Inserted location for park_submission_id=%: %', + v_park_submission_id, v_temp_location->>'name'; + END IF; + + ELSIF v_item_type IN ('manufacturer', 'operator', 'property_owner', 'designer') THEN + INSERT INTO company_submissions ( + submission_id, name, slug, description, company_type, person_type, + founded_year, founded_date, founded_date_precision, + headquarters_location, website_url, logo_url, + banner_image_url, banner_image_id, card_image_url, card_image_id + ) VALUES ( + v_submission_id, + v_item_data->>'name', + v_item_data->>'slug', + v_item_data->>'description', + v_item_type, + COALESCE(v_item_data->>'person_type', 'company'), + (v_item_data->>'founded_year')::INTEGER, + (v_item_data->>'founded_date')::DATE, + v_item_data->>'founded_date_precision', + v_item_data->>'headquarters_location', + v_item_data->>'website_url', + v_item_data->>'logo_url', + v_item_data->>'banner_image_url', + v_item_data->>'banner_image_id', + v_item_data->>'card_image_url', + v_item_data->>'card_image_id' + ) RETURNING id INTO v_company_submission_id; + + ELSIF v_item_type = 'ride' THEN + INSERT INTO ride_submissions ( + submission_id, name, slug, description, category, status, + park_id, manufacturer_id, designer_id, ride_model_id, + opening_date, opening_date_precision, closing_date, closing_date_precision, + height_requirement_cm, age_requirement, max_speed_kmh, duration_seconds, + capacity_per_hour, gforce_max, inversions_count, length_meters, + height_meters, drop_meters, + banner_image_url, banner_image_id, card_image_url, card_image_id, image_url, + ride_sub_type, coaster_type, seating_type, intensity_level + ) VALUES ( + v_submission_id, + v_item_data->>'name', + v_item_data->>'slug', + v_item_data->>'description', + v_item_data->>'category', + v_item_data->>'status', + (v_item_data->>'park_id')::UUID, + (v_item_data->>'manufacturer_id')::UUID, + (v_item_data->>'designer_id')::UUID, + (v_item_data->>'ride_model_id')::UUID, + (v_item_data->>'opening_date')::DATE, + v_item_data->>'opening_date_precision', + (v_item_data->>'closing_date')::DATE, + v_item_data->>'closing_date_precision', + (v_item_data->>'height_requirement_cm')::NUMERIC, + (v_item_data->>'age_requirement')::INTEGER, + (v_item_data->>'max_speed_kmh')::NUMERIC, + (v_item_data->>'duration_seconds')::INTEGER, + (v_item_data->>'capacity_per_hour')::INTEGER, + (v_item_data->>'gforce_max')::NUMERIC, + (v_item_data->>'inversions_count')::INTEGER, + (v_item_data->>'length_meters')::NUMERIC, + (v_item_data->>'height_meters')::NUMERIC, + (v_item_data->>'drop_meters')::NUMERIC, + v_item_data->>'banner_image_url', + v_item_data->>'banner_image_id', + v_item_data->>'card_image_url', + v_item_data->>'card_image_id', + v_item_data->>'image_url', + v_item_data->>'ride_sub_type', + v_item_data->>'coaster_type', + v_item_data->>'seating_type', + v_item_data->>'intensity_level' + ) RETURNING id INTO v_ride_submission_id; + + ELSIF v_item_type = 'ride_model' THEN + INSERT INTO ride_model_submissions ( + submission_id, name, slug, manufacturer_id, category, ride_type, description, + banner_image_url, banner_image_id, card_image_url, card_image_id + ) VALUES ( + v_submission_id, + v_item_data->>'name', + v_item_data->>'slug', + (v_item_data->>'manufacturer_id')::UUID, + v_item_data->>'category', + v_item_data->>'ride_type', + v_item_data->>'description', + v_item_data->>'banner_image_url', + v_item_data->>'banner_image_id', + v_item_data->>'card_image_url', + v_item_data->>'card_image_id' + ) RETURNING id INTO v_ride_model_submission_id; + + ELSIF v_item_type = 'photo' THEN + INSERT INTO photo_submissions ( + submission_id, entity_type, entity_id, title + ) VALUES ( + v_submission_id, + v_item_data->>'entity_type', + (v_item_data->>'entity_id')::UUID, + v_item_data->>'title' + ) RETURNING id INTO v_photo_submission_id; + + ELSIF v_item_type IN ('timeline_event', 'milestone') THEN + INSERT INTO timeline_event_submissions ( + submission_id, entity_type, entity_id, event_type, event_date, + event_date_precision, title, description + ) VALUES ( + v_submission_id, + v_item_data->>'entity_type', + (v_item_data->>'entity_id')::UUID, + v_item_data->>'event_type', + (v_item_data->>'event_date')::DATE, + v_item_data->>'event_date_precision', + v_item_data->>'title', + v_item_data->>'description' + ) RETURNING id INTO v_timeline_event_submission_id; + END IF; + + INSERT INTO submission_items ( + submission_id, + item_type, + action_type, + park_submission_id, + company_submission_id, + ride_submission_id, + ride_model_submission_id, + photo_submission_id, + timeline_event_submission_id, + status, + order_index, + depends_on + ) VALUES ( + v_submission_id, + v_item_type, + v_action_type, + v_park_submission_id, + v_company_submission_id, + v_ride_submission_id, + v_ride_model_submission_id, + v_photo_submission_id, + v_timeline_event_submission_id, + 'pending', + COALESCE((v_item->>'order_index')::INTEGER, 0), + (v_item->>'depends_on')::UUID + ) RETURNING id INTO v_submission_item_id; + + IF v_item_data IS NOT NULL AND jsonb_typeof(v_item_data) = 'object' THEN + FOR v_temp_ref_key, v_temp_ref_value IN + SELECT key, value::text + FROM jsonb_each_text(v_item_data) + WHERE key LIKE '_temp_%_ref' + AND value ~ '^\d+$' + LOOP + BEGIN + v_ref_type := substring(v_temp_ref_key from '_temp_(.+)_ref'); + v_ref_order_index := v_temp_ref_value::INTEGER; + + INSERT INTO submission_item_temp_refs ( + submission_item_id, + ref_type, + ref_order_index + ) VALUES ( + v_submission_item_id, + v_ref_type, + v_ref_order_index + ); + + RAISE NOTICE 'Stored temp ref: item_id=%, ref_type=%, order_index=%', + v_submission_item_id, v_ref_type, v_ref_order_index; + EXCEPTION + WHEN OTHERS THEN + RAISE WARNING 'Failed to store temp ref % for item %: %', + v_temp_ref_key, v_submission_item_id, SQLERRM; + END; + END LOOP; + END IF; + + END LOOP; + + PERFORM set_config('app.current_user_id', '', true); + PERFORM set_config('app.submission_id', '', true); + + RETURN v_submission_id; + +EXCEPTION + WHEN OTHERS THEN + PERFORM set_config('app.current_user_id', '', true); + PERFORM set_config('app.submission_id', '', true); + + RAISE NOTICE 'Submission creation failed for user % (type=%): %', p_user_id, p_submission_type, SQLERRM; + RAISE; +END; +$$; + +COMMENT ON FUNCTION public.create_submission_with_items(uuid, text, jsonb, jsonb[]) IS +'Creates submission with items. Uses relational park_submission_locations table instead of temp_location_data JSONB column.'; \ No newline at end of file