chore: sync current workspace to dev
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
"""bind_profiles_to_auth_users
|
||||
|
||||
Revision ID: 20260224_bind_profiles_auth
|
||||
Revises: 85d25a191d06
|
||||
Create Date: 2026-02-24 17:55:00.000000
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "20260224_bind_profiles_auth"
|
||||
down_revision: Union[str, Sequence[str], None] = "85d25a191d06"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# Remove orphan profiles that are not backed by auth.users.
|
||||
# This guarantees FK creation will not fail on historical inconsistent data.
|
||||
op.execute(
|
||||
"""
|
||||
DELETE FROM public.profiles p
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM auth.users u
|
||||
WHERE u.id = p.id
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
# Backfill profile rows for existing auth users.
|
||||
op.execute(
|
||||
"""
|
||||
INSERT INTO public.profiles (id, username, display_name)
|
||||
SELECT
|
||||
u.id,
|
||||
'user_' || substr(replace(u.id::text, '-', ''), 1, 25),
|
||||
COALESCE(
|
||||
NULLIF(u.raw_user_meta_data->>'display_name', ''),
|
||||
NULLIF(u.raw_user_meta_data->>'full_name', '')
|
||||
)
|
||||
FROM auth.users u
|
||||
LEFT JOIN public.profiles p ON p.id = u.id
|
||||
WHERE p.id IS NULL
|
||||
"""
|
||||
)
|
||||
|
||||
# Enforce one-to-one binding between profiles.id and auth.users.id.
|
||||
op.execute(
|
||||
"""
|
||||
ALTER TABLE public.profiles
|
||||
ADD CONSTRAINT fk_profiles_id_auth_users
|
||||
FOREIGN KEY (id) REFERENCES auth.users(id)
|
||||
ON DELETE CASCADE
|
||||
"""
|
||||
)
|
||||
|
||||
# Auto-create profile rows when new auth users are registered.
|
||||
op.execute(
|
||||
"""
|
||||
CREATE OR REPLACE FUNCTION public.create_profile_for_new_user()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
AS $$
|
||||
BEGIN
|
||||
INSERT INTO public.profiles (id, username, display_name)
|
||||
VALUES (
|
||||
NEW.id,
|
||||
'user_' || substr(replace(NEW.id::text, '-', ''), 1, 25),
|
||||
COALESCE(
|
||||
NULLIF(NEW.raw_user_meta_data->>'display_name', ''),
|
||||
NULLIF(NEW.raw_user_meta_data->>'full_name', '')
|
||||
)
|
||||
)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
"""
|
||||
)
|
||||
|
||||
op.execute(
|
||||
"""
|
||||
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users
|
||||
"""
|
||||
)
|
||||
op.execute(
|
||||
"""
|
||||
CREATE TRIGGER on_auth_user_created
|
||||
AFTER INSERT ON auth.users
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.create_profile_for_new_user()
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.execute("DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users")
|
||||
op.execute("DROP FUNCTION IF EXISTS public.create_profile_for_new_user()")
|
||||
op.execute(
|
||||
"""
|
||||
ALTER TABLE public.profiles
|
||||
DROP CONSTRAINT IF EXISTS fk_profiles_id_auth_users
|
||||
"""
|
||||
)
|
||||
Reference in New Issue
Block a user