62 lines
2.3 KiB
SQL
62 lines
2.3 KiB
SQL
-- =====================================================
|
|
-- Missing Database Constraints
|
|
--
|
|
-- Adds CHECK constraints for data sanity, UNIQUE index
|
|
-- for email per account, and IBAN format validation.
|
|
--
|
|
-- Fixes existing invalid data before adding constraints.
|
|
-- =====================================================
|
|
|
|
-- Fix existing invalid data before adding constraints
|
|
UPDATE public.members SET date_of_birth = NULL
|
|
WHERE date_of_birth IS NOT NULL AND date_of_birth > current_date;
|
|
|
|
UPDATE public.members SET exit_date = entry_date
|
|
WHERE exit_date IS NOT NULL AND entry_date IS NOT NULL AND exit_date < entry_date;
|
|
|
|
UPDATE public.members SET entry_date = current_date
|
|
WHERE entry_date IS NOT NULL AND entry_date > current_date;
|
|
|
|
-- Normalize IBANs in sepa_mandates to uppercase, strip spaces
|
|
UPDATE public.sepa_mandates
|
|
SET iban = upper(regexp_replace(iban, '\s', '', 'g'))
|
|
WHERE iban IS NOT NULL AND iban != '';
|
|
|
|
-- Date sanity constraints
|
|
ALTER TABLE public.members
|
|
ADD CONSTRAINT chk_members_dob_not_future
|
|
CHECK (date_of_birth IS NULL OR date_of_birth <= current_date);
|
|
|
|
ALTER TABLE public.members
|
|
ADD CONSTRAINT chk_members_exit_after_entry
|
|
CHECK (exit_date IS NULL OR entry_date IS NULL OR exit_date >= entry_date);
|
|
|
|
ALTER TABLE public.members
|
|
ADD CONSTRAINT chk_members_entry_not_future
|
|
CHECK (entry_date IS NULL OR entry_date <= current_date);
|
|
|
|
-- Email uniqueness per account (partial index — allows NULLs and empty strings)
|
|
CREATE UNIQUE INDEX IF NOT EXISTS uix_members_email_per_account
|
|
ON public.members(account_id, lower(email))
|
|
WHERE email IS NOT NULL AND email != '';
|
|
|
|
-- IBAN format on sepa_mandates (2-letter country + 2 check digits + 11-30 alphanumeric)
|
|
ALTER TABLE public.sepa_mandates
|
|
ADD CONSTRAINT chk_sepa_iban_format
|
|
CHECK (iban ~ '^[A-Z]{2}[0-9]{2}[A-Z0-9]{11,30}$');
|
|
|
|
-- Mandate reference must not be empty
|
|
ALTER TABLE public.sepa_mandates
|
|
ADD CONSTRAINT chk_sepa_mandate_reference_not_empty
|
|
CHECK (mandate_reference IS NOT NULL AND mandate_reference != '');
|
|
|
|
-- Member roles: from_date should not be after until_date
|
|
ALTER TABLE public.member_roles
|
|
ADD CONSTRAINT chk_member_roles_date_range
|
|
CHECK (until_date IS NULL OR from_date IS NULL OR until_date >= from_date);
|
|
|
|
-- Dues categories: amount must be non-negative
|
|
ALTER TABLE public.dues_categories
|
|
ADD CONSTRAINT chk_dues_amount_non_negative
|
|
CHECK (amount >= 0);
|