-- Customer favorites: one row per (user, product) or (user, shop). -- Two nullable FKs plus a check keep the target shape honest; partial unique -- indexes enforce uniqueness without letting NULL shop/product repeat. CREATE TABLE favorites ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES users (id) ON DELETE CASCADE, product_id UUID REFERENCES products (id) ON DELETE CASCADE, shop_id UUID REFERENCES shops (id) ON DELETE CASCADE, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), CONSTRAINT favorites_exactly_one_target CHECK ( (product_id IS NOT NULL AND shop_id IS NULL) OR (product_id IS NULL AND shop_id IS NOT NULL) ) ); CREATE INDEX favorites_user_created_idx ON favorites (user_id, created_at DESC); CREATE UNIQUE INDEX favorites_user_product_idx ON favorites (user_id, product_id) WHERE product_id IS NOT NULL; CREATE UNIQUE INDEX favorites_user_shop_idx ON favorites (user_id, shop_id) WHERE shop_id IS NOT NULL;