144 lines
3.9 KiB
SQL
144 lines
3.9 KiB
SQL
-- =====================================================
|
|
-- Data Integrity Constraints for Courses, Events, Bookings
|
|
--
|
|
-- Adds CHECK constraints and partial unique indexes to
|
|
-- enforce business rules at the database level.
|
|
--
|
|
-- All constraint additions are idempotent — wrapped in
|
|
-- DO blocks that check pg_constraint before adding.
|
|
-- =====================================================
|
|
|
|
-- -------------------------------------------------------
|
|
-- COURSES
|
|
-- -------------------------------------------------------
|
|
|
|
-- reduced_fee must not exceed fee
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM pg_constraint WHERE conname = 'chk_courses_reduced_fee_lte_fee'
|
|
) THEN
|
|
ALTER TABLE public.courses
|
|
ADD CONSTRAINT chk_courses_reduced_fee_lte_fee
|
|
CHECK (reduced_fee IS NULL OR reduced_fee <= fee);
|
|
END IF;
|
|
END;
|
|
$$;
|
|
|
|
-- min_participants must not exceed capacity
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM pg_constraint WHERE conname = 'chk_courses_min_lte_capacity'
|
|
) THEN
|
|
ALTER TABLE public.courses
|
|
ADD CONSTRAINT chk_courses_min_lte_capacity
|
|
CHECK (min_participants IS NULL OR min_participants <= capacity);
|
|
END IF;
|
|
END;
|
|
$$;
|
|
|
|
-- end_date must be on or after start_date
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM pg_constraint WHERE conname = 'chk_courses_date_range'
|
|
) THEN
|
|
ALTER TABLE public.courses
|
|
ADD CONSTRAINT chk_courses_date_range
|
|
CHECK (end_date IS NULL OR start_date IS NULL OR end_date >= start_date);
|
|
END IF;
|
|
END;
|
|
$$;
|
|
|
|
-- registration_deadline must be on or before start_date
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM pg_constraint WHERE conname = 'chk_courses_deadline_before_start'
|
|
) THEN
|
|
ALTER TABLE public.courses
|
|
ADD CONSTRAINT chk_courses_deadline_before_start
|
|
CHECK (registration_deadline IS NULL OR start_date IS NULL OR registration_deadline <= start_date);
|
|
END IF;
|
|
END;
|
|
$$;
|
|
|
|
-- Unique course_number per account (partial index — allows NULLs and empty strings)
|
|
CREATE UNIQUE INDEX IF NOT EXISTS uix_courses_number_per_account
|
|
ON public.courses(account_id, course_number)
|
|
WHERE course_number IS NOT NULL AND course_number != '';
|
|
|
|
-- -------------------------------------------------------
|
|
-- EVENTS
|
|
-- -------------------------------------------------------
|
|
|
|
-- min_age must not exceed max_age
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM pg_constraint WHERE conname = 'chk_events_age_range'
|
|
) THEN
|
|
ALTER TABLE public.events
|
|
ADD CONSTRAINT chk_events_age_range
|
|
CHECK (min_age IS NULL OR max_age IS NULL OR min_age <= max_age);
|
|
END IF;
|
|
END;
|
|
$$;
|
|
|
|
-- end_date must be on or after event_date
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM pg_constraint WHERE conname = 'chk_events_date_range'
|
|
) THEN
|
|
ALTER TABLE public.events
|
|
ADD CONSTRAINT chk_events_date_range
|
|
CHECK (end_date IS NULL OR end_date >= event_date);
|
|
END IF;
|
|
END;
|
|
$$;
|
|
|
|
-- registration_deadline must be on or before event_date
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM pg_constraint WHERE conname = 'chk_events_deadline_before_event'
|
|
) THEN
|
|
ALTER TABLE public.events
|
|
ADD CONSTRAINT chk_events_deadline_before_event
|
|
CHECK (registration_deadline IS NULL OR registration_deadline <= event_date);
|
|
END IF;
|
|
END;
|
|
$$;
|
|
|
|
-- -------------------------------------------------------
|
|
-- BOOKINGS
|
|
-- -------------------------------------------------------
|
|
|
|
-- At least 1 adult required
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM pg_constraint WHERE conname = 'chk_bookings_min_adults'
|
|
) THEN
|
|
ALTER TABLE public.bookings
|
|
ADD CONSTRAINT chk_bookings_min_adults
|
|
CHECK (adults >= 1);
|
|
END IF;
|
|
END;
|
|
$$;
|
|
|
|
-- total_price must be non-negative
|
|
DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM pg_constraint WHERE conname = 'chk_bookings_price_non_negative'
|
|
) THEN
|
|
ALTER TABLE public.bookings
|
|
ADD CONSTRAINT chk_bookings_price_non_negative
|
|
CHECK (total_price >= 0);
|
|
END IF;
|
|
END;
|
|
$$;
|