Download sql/create_tables.sql from HydraBolt/SanadLLM: direct link, hf CLI and curl.
- Browser
- Download file 8.42 kB
-
https://huggingface.co/spaces/HydraBolt/SanadLLM/resolve/main/sql/create_tables.sql
- Command line
-
hf download hf://spaces/HydraBolt/SanadLLM/sql/create_tables.sql
-
curl -L -o create_tables.sql https://huggingface.co/spaces/HydraBolt/SanadLLM/resolve/main/sql/create_tables.sql
8.42 kB
| -- Supabase Database Schema for SanadCheck LLM API | |
| -- Execute these scripts in your Supabase SQL Editor | |
| -- Enable necessary extensions | |
| CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; | |
| -- Create custom user roles enum | |
| CREATE TYPE user_role AS ENUM ('user', 'admin', 'researcher'); | |
| -- Create users table (extends Supabase auth.users) | |
| CREATE TABLE IF NOT EXISTS public.users ( | |
| id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE, | |
| email TEXT UNIQUE NOT NULL, | |
| username TEXT UNIQUE, | |
| full_name TEXT, | |
| role user_role DEFAULT 'user'::user_role, | |
| is_active BOOLEAN DEFAULT TRUE, | |
| created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), | |
| updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), | |
| last_login TIMESTAMP WITH TIME ZONE, | |
| -- Constraints | |
| CONSTRAINT valid_email CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'), | |
| CONSTRAINT username_length CHECK (length(username) >= 3 AND length(username) <= 50), | |
| CONSTRAINT full_name_length CHECK (length(full_name) <= 100) | |
| ); | |
| -- Create user_sessions table for JWT session management | |
| CREATE TABLE IF NOT EXISTS public.user_sessions ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, | |
| access_token TEXT NOT NULL, | |
| refresh_token TEXT, | |
| expires_at TIMESTAMP WITH TIME ZONE NOT NULL, | |
| created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), | |
| last_used TIMESTAMP WITH TIME ZONE DEFAULT NOW(), | |
| ended_at TIMESTAMP WITH TIME ZONE, | |
| user_agent TEXT, | |
| ip_address INET, | |
| -- Indexes for performance | |
| CONSTRAINT unique_access_token UNIQUE (access_token) | |
| ); | |
| -- Create narrator_extractions table for storing extraction results | |
| CREATE TABLE IF NOT EXISTS public.narrator_extractions ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, | |
| session_id UUID REFERENCES public.user_sessions(id) ON DELETE SET NULL, | |
| hadith_text TEXT NOT NULL, | |
| extracted_narrators TEXT[] NOT NULL DEFAULT '{}', | |
| sanad_chain TEXT NOT NULL, | |
| success BOOLEAN NOT NULL DEFAULT FALSE, | |
| error_message TEXT, | |
| processing_time_ms INTEGER, | |
| created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), | |
| ip_address INET, | |
| -- Constraints | |
| CONSTRAINT hadith_text_not_empty CHECK (length(trim(hadith_text)) > 0), | |
| CONSTRAINT processing_time_positive CHECK (processing_time_ms IS NULL OR processing_time_ms >= 0) | |
| ); | |
| -- Create narrator_analyses table for storing individual narrator analysis results | |
| CREATE TABLE IF NOT EXISTS public.narrator_analyses ( | |
| id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), | |
| user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, | |
| extraction_id UUID REFERENCES public.narrator_extractions(id) ON DELETE SET NULL, | |
| narrator_name TEXT NOT NULL, | |
| reliability_grade TEXT NOT NULL, | |
| confidence_level TEXT NOT NULL, | |
| reasoning TEXT NOT NULL, | |
| scholarly_consensus TEXT NOT NULL, | |
| known_issues TEXT, | |
| biographical_info TEXT NOT NULL, | |
| recommendation TEXT NOT NULL, | |
| success BOOLEAN NOT NULL DEFAULT FALSE, | |
| error_message TEXT, | |
| processing_time_ms INTEGER, | |
| created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), | |
| -- Constraints | |
| CONSTRAINT narrator_name_not_empty CHECK (length(trim(narrator_name)) > 0), | |
| CONSTRAINT reliability_grade_valid CHECK (reliability_grade IN ('Thiqah', 'Saduq', 'Da''if', 'Matruk', 'Majhul')), | |
| CONSTRAINT confidence_level_valid CHECK (confidence_level IN ('High', 'Medium', 'Low')), | |
| CONSTRAINT processing_time_positive CHECK (processing_time_ms IS NULL OR processing_time_ms >= 0) | |
| ); | |
| -- Create indexes for better performance | |
| CREATE INDEX IF NOT EXISTS idx_user_sessions_user_id ON public.user_sessions(user_id); | |
| CREATE INDEX IF NOT EXISTS idx_user_sessions_access_token ON public.user_sessions(access_token); | |
| CREATE INDEX IF NOT EXISTS idx_user_sessions_expires_at ON public.user_sessions(expires_at); | |
| CREATE INDEX IF NOT EXISTS idx_user_sessions_active ON public.user_sessions(user_id) WHERE ended_at IS NULL; | |
| CREATE INDEX IF NOT EXISTS idx_narrator_extractions_user_id ON public.narrator_extractions(user_id); | |
| CREATE INDEX IF NOT EXISTS idx_narrator_extractions_created_at ON public.narrator_extractions(created_at); | |
| CREATE INDEX IF NOT EXISTS idx_narrator_extractions_success ON public.narrator_extractions(success); | |
| CREATE INDEX IF NOT EXISTS idx_narrator_analyses_user_id ON public.narrator_analyses(user_id); | |
| CREATE INDEX IF NOT EXISTS idx_narrator_analyses_extraction_id ON public.narrator_analyses(extraction_id); | |
| CREATE INDEX IF NOT EXISTS idx_narrator_analyses_narrator_name ON public.narrator_analyses(narrator_name); | |
| CREATE INDEX IF NOT EXISTS idx_narrator_analyses_created_at ON public.narrator_analyses(created_at); | |
| -- Create updated_at trigger function | |
| CREATE OR REPLACE FUNCTION public.update_updated_at_column() | |
| RETURNS TRIGGER AS $$ | |
| BEGIN | |
| NEW.updated_at = NOW(); | |
| RETURN NEW; | |
| END; | |
| $$ language 'plpgsql'; | |
| -- Add updated_at trigger to users table | |
| CREATE TRIGGER update_users_updated_at | |
| BEFORE UPDATE ON public.users | |
| FOR EACH ROW | |
| EXECUTE FUNCTION public.update_updated_at_column(); | |
| -- Row Level Security (RLS) Policies | |
| -- Enable RLS on all tables | |
| ALTER TABLE public.users ENABLE ROW LEVEL SECURITY; | |
| ALTER TABLE public.user_sessions ENABLE ROW LEVEL SECURITY; | |
| ALTER TABLE public.narrator_extractions ENABLE ROW LEVEL SECURITY; | |
| ALTER TABLE public.narrator_analyses ENABLE ROW LEVEL SECURITY; | |
| -- Users table policies | |
| CREATE POLICY "Users can view own profile" ON public.users | |
| FOR SELECT USING (auth.uid() = id); | |
| CREATE POLICY "Users can update own profile" ON public.users | |
| FOR UPDATE USING (auth.uid() = id); | |
| CREATE POLICY "Service role can manage all users" ON public.users | |
| FOR ALL USING (auth.role() = 'service_role'); | |
| -- User sessions policies | |
| CREATE POLICY "Users can view own sessions" ON public.user_sessions | |
| FOR SELECT USING (auth.uid() = user_id); | |
| CREATE POLICY "Service role can manage all sessions" ON public.user_sessions | |
| FOR ALL USING (auth.role() = 'service_role'); | |
| -- Narrator extractions policies | |
| CREATE POLICY "Users can view own extractions" ON public.narrator_extractions | |
| FOR SELECT USING (auth.uid() = user_id); | |
| CREATE POLICY "Users can insert own extractions" ON public.narrator_extractions | |
| FOR INSERT WITH CHECK (auth.uid() = user_id); | |
| CREATE POLICY "Service role can manage all extractions" ON public.narrator_extractions | |
| FOR ALL USING (auth.role() = 'service_role'); | |
| -- Narrator analyses policies | |
| CREATE POLICY "Users can view own analyses" ON public.narrator_analyses | |
| FOR SELECT USING (auth.uid() = user_id); | |
| CREATE POLICY "Users can insert own analyses" ON public.narrator_analyses | |
| FOR INSERT WITH CHECK (auth.uid() = user_id); | |
| CREATE POLICY "Service role can manage all analyses" ON public.narrator_analyses | |
| FOR ALL USING (auth.role() = 'service_role'); | |
| -- Grant necessary permissions | |
| GRANT USAGE ON SCHEMA public TO anon, authenticated; | |
| GRANT ALL ON ALL TABLES IN SCHEMA public TO anon, authenticated; | |
| GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO anon, authenticated; | |
| -- Create a function to automatically create user profile on signup | |
| CREATE OR REPLACE FUNCTION public.handle_new_user() | |
| RETURNS TRIGGER AS $$ | |
| BEGIN | |
| INSERT INTO public.users (id, email, username, full_name) | |
| VALUES ( | |
| NEW.id, | |
| NEW.email, | |
| COALESCE(NEW.raw_user_meta_data->>'username', NULL), | |
| COALESCE(NEW.raw_user_meta_data->>'full_name', NULL) | |
| ); | |
| RETURN NEW; | |
| END; | |
| $$ LANGUAGE plpgsql SECURITY DEFINER; | |
| -- Create trigger to run the function on new user signup | |
| CREATE TRIGGER on_auth_user_created | |
| AFTER INSERT ON auth.users | |
| FOR EACH ROW EXECUTE FUNCTION public.handle_new_user(); | |
| -- Create a view for user analytics | |
| CREATE VIEW public.user_analytics AS | |
| SELECT | |
| u.id, | |
| u.email, | |
| u.role, | |
| u.created_at, | |
| u.last_login, | |
| COUNT(ne.id) as total_extractions, | |
| COUNT(na.id) as total_analyses, | |
| COUNT(us.id) as total_sessions | |
| FROM public.users u | |
| LEFT JOIN public.narrator_extractions ne ON u.id = ne.user_id | |
| LEFT JOIN public.narrator_analyses na ON u.id = na.user_id | |
| LEFT JOIN public.user_sessions us ON u.id = us.user_id | |
| GROUP BY u.id, u.email, u.role, u.created_at, u.last_login; | |
| -- Grant select on the view | |
| GRANT SELECT ON public.user_analytics TO authenticated; | |