Update session summary and clean up unused files
- Added additional notes to SESSION_SUMMARY.md regarding MQTT debugging and enhanced logging. - Removed outdated SQL seed files related to Phase 2 JC Experiments and Meyer Experiments to streamline the codebase. - Updated the CLI version in the Supabase configuration for consistency. - Cleaned up test files in the camera management API to improve maintainability.
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
-- Extensions and Utility Functions
|
||||
-- This migration creates required extensions and utility functions used across the database
|
||||
|
||||
-- =============================================
|
||||
-- 1. EXTENSIONS
|
||||
-- =============================================
|
||||
|
||||
-- Enable UUID generation
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- Enable password hashing
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||||
|
||||
-- =============================================
|
||||
-- 2. UTILITY FUNCTIONS
|
||||
-- =============================================
|
||||
|
||||
-- Function to handle updated_at timestamp
|
||||
CREATE OR REPLACE FUNCTION public.handle_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Helper function to get current user's roles
|
||||
CREATE OR REPLACE FUNCTION public.get_user_roles()
|
||||
RETURNS TEXT[] AS $$
|
||||
BEGIN
|
||||
RETURN ARRAY(
|
||||
SELECT r.name
|
||||
FROM public.user_roles ur
|
||||
JOIN public.roles r ON ur.role_id = r.id
|
||||
WHERE ur.user_id = auth.uid()
|
||||
);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- Helper function to get current user's first role (for backward compatibility)
|
||||
CREATE OR REPLACE FUNCTION public.get_user_role()
|
||||
RETURNS TEXT AS $$
|
||||
BEGIN
|
||||
-- Return the first role found (for backward compatibility)
|
||||
RETURN (
|
||||
SELECT r.name
|
||||
FROM public.user_roles ur
|
||||
JOIN public.roles r ON ur.role_id = r.id
|
||||
WHERE ur.user_id = auth.uid()
|
||||
LIMIT 1
|
||||
);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- Helper function to check if user is admin
|
||||
CREATE OR REPLACE FUNCTION public.is_admin()
|
||||
RETURNS BOOLEAN AS $$
|
||||
BEGIN
|
||||
RETURN 'admin' = ANY(public.get_user_roles());
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- Helper function to check if user has specific role
|
||||
CREATE OR REPLACE FUNCTION public.has_role(role_name TEXT)
|
||||
RETURNS BOOLEAN AS $$
|
||||
BEGIN
|
||||
RETURN role_name = ANY(public.get_user_roles());
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- Helper function to check if user can manage experiments
|
||||
CREATE OR REPLACE FUNCTION public.can_manage_experiments()
|
||||
RETURNS BOOLEAN AS $$
|
||||
BEGIN
|
||||
RETURN EXISTS (
|
||||
SELECT 1
|
||||
FROM public.user_roles ur
|
||||
JOIN public.roles r ON ur.role_id = r.id
|
||||
WHERE ur.user_id = auth.uid()
|
||||
AND r.name IN ('admin', 'conductor')
|
||||
);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
|
||||
|
||||
@@ -1,21 +1,10 @@
|
||||
-- User Management and Authentication
|
||||
-- This migration creates user-related tables, roles, and authentication structures
|
||||
-- Users and Roles
|
||||
-- This migration creates user-related tables with clean separation
|
||||
|
||||
-- =============================================
|
||||
-- 1. EXTENSIONS
|
||||
-- 1. ROLES TABLE
|
||||
-- =============================================
|
||||
|
||||
-- Enable UUID generation
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- Enable password hashing
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||||
|
||||
-- =============================================
|
||||
-- 2. USER MANAGEMENT
|
||||
-- =============================================
|
||||
|
||||
-- Create roles table
|
||||
CREATE TABLE IF NOT EXISTS public.roles (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
@@ -24,7 +13,10 @@ CREATE TABLE IF NOT EXISTS public.roles (
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Create user profiles table
|
||||
-- =============================================
|
||||
-- 2. USER PROFILES TABLE
|
||||
-- =============================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.user_profiles (
|
||||
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
@@ -35,7 +27,10 @@ CREATE TABLE IF NOT EXISTS public.user_profiles (
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Create user roles junction table
|
||||
-- =============================================
|
||||
-- 3. USER ROLES JUNCTION TABLE
|
||||
-- =============================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.user_roles (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id UUID NOT NULL REFERENCES public.user_profiles(id) ON DELETE CASCADE,
|
||||
@@ -45,77 +40,6 @@ CREATE TABLE IF NOT EXISTS public.user_roles (
|
||||
UNIQUE(user_id, role_id)
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 3. UTILITY FUNCTIONS
|
||||
-- =============================================
|
||||
|
||||
-- Function to handle updated_at timestamp
|
||||
CREATE OR REPLACE FUNCTION public.handle_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Helper function to get current user's roles
|
||||
CREATE OR REPLACE FUNCTION public.get_user_roles()
|
||||
RETURNS TEXT[] AS $$
|
||||
BEGIN
|
||||
RETURN ARRAY(
|
||||
SELECT r.name
|
||||
FROM public.user_roles ur
|
||||
JOIN public.roles r ON ur.role_id = r.id
|
||||
WHERE ur.user_id = auth.uid()
|
||||
);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- Helper function to get current user's first role (for backward compatibility)
|
||||
CREATE OR REPLACE FUNCTION public.get_user_role()
|
||||
RETURNS TEXT AS $$
|
||||
BEGIN
|
||||
-- Return the first role found (for backward compatibility)
|
||||
RETURN (
|
||||
SELECT r.name
|
||||
FROM public.user_roles ur
|
||||
JOIN public.roles r ON ur.role_id = r.id
|
||||
WHERE ur.user_id = auth.uid()
|
||||
LIMIT 1
|
||||
);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- Helper function to check if user is admin
|
||||
CREATE OR REPLACE FUNCTION public.is_admin()
|
||||
RETURNS BOOLEAN AS $$
|
||||
BEGIN
|
||||
RETURN 'admin' = ANY(public.get_user_roles());
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- Helper function to check if user has specific role
|
||||
CREATE OR REPLACE FUNCTION public.has_role(role_name TEXT)
|
||||
RETURNS BOOLEAN AS $$
|
||||
BEGIN
|
||||
RETURN role_name = ANY(public.get_user_roles());
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- Helper function to check if user can manage experiments
|
||||
CREATE OR REPLACE FUNCTION public.can_manage_experiments()
|
||||
RETURNS BOOLEAN AS $$
|
||||
BEGIN
|
||||
RETURN EXISTS (
|
||||
SELECT 1
|
||||
FROM public.user_roles ur
|
||||
JOIN public.roles r ON ur.role_id = r.id
|
||||
WHERE ur.user_id = auth.uid()
|
||||
AND r.name IN ('admin', 'conductor')
|
||||
);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- =============================================
|
||||
-- 4. INDEXES FOR PERFORMANCE
|
||||
-- =============================================
|
||||
@@ -134,6 +58,12 @@ CREATE TRIGGER set_updated_at_user_profiles
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
-- Create trigger for updated_at on roles
|
||||
CREATE TRIGGER set_updated_at_roles
|
||||
BEFORE UPDATE ON public.roles
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
-- =============================================
|
||||
-- 6. GRANT PERMISSIONS
|
||||
-- =============================================
|
||||
@@ -186,4 +116,3 @@ CREATE POLICY "User roles are deletable by authenticated users" ON public.user_r
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
-- Machine Types
|
||||
-- This migration creates the machine types table
|
||||
|
||||
-- =============================================
|
||||
-- 1. MACHINE TYPES TABLE
|
||||
-- =============================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.machine_types (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
created_by UUID NOT NULL REFERENCES public.user_profiles(id)
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 2. INDEXES FOR PERFORMANCE
|
||||
-- =============================================
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_machine_types_name ON public.machine_types(name);
|
||||
|
||||
-- =============================================
|
||||
-- 3. TRIGGERS
|
||||
-- =============================================
|
||||
|
||||
-- Create trigger for updated_at on machine_types
|
||||
CREATE TRIGGER set_updated_at_machine_types
|
||||
BEFORE UPDATE ON public.machine_types
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
-- =============================================
|
||||
-- 4. GRANT PERMISSIONS
|
||||
-- =============================================
|
||||
|
||||
GRANT ALL ON public.machine_types TO authenticated;
|
||||
|
||||
-- =============================================
|
||||
-- 5. ENABLE ROW LEVEL SECURITY
|
||||
-- =============================================
|
||||
|
||||
ALTER TABLE public.machine_types ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- =============================================
|
||||
-- 6. CREATE RLS POLICIES
|
||||
-- =============================================
|
||||
|
||||
CREATE POLICY "Machine types are viewable by authenticated users" ON public.machine_types
|
||||
FOR SELECT USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Machine types are insertable by authenticated users" ON public.machine_types
|
||||
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Machine types are updatable by authenticated users" ON public.machine_types
|
||||
FOR UPDATE USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Machine types are deletable by authenticated users" ON public.machine_types
|
||||
FOR DELETE USING (auth.role() = 'authenticated');
|
||||
|
||||
|
||||
|
||||
@@ -1,25 +1,10 @@
|
||||
-- Machine Types and Experiment Phases
|
||||
-- This migration creates machine types and experiment phase definitions
|
||||
-- Experiment Phases
|
||||
-- This migration creates the experiment phases table
|
||||
|
||||
-- =============================================
|
||||
-- 1. MACHINE TYPES
|
||||
-- 1. EXPERIMENT PHASES TABLE
|
||||
-- =============================================
|
||||
|
||||
-- Create machine types table
|
||||
CREATE TABLE IF NOT EXISTS public.machine_types (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
created_by UUID NOT NULL REFERENCES public.user_profiles(id)
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 2. EXPERIMENT PHASES
|
||||
-- =============================================
|
||||
|
||||
-- Create experiment phases table
|
||||
CREATE TABLE IF NOT EXISTS public.experiment_phases (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
@@ -43,23 +28,16 @@ CREATE TABLE IF NOT EXISTS public.experiment_phases (
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 3. INDEXES FOR PERFORMANCE
|
||||
-- 2. INDEXES FOR PERFORMANCE
|
||||
-- =============================================
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_machine_types_name ON public.machine_types(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiment_phases_name ON public.experiment_phases(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiment_phases_cracking_machine_type_id ON public.experiment_phases(cracking_machine_type_id);
|
||||
|
||||
-- =============================================
|
||||
-- 4. TRIGGERS
|
||||
-- 3. TRIGGERS
|
||||
-- =============================================
|
||||
|
||||
-- Create trigger for updated_at on machine_types
|
||||
CREATE TRIGGER set_updated_at_machine_types
|
||||
BEFORE UPDATE ON public.machine_types
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
-- Create trigger for updated_at on experiment_phases
|
||||
CREATE TRIGGER set_updated_at_experiment_phases
|
||||
BEFORE UPDATE ON public.experiment_phases
|
||||
@@ -67,37 +45,21 @@ CREATE TRIGGER set_updated_at_experiment_phases
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
-- =============================================
|
||||
-- 5. GRANT PERMISSIONS
|
||||
-- 4. GRANT PERMISSIONS
|
||||
-- =============================================
|
||||
|
||||
GRANT ALL ON public.machine_types TO authenticated;
|
||||
GRANT ALL ON public.experiment_phases TO authenticated;
|
||||
|
||||
-- =============================================
|
||||
-- 6. ENABLE ROW LEVEL SECURITY
|
||||
-- 5. ENABLE ROW LEVEL SECURITY
|
||||
-- =============================================
|
||||
|
||||
ALTER TABLE public.machine_types ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.experiment_phases ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- =============================================
|
||||
-- 7. CREATE RLS POLICIES
|
||||
-- 6. CREATE RLS POLICIES
|
||||
-- =============================================
|
||||
|
||||
-- Create RLS policies for machine_types
|
||||
CREATE POLICY "Machine types are viewable by authenticated users" ON public.machine_types
|
||||
FOR SELECT USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Machine types are insertable by authenticated users" ON public.machine_types
|
||||
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Machine types are updatable by authenticated users" ON public.machine_types
|
||||
FOR UPDATE USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Machine types are deletable by authenticated users" ON public.machine_types
|
||||
FOR DELETE USING (auth.role() = 'authenticated');
|
||||
|
||||
-- Create RLS policies for experiment_phases
|
||||
CREATE POLICY "Experiment phases are viewable by authenticated users" ON public.experiment_phases
|
||||
FOR SELECT USING (auth.role() = 'authenticated');
|
||||
|
||||
@@ -112,4 +74,3 @@ CREATE POLICY "Experiment phases are deletable by authenticated users" ON public
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
-- Experiments
|
||||
-- This migration creates the experiments table
|
||||
|
||||
-- =============================================
|
||||
-- 1. EXPERIMENTS TABLE
|
||||
-- =============================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.experiments (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
experiment_number INTEGER NOT NULL,
|
||||
reps_required INTEGER NOT NULL CHECK (reps_required > 0),
|
||||
weight_per_repetition_lbs DOUBLE PRECISION NOT NULL DEFAULT 5.0 CHECK (weight_per_repetition_lbs > 0),
|
||||
results_status TEXT NOT NULL DEFAULT 'valid' CHECK (results_status IN ('valid', 'invalid')),
|
||||
completion_status BOOLEAN NOT NULL DEFAULT false,
|
||||
phase_id UUID NOT NULL REFERENCES public.experiment_phases(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
created_by UUID NOT NULL REFERENCES public.user_profiles(id)
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 2. INDEXES FOR PERFORMANCE
|
||||
-- =============================================
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_experiments_phase_id ON public.experiments(phase_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiments_experiment_number ON public.experiments(experiment_number);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiments_created_by ON public.experiments(created_by);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiments_id ON public.experiments(id);
|
||||
|
||||
-- =============================================
|
||||
-- 3. TRIGGERS
|
||||
-- =============================================
|
||||
|
||||
-- Create trigger for updated_at on experiments
|
||||
CREATE TRIGGER set_updated_at_experiments
|
||||
BEFORE UPDATE ON public.experiments
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
-- =============================================
|
||||
-- 4. GRANT PERMISSIONS
|
||||
-- =============================================
|
||||
|
||||
GRANT ALL ON public.experiments TO authenticated;
|
||||
|
||||
-- =============================================
|
||||
-- 5. ENABLE ROW LEVEL SECURITY
|
||||
-- =============================================
|
||||
|
||||
ALTER TABLE public.experiments ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- =============================================
|
||||
-- 6. CREATE RLS POLICIES
|
||||
-- =============================================
|
||||
|
||||
CREATE POLICY "Experiments are viewable by authenticated users" ON public.experiments
|
||||
FOR SELECT USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Experiments are insertable by authenticated users" ON public.experiments
|
||||
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Experiments are updatable by authenticated users" ON public.experiments
|
||||
FOR UPDATE USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Experiments are deletable by authenticated users" ON public.experiments
|
||||
FOR DELETE USING (auth.role() = 'authenticated');
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
-- Experiment Repetitions
|
||||
-- This migration creates the experiment repetitions table
|
||||
|
||||
-- =============================================
|
||||
-- 1. EXPERIMENT REPETITIONS TABLE
|
||||
-- =============================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.experiment_repetitions (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
experiment_id UUID NOT NULL REFERENCES public.experiments(id) ON DELETE CASCADE,
|
||||
repetition_number INTEGER NOT NULL CHECK (repetition_number > 0),
|
||||
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'in_progress', 'completed', 'cancelled')),
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
created_by UUID NOT NULL REFERENCES public.user_profiles(id),
|
||||
|
||||
-- Ensure unique repetition numbers per experiment
|
||||
UNIQUE(experiment_id, repetition_number)
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 2. INDEXES FOR PERFORMANCE
|
||||
-- =============================================
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_experiment_repetitions_experiment_id ON public.experiment_repetitions(experiment_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiment_repetitions_created_by ON public.experiment_repetitions(created_by);
|
||||
|
||||
-- =============================================
|
||||
-- 3. TRIGGERS
|
||||
-- =============================================
|
||||
|
||||
-- Create trigger for updated_at on experiment_repetitions
|
||||
CREATE TRIGGER set_updated_at_experiment_repetitions
|
||||
BEFORE UPDATE ON public.experiment_repetitions
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
-- =============================================
|
||||
-- 4. GRANT PERMISSIONS
|
||||
-- =============================================
|
||||
|
||||
GRANT ALL ON public.experiment_repetitions TO authenticated;
|
||||
|
||||
-- =============================================
|
||||
-- 5. ENABLE ROW LEVEL SECURITY
|
||||
-- =============================================
|
||||
|
||||
ALTER TABLE public.experiment_repetitions ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- =============================================
|
||||
-- 6. CREATE RLS POLICIES
|
||||
-- =============================================
|
||||
|
||||
CREATE POLICY "Experiment repetitions are viewable by authenticated users" ON public.experiment_repetitions
|
||||
FOR SELECT USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Experiment repetitions are insertable by authenticated users" ON public.experiment_repetitions
|
||||
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Experiment repetitions are updatable by authenticated users" ON public.experiment_repetitions
|
||||
FOR UPDATE USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Experiment repetitions are deletable by authenticated users" ON public.experiment_repetitions
|
||||
FOR DELETE USING (auth.role() = 'authenticated');
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
-- Cracker Parameters
|
||||
-- This migration creates machine-specific parameter tables (must be created before cracking table)
|
||||
|
||||
-- =============================================
|
||||
-- 1. JC CRACKER PARAMETERS TABLE
|
||||
-- =============================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.jc_cracker_parameters (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
plate_contact_frequency_hz DOUBLE PRECISION NOT NULL CHECK (plate_contact_frequency_hz > 0),
|
||||
throughput_rate_pecans_sec DOUBLE PRECISION NOT NULL CHECK (throughput_rate_pecans_sec > 0),
|
||||
crush_amount_in DOUBLE PRECISION NOT NULL CHECK (crush_amount_in >= 0),
|
||||
entry_exit_height_diff_in DOUBLE PRECISION NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 2. MEYER CRACKER PARAMETERS TABLE
|
||||
-- =============================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.meyer_cracker_parameters (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
motor_speed_hz DOUBLE PRECISION NOT NULL CHECK (motor_speed_hz > 0),
|
||||
jig_displacement_inches DOUBLE PRECISION NOT NULL,
|
||||
spring_stiffness_nm DOUBLE PRECISION NOT NULL CHECK (spring_stiffness_nm > 0),
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 3. TRIGGERS
|
||||
-- =============================================
|
||||
|
||||
CREATE TRIGGER set_updated_at_jc_cracker_parameters
|
||||
BEFORE UPDATE ON public.jc_cracker_parameters
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
CREATE TRIGGER set_updated_at_meyer_cracker_parameters
|
||||
BEFORE UPDATE ON public.meyer_cracker_parameters
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
-- =============================================
|
||||
-- 4. GRANT PERMISSIONS
|
||||
-- =============================================
|
||||
|
||||
GRANT ALL ON public.jc_cracker_parameters TO authenticated;
|
||||
GRANT ALL ON public.meyer_cracker_parameters TO authenticated;
|
||||
|
||||
-- =============================================
|
||||
-- 5. ENABLE ROW LEVEL SECURITY
|
||||
-- =============================================
|
||||
|
||||
ALTER TABLE public.jc_cracker_parameters ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.meyer_cracker_parameters ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- =============================================
|
||||
-- 6. CREATE RLS POLICIES
|
||||
-- =============================================
|
||||
|
||||
CREATE POLICY "JC Cracker parameters are viewable by authenticated users" ON public.jc_cracker_parameters
|
||||
FOR SELECT USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "JC Cracker parameters are insertable by authenticated users" ON public.jc_cracker_parameters
|
||||
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "JC Cracker parameters are updatable by authenticated users" ON public.jc_cracker_parameters
|
||||
FOR UPDATE USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "JC Cracker parameters are deletable by authenticated users" ON public.jc_cracker_parameters
|
||||
FOR DELETE USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Meyer Cracker parameters are viewable by authenticated users" ON public.meyer_cracker_parameters
|
||||
FOR SELECT USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Meyer Cracker parameters are insertable by authenticated users" ON public.meyer_cracker_parameters
|
||||
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Meyer Cracker parameters are updatable by authenticated users" ON public.meyer_cracker_parameters
|
||||
FOR UPDATE USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Meyer Cracker parameters are deletable by authenticated users" ON public.meyer_cracker_parameters
|
||||
FOR DELETE USING (auth.role() = 'authenticated');
|
||||
|
||||
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
-- Data Entry Tables
|
||||
-- This migration creates the phase-specific data entry tables (soaking, airdrying, cracking, shelling)
|
||||
-- Phase Data Tables
|
||||
-- This migration creates phase-specific data entry tables (soaking, airdrying, cracking, shelling)
|
||||
|
||||
-- =============================================
|
||||
-- 1. SOAKING TABLE
|
||||
-- =============================================
|
||||
|
||||
-- Create soaking table
|
||||
CREATE TABLE IF NOT EXISTS public.soaking (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
experiment_id UUID NOT NULL REFERENCES public.experiments(id) ON DELETE CASCADE,
|
||||
repetition_id UUID REFERENCES public.experiment_repetitions(id) ON DELETE CASCADE,
|
||||
scheduled_start_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
actual_start_time TIMESTAMP WITH TIME ZONE,
|
||||
soaking_duration_hours DOUBLE PRECISION NOT NULL CHECK (soaking_duration_hours > 0),
|
||||
soaking_duration_minutes INTEGER NOT NULL CHECK (soaking_duration_minutes > 0),
|
||||
scheduled_end_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
actual_end_time TIMESTAMP WITH TIME ZONE,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
@@ -28,7 +27,6 @@ CREATE TABLE IF NOT EXISTS public.soaking (
|
||||
-- 2. AIRDRYING TABLE
|
||||
-- =============================================
|
||||
|
||||
-- Create airdrying table
|
||||
CREATE TABLE IF NOT EXISTS public.airdrying (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
experiment_id UUID NOT NULL REFERENCES public.experiments(id) ON DELETE CASCADE,
|
||||
@@ -51,14 +49,11 @@ CREATE TABLE IF NOT EXISTS public.airdrying (
|
||||
-- 3. CRACKING TABLE
|
||||
-- =============================================
|
||||
|
||||
-- Create cracking table
|
||||
CREATE TABLE IF NOT EXISTS public.cracking (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
experiment_id UUID NOT NULL REFERENCES public.experiments(id) ON DELETE CASCADE,
|
||||
repetition_id UUID REFERENCES public.experiment_repetitions(id) ON DELETE CASCADE,
|
||||
machine_type_id UUID NOT NULL REFERENCES public.machine_types(id),
|
||||
jc_cracker_parameters_id UUID REFERENCES public.jc_cracker_parameters(id) ON DELETE SET NULL,
|
||||
meyer_cracker_parameters_id UUID REFERENCES public.meyer_cracker_parameters(id) ON DELETE SET NULL,
|
||||
scheduled_start_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
actual_start_time TIMESTAMP WITH TIME ZONE,
|
||||
actual_end_time TIMESTAMP WITH TIME ZONE,
|
||||
@@ -68,19 +63,13 @@ CREATE TABLE IF NOT EXISTS public.cracking (
|
||||
|
||||
-- Ensure only one cracking per experiment or repetition
|
||||
CONSTRAINT unique_cracking_per_experiment UNIQUE (experiment_id),
|
||||
CONSTRAINT unique_cracking_per_repetition UNIQUE (repetition_id),
|
||||
-- Ensure exactly one cracker parameter set is specified
|
||||
CONSTRAINT check_exactly_one_cracker_params CHECK (
|
||||
(jc_cracker_parameters_id IS NOT NULL AND meyer_cracker_parameters_id IS NULL) OR
|
||||
(jc_cracker_parameters_id IS NULL AND meyer_cracker_parameters_id IS NOT NULL)
|
||||
)
|
||||
CONSTRAINT unique_cracking_per_repetition UNIQUE (repetition_id)
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 4. SHELLING TABLE
|
||||
-- =============================================
|
||||
|
||||
-- Create shelling table
|
||||
CREATE TABLE IF NOT EXISTS public.shelling (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
experiment_id UUID NOT NULL REFERENCES public.experiments(id) ON DELETE CASCADE,
|
||||
@@ -98,38 +87,7 @@ CREATE TABLE IF NOT EXISTS public.shelling (
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 5. MACHINE-SPECIFIC PARAMETER TABLES
|
||||
-- =============================================
|
||||
|
||||
-- Create JC Cracker parameters table
|
||||
CREATE TABLE IF NOT EXISTS public.jc_cracker_parameters (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
plate_contact_frequency_hz DOUBLE PRECISION NOT NULL CHECK (plate_contact_frequency_hz > 0),
|
||||
throughput_rate_pecans_sec DOUBLE PRECISION NOT NULL CHECK (throughput_rate_pecans_sec > 0),
|
||||
crush_amount_in DOUBLE PRECISION NOT NULL CHECK (crush_amount_in >= 0),
|
||||
entry_exit_height_diff_in DOUBLE PRECISION NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Create Meyer Cracker parameters table
|
||||
CREATE TABLE IF NOT EXISTS public.meyer_cracker_parameters (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
motor_speed_hz DOUBLE PRECISION NOT NULL CHECK (motor_speed_hz > 0),
|
||||
jig_displacement_inches DOUBLE PRECISION NOT NULL,
|
||||
spring_stiffness_nm DOUBLE PRECISION NOT NULL CHECK (spring_stiffness_nm > 0),
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 6. EXPERIMENTS TABLE DOES NOT NEED FOREIGN KEYS TO PHASE TABLES
|
||||
-- =============================================
|
||||
-- Phase tables reference experiments via experiment_id
|
||||
-- Experiments inherit phase configuration from experiment_phases via phase_id
|
||||
|
||||
-- =============================================
|
||||
-- 7. INDEXES FOR PERFORMANCE
|
||||
-- 5. INDEXES FOR PERFORMANCE
|
||||
-- =============================================
|
||||
|
||||
-- Create indexes for experiment_id references
|
||||
@@ -154,25 +112,18 @@ CREATE INDEX IF NOT EXISTS idx_cracking_created_by ON public.cracking(created_by
|
||||
CREATE INDEX IF NOT EXISTS idx_shelling_created_by ON public.shelling(created_by);
|
||||
|
||||
-- =============================================
|
||||
-- 8. TRIGGERS FOR AUTOMATIC TIMESTAMP CALCULATIONS
|
||||
-- 6. TRIGGER FUNCTIONS FOR AUTOMATIC TIMESTAMP CALCULATIONS
|
||||
-- =============================================
|
||||
|
||||
-- Function to calculate scheduled end time for soaking
|
||||
CREATE OR REPLACE FUNCTION calculate_soaking_scheduled_end_time()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.scheduled_end_time = NEW.scheduled_start_time + (NEW.soaking_duration_hours || ' hours')::INTERVAL;
|
||||
NEW.scheduled_end_time = NEW.scheduled_start_time + (NEW.soaking_duration_minutes || ' minutes')::INTERVAL;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Trigger for soaking scheduled end time
|
||||
DROP TRIGGER IF EXISTS trigger_calculate_soaking_scheduled_end_time ON public.soaking;
|
||||
CREATE TRIGGER trigger_calculate_soaking_scheduled_end_time
|
||||
BEFORE INSERT OR UPDATE ON public.soaking
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION calculate_soaking_scheduled_end_time();
|
||||
|
||||
-- Function to calculate scheduled end time for airdrying
|
||||
CREATE OR REPLACE FUNCTION calculate_airdrying_scheduled_end_time()
|
||||
RETURNS TRIGGER AS $$
|
||||
@@ -182,13 +133,6 @@ BEGIN
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Trigger for airdrying scheduled end time
|
||||
DROP TRIGGER IF EXISTS trigger_calculate_airdrying_scheduled_end_time ON public.airdrying;
|
||||
CREATE TRIGGER trigger_calculate_airdrying_scheduled_end_time
|
||||
BEFORE INSERT OR UPDATE ON public.airdrying
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION calculate_airdrying_scheduled_end_time();
|
||||
|
||||
-- Function to set airdrying scheduled start time based on soaking end time
|
||||
CREATE OR REPLACE FUNCTION set_airdrying_scheduled_start_time()
|
||||
RETURNS TRIGGER AS $$
|
||||
@@ -205,13 +149,6 @@ BEGIN
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Trigger for airdrying scheduled start time
|
||||
DROP TRIGGER IF EXISTS trigger_set_airdrying_scheduled_start_time ON public.airdrying;
|
||||
CREATE TRIGGER trigger_set_airdrying_scheduled_start_time
|
||||
BEFORE INSERT ON public.airdrying
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_airdrying_scheduled_start_time();
|
||||
|
||||
-- Function to set cracking scheduled start time based on airdrying end time
|
||||
CREATE OR REPLACE FUNCTION set_cracking_scheduled_start_time()
|
||||
RETURNS TRIGGER AS $$
|
||||
@@ -228,18 +165,36 @@ BEGIN
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Trigger for cracking scheduled start time
|
||||
-- =============================================
|
||||
-- 7. TRIGGERS
|
||||
-- =============================================
|
||||
|
||||
-- Triggers for automatic timestamp calculations
|
||||
DROP TRIGGER IF EXISTS trigger_calculate_soaking_scheduled_end_time ON public.soaking;
|
||||
CREATE TRIGGER trigger_calculate_soaking_scheduled_end_time
|
||||
BEFORE INSERT OR UPDATE ON public.soaking
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION calculate_soaking_scheduled_end_time();
|
||||
|
||||
DROP TRIGGER IF EXISTS trigger_calculate_airdrying_scheduled_end_time ON public.airdrying;
|
||||
CREATE TRIGGER trigger_calculate_airdrying_scheduled_end_time
|
||||
BEFORE INSERT OR UPDATE ON public.airdrying
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION calculate_airdrying_scheduled_end_time();
|
||||
|
||||
DROP TRIGGER IF EXISTS trigger_set_airdrying_scheduled_start_time ON public.airdrying;
|
||||
CREATE TRIGGER trigger_set_airdrying_scheduled_start_time
|
||||
BEFORE INSERT ON public.airdrying
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_airdrying_scheduled_start_time();
|
||||
|
||||
DROP TRIGGER IF EXISTS trigger_set_cracking_scheduled_start_time ON public.cracking;
|
||||
CREATE TRIGGER trigger_set_cracking_scheduled_start_time
|
||||
BEFORE INSERT ON public.cracking
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION set_cracking_scheduled_start_time();
|
||||
|
||||
-- =============================================
|
||||
-- 9. TRIGGERS FOR UPDATED_AT
|
||||
-- =============================================
|
||||
|
||||
-- Create triggers for updated_at on all phase tables
|
||||
-- Triggers for updated_at on all phase tables
|
||||
CREATE TRIGGER set_updated_at_soaking
|
||||
BEFORE UPDATE ON public.soaking
|
||||
FOR EACH ROW
|
||||
@@ -260,40 +215,26 @@ CREATE TRIGGER set_updated_at_shelling
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
CREATE TRIGGER set_updated_at_jc_cracker_parameters
|
||||
BEFORE UPDATE ON public.jc_cracker_parameters
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
CREATE TRIGGER set_updated_at_meyer_cracker_parameters
|
||||
BEFORE UPDATE ON public.meyer_cracker_parameters
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
-- =============================================
|
||||
-- 10. GRANT PERMISSIONS
|
||||
-- 8. GRANT PERMISSIONS
|
||||
-- =============================================
|
||||
|
||||
GRANT ALL ON public.soaking TO authenticated;
|
||||
GRANT ALL ON public.airdrying TO authenticated;
|
||||
GRANT ALL ON public.cracking TO authenticated;
|
||||
GRANT ALL ON public.shelling TO authenticated;
|
||||
GRANT ALL ON public.jc_cracker_parameters TO authenticated;
|
||||
GRANT ALL ON public.meyer_cracker_parameters TO authenticated;
|
||||
|
||||
-- =============================================
|
||||
-- 11. ENABLE ROW LEVEL SECURITY
|
||||
-- 9. ENABLE ROW LEVEL SECURITY
|
||||
-- =============================================
|
||||
|
||||
ALTER TABLE public.soaking ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.airdrying ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.cracking ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.shelling ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.jc_cracker_parameters ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.meyer_cracker_parameters ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- =============================================
|
||||
-- 12. CREATE RLS POLICIES
|
||||
-- 10. CREATE RLS POLICIES
|
||||
-- =============================================
|
||||
|
||||
-- Create RLS policies for phase tables
|
||||
@@ -345,31 +286,3 @@ CREATE POLICY "Shelling data is updatable by authenticated users" ON public.shel
|
||||
CREATE POLICY "Shelling data is deletable by authenticated users" ON public.shelling
|
||||
FOR DELETE USING (auth.role() = 'authenticated');
|
||||
|
||||
-- RLS policies for machine parameter tables
|
||||
CREATE POLICY "JC Cracker parameters are viewable by authenticated users" ON public.jc_cracker_parameters
|
||||
FOR SELECT USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "JC Cracker parameters are insertable by authenticated users" ON public.jc_cracker_parameters
|
||||
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "JC Cracker parameters are updatable by authenticated users" ON public.jc_cracker_parameters
|
||||
FOR UPDATE USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "JC Cracker parameters are deletable by authenticated users" ON public.jc_cracker_parameters
|
||||
FOR DELETE USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Meyer Cracker parameters are viewable by authenticated users" ON public.meyer_cracker_parameters
|
||||
FOR SELECT USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Meyer Cracker parameters are insertable by authenticated users" ON public.meyer_cracker_parameters
|
||||
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Meyer Cracker parameters are updatable by authenticated users" ON public.meyer_cracker_parameters
|
||||
FOR UPDATE USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Meyer Cracker parameters are deletable by authenticated users" ON public.meyer_cracker_parameters
|
||||
FOR DELETE USING (auth.role() = 'authenticated');
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
-- Conductor Availability and Scheduling
|
||||
-- This migration creates tables for conductor availability management and experiment scheduling
|
||||
-- Conductor Availability
|
||||
-- This migration creates the conductor availability table
|
||||
|
||||
-- =============================================
|
||||
-- 1. CONDUCTOR AVAILABILITY TABLE
|
||||
-- =============================================
|
||||
|
||||
-- Create conductor_availability table
|
||||
CREATE TABLE IF NOT EXISTS public.conductor_availability (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id UUID NOT NULL REFERENCES public.user_profiles(id) ON DELETE CASCADE,
|
||||
@@ -25,41 +24,9 @@ CREATE TABLE IF NOT EXISTS public.conductor_availability (
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 2. EXPERIMENT PHASE ASSIGNMENTS TABLE
|
||||
-- 2. INDEXES FOR PERFORMANCE
|
||||
-- =============================================
|
||||
|
||||
-- Create experiment_phase_assignments table for scheduling conductors to experiment phases
|
||||
CREATE TABLE IF NOT EXISTS public.experiment_phase_assignments (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
experiment_number INTEGER NOT NULL,
|
||||
experiment_phase_id UUID NOT NULL,
|
||||
repetition_id UUID NOT NULL REFERENCES public.experiment_repetitions(id) ON DELETE CASCADE,
|
||||
conductor_id UUID NOT NULL REFERENCES public.user_profiles(id) ON DELETE CASCADE,
|
||||
phase_name TEXT NOT NULL CHECK (phase_name IN ('pre-soaking', 'air-drying', 'cracking', 'shelling')),
|
||||
scheduled_start_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
scheduled_end_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||
status TEXT NOT NULL DEFAULT 'scheduled' CHECK (status IN ('scheduled', 'in-progress', 'completed', 'cancelled')),
|
||||
notes TEXT, -- Optional notes about the assignment
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
created_by UUID NOT NULL REFERENCES public.user_profiles(id),
|
||||
|
||||
-- Foreign key to experiments using composite key
|
||||
FOREIGN KEY (experiment_number, experiment_phase_id)
|
||||
REFERENCES public.experiments(experiment_number, phase_id) ON DELETE CASCADE,
|
||||
|
||||
-- Ensure scheduled_end_time is after scheduled_start_time
|
||||
CONSTRAINT valid_scheduled_time_range CHECK (scheduled_end_time > scheduled_start_time),
|
||||
|
||||
-- Ensure unique assignment per conductor per phase per repetition
|
||||
CONSTRAINT unique_conductor_phase_assignment UNIQUE (repetition_id, conductor_id, phase_name)
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 3. INDEXES FOR PERFORMANCE
|
||||
-- =============================================
|
||||
|
||||
-- Conductor availability indexes
|
||||
CREATE INDEX IF NOT EXISTS idx_conductor_availability_user_id ON public.conductor_availability(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_conductor_availability_available_from ON public.conductor_availability(available_from);
|
||||
CREATE INDEX IF NOT EXISTS idx_conductor_availability_available_to ON public.conductor_availability(available_to);
|
||||
@@ -67,17 +34,8 @@ CREATE INDEX IF NOT EXISTS idx_conductor_availability_status ON public.conductor
|
||||
CREATE INDEX IF NOT EXISTS idx_conductor_availability_created_by ON public.conductor_availability(created_by);
|
||||
CREATE INDEX IF NOT EXISTS idx_conductor_availability_time_range ON public.conductor_availability(available_from, available_to);
|
||||
|
||||
-- Experiment phase assignments indexes
|
||||
CREATE INDEX IF NOT EXISTS idx_experiment_phase_assignments_experiment_composite ON public.experiment_phase_assignments(experiment_number, experiment_phase_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiment_phase_assignments_repetition_id ON public.experiment_phase_assignments(repetition_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiment_phase_assignments_conductor_id ON public.experiment_phase_assignments(conductor_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiment_phase_assignments_phase_name ON public.experiment_phase_assignments(phase_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiment_phase_assignments_status ON public.experiment_phase_assignments(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiment_phase_assignments_scheduled_start ON public.experiment_phase_assignments(scheduled_start_time);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiment_phase_assignments_created_by ON public.experiment_phase_assignments(created_by);
|
||||
|
||||
-- =============================================
|
||||
-- 4. FUNCTIONS FOR OVERLAP PREVENTION
|
||||
-- 3. FUNCTIONS FOR OVERLAP PREVENTION
|
||||
-- =============================================
|
||||
|
||||
-- Function to check for overlapping availabilities
|
||||
@@ -111,10 +69,6 @@ BEGIN
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- =============================================
|
||||
-- 5. HELPER FUNCTIONS
|
||||
-- =============================================
|
||||
|
||||
-- Function to get available conductors for a specific time range
|
||||
CREATE OR REPLACE FUNCTION public.get_available_conductors(
|
||||
start_time TIMESTAMP WITH TIME ZONE,
|
||||
@@ -167,7 +121,7 @@ END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- =============================================
|
||||
-- 6. TRIGGERS
|
||||
-- 4. TRIGGERS
|
||||
-- =============================================
|
||||
|
||||
-- Create trigger for updated_at on conductor_availability
|
||||
@@ -176,12 +130,6 @@ CREATE TRIGGER set_updated_at_conductor_availability
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
-- Create trigger for updated_at on experiment_phase_assignments
|
||||
CREATE TRIGGER set_updated_at_experiment_phase_assignments
|
||||
BEFORE UPDATE ON public.experiment_phase_assignments
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
-- Create trigger to prevent overlapping availabilities
|
||||
CREATE TRIGGER trigger_check_availability_overlap
|
||||
BEFORE INSERT OR UPDATE ON public.conductor_availability
|
||||
@@ -189,24 +137,21 @@ CREATE TRIGGER trigger_check_availability_overlap
|
||||
EXECUTE FUNCTION public.check_availability_overlap();
|
||||
|
||||
-- =============================================
|
||||
-- 7. GRANT PERMISSIONS
|
||||
-- 5. GRANT PERMISSIONS
|
||||
-- =============================================
|
||||
|
||||
GRANT ALL ON public.conductor_availability TO authenticated;
|
||||
GRANT ALL ON public.experiment_phase_assignments TO authenticated;
|
||||
|
||||
-- =============================================
|
||||
-- 8. ENABLE ROW LEVEL SECURITY
|
||||
-- 6. ENABLE ROW LEVEL SECURITY
|
||||
-- =============================================
|
||||
|
||||
ALTER TABLE public.conductor_availability ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.experiment_phase_assignments ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- =============================================
|
||||
-- 9. CREATE RLS POLICIES
|
||||
-- 7. CREATE RLS POLICIES
|
||||
-- =============================================
|
||||
|
||||
-- Conductor availability policies
|
||||
CREATE POLICY "conductor_availability_select_policy" ON public.conductor_availability
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
@@ -243,61 +188,5 @@ CREATE POLICY "conductor_availability_delete_policy" ON public.conductor_availab
|
||||
user_id = auth.uid() OR public.is_admin()
|
||||
);
|
||||
|
||||
-- Experiment phase assignments policies
|
||||
CREATE POLICY "experiment_phase_assignments_select_policy" ON public.experiment_phase_assignments
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (
|
||||
-- Conductors can view their own assignments, admins can view all
|
||||
conductor_id = auth.uid() OR public.is_admin()
|
||||
);
|
||||
|
||||
CREATE POLICY "experiment_phase_assignments_insert_policy" ON public.experiment_phase_assignments
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (
|
||||
-- Only admins and conductors can create assignments
|
||||
public.can_manage_experiments()
|
||||
);
|
||||
|
||||
CREATE POLICY "experiment_phase_assignments_update_policy" ON public.experiment_phase_assignments
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (
|
||||
-- Conductors can update their own assignments, admins can update any
|
||||
conductor_id = auth.uid() OR public.is_admin()
|
||||
)
|
||||
WITH CHECK (
|
||||
-- Conductors can update their own assignments, admins can update any
|
||||
conductor_id = auth.uid() OR public.is_admin()
|
||||
);
|
||||
|
||||
CREATE POLICY "experiment_phase_assignments_delete_policy" ON public.experiment_phase_assignments
|
||||
FOR DELETE
|
||||
TO authenticated
|
||||
USING (
|
||||
-- Only admins can delete assignments
|
||||
public.is_admin()
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 10. COMMENTS FOR DOCUMENTATION
|
||||
-- =============================================
|
||||
|
||||
COMMENT ON TABLE public.conductor_availability IS 'Stores conductor availability windows for experiment scheduling';
|
||||
COMMENT ON TABLE public.experiment_phase_assignments IS 'Assigns conductors to specific experiment repetition phases with scheduled times';
|
||||
|
||||
COMMENT ON COLUMN public.conductor_availability.available_from IS 'Start time of availability window';
|
||||
COMMENT ON COLUMN public.conductor_availability.available_to IS 'End time of availability window';
|
||||
COMMENT ON COLUMN public.conductor_availability.notes IS 'Optional notes about the availability period';
|
||||
COMMENT ON COLUMN public.conductor_availability.status IS 'Status of the availability (active or cancelled)';
|
||||
|
||||
COMMENT ON COLUMN public.experiment_phase_assignments.phase_name IS 'Experiment phase being assigned (pre-soaking, air-drying, cracking, shelling)';
|
||||
COMMENT ON COLUMN public.experiment_phase_assignments.scheduled_start_time IS 'Planned start time for the phase';
|
||||
COMMENT ON COLUMN public.experiment_phase_assignments.scheduled_end_time IS 'Planned end time for the phase';
|
||||
COMMENT ON COLUMN public.experiment_phase_assignments.status IS 'Current status of the assignment';
|
||||
COMMENT ON COLUMN public.experiment_phase_assignments.notes IS 'Optional notes about the assignment';
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
-- Views and Final Setup
|
||||
-- This migration creates views for easier querying and finalizes the database setup
|
||||
-- Views
|
||||
-- This migration creates views for easier querying (must run last after all tables are created)
|
||||
|
||||
-- =============================================
|
||||
-- 1. CREATE VIEWS FOR EASIER QUERYING
|
||||
@@ -15,10 +15,6 @@ SELECT
|
||||
e.results_status,
|
||||
e.completion_status,
|
||||
e.phase_id,
|
||||
e.soaking_id,
|
||||
e.airdrying_id,
|
||||
e.cracking_id,
|
||||
e.shelling_id,
|
||||
e.created_at,
|
||||
e.updated_at,
|
||||
e.created_by,
|
||||
@@ -28,42 +24,47 @@ SELECT
|
||||
ep.has_airdrying,
|
||||
ep.has_cracking,
|
||||
ep.has_shelling,
|
||||
s.id as soaking_id,
|
||||
s.scheduled_start_time as soaking_scheduled_start,
|
||||
s.actual_start_time as soaking_actual_start,
|
||||
s.soaking_duration_hours,
|
||||
s.soaking_duration_minutes,
|
||||
s.scheduled_end_time as soaking_scheduled_end,
|
||||
s.actual_end_time as soaking_actual_end,
|
||||
ad.id as airdrying_id,
|
||||
ad.scheduled_start_time as airdrying_scheduled_start,
|
||||
ad.actual_start_time as airdrying_actual_start,
|
||||
ad.duration_minutes as airdrying_duration,
|
||||
ad.scheduled_end_time as airdrying_scheduled_end,
|
||||
ad.actual_end_time as airdrying_actual_end,
|
||||
c.id as cracking_id,
|
||||
c.scheduled_start_time as cracking_scheduled_start,
|
||||
c.actual_start_time as cracking_actual_start,
|
||||
c.actual_end_time as cracking_actual_end,
|
||||
mt.name as machine_type_name,
|
||||
sh.id as shelling_id,
|
||||
sh.scheduled_start_time as shelling_scheduled_start,
|
||||
sh.actual_start_time as shelling_actual_start,
|
||||
sh.actual_end_time as shelling_actual_end
|
||||
FROM public.experiments e
|
||||
LEFT JOIN public.experiment_phases ep ON e.phase_id = ep.id
|
||||
LEFT JOIN public.soaking s ON e.soaking_id = s.id
|
||||
LEFT JOIN public.airdrying ad ON e.airdrying_id = ad.id
|
||||
LEFT JOIN public.cracking c ON e.cracking_id = c.id
|
||||
LEFT JOIN public.soaking s ON s.experiment_id = e.id
|
||||
LEFT JOIN public.airdrying ad ON ad.experiment_id = e.id
|
||||
LEFT JOIN public.cracking c ON c.experiment_id = e.id
|
||||
LEFT JOIN public.machine_types mt ON c.machine_type_id = mt.id
|
||||
LEFT JOIN public.shelling sh ON e.shelling_id = sh.id;
|
||||
LEFT JOIN public.shelling sh ON sh.experiment_id = e.id;
|
||||
|
||||
-- View for repetitions with phase information
|
||||
CREATE OR REPLACE VIEW public.repetitions_with_phases AS
|
||||
SELECT
|
||||
er.id,
|
||||
er.experiment_number,
|
||||
er.experiment_phase_id,
|
||||
er.experiment_id,
|
||||
er.repetition_number,
|
||||
er.status,
|
||||
er.created_at,
|
||||
er.updated_at,
|
||||
er.created_by,
|
||||
e.experiment_number,
|
||||
e.phase_id,
|
||||
e.weight_per_repetition_lbs,
|
||||
ep.name as phase_name,
|
||||
ep.has_soaking,
|
||||
@@ -72,7 +73,7 @@ SELECT
|
||||
ep.has_shelling,
|
||||
s.scheduled_start_time as soaking_scheduled_start,
|
||||
s.actual_start_time as soaking_actual_start,
|
||||
s.soaking_duration_hours,
|
||||
s.soaking_duration_minutes,
|
||||
s.scheduled_end_time as soaking_scheduled_end,
|
||||
s.actual_end_time as soaking_actual_end,
|
||||
ad.scheduled_start_time as airdrying_scheduled_start,
|
||||
@@ -88,7 +89,7 @@ SELECT
|
||||
sh.actual_start_time as shelling_actual_start,
|
||||
sh.actual_end_time as shelling_actual_end
|
||||
FROM public.experiment_repetitions er
|
||||
JOIN public.experiments e ON er.experiment_number = e.experiment_number AND er.experiment_phase_id = e.phase_id
|
||||
JOIN public.experiments e ON er.experiment_id = e.id
|
||||
LEFT JOIN public.experiment_phases ep ON e.phase_id = ep.id
|
||||
LEFT JOIN public.soaking s ON er.id = s.repetition_id
|
||||
LEFT JOIN public.airdrying ad ON er.id = ad.repetition_id
|
||||
@@ -96,37 +97,6 @@ LEFT JOIN public.cracking c ON er.id = c.repetition_id
|
||||
LEFT JOIN public.machine_types mt ON c.machine_type_id = mt.id
|
||||
LEFT JOIN public.shelling sh ON er.id = sh.repetition_id;
|
||||
|
||||
-- View for conductor assignments with experiment details
|
||||
CREATE OR REPLACE VIEW public.conductor_assignments_with_details AS
|
||||
SELECT
|
||||
epa.id,
|
||||
epa.experiment_number,
|
||||
epa.experiment_phase_id,
|
||||
epa.repetition_id,
|
||||
epa.conductor_id,
|
||||
epa.phase_name,
|
||||
epa.scheduled_start_time,
|
||||
epa.scheduled_end_time,
|
||||
epa.status,
|
||||
epa.notes,
|
||||
epa.created_at,
|
||||
epa.updated_at,
|
||||
epa.created_by,
|
||||
e.reps_required,
|
||||
e.weight_per_repetition_lbs,
|
||||
ep.name as experiment_phase_name,
|
||||
ep.description as phase_description,
|
||||
up.email as conductor_email,
|
||||
up.first_name as conductor_first_name,
|
||||
up.last_name as conductor_last_name,
|
||||
er.repetition_number,
|
||||
er.status as repetition_status
|
||||
FROM public.experiment_phase_assignments epa
|
||||
JOIN public.experiments e ON epa.experiment_number = e.experiment_number AND epa.experiment_phase_id = e.phase_id
|
||||
JOIN public.experiment_phases ep ON e.phase_id = ep.id
|
||||
JOIN public.user_profiles up ON epa.conductor_id = up.id
|
||||
JOIN public.experiment_repetitions er ON epa.repetition_id = er.id;
|
||||
|
||||
-- View for available conductors with their roles
|
||||
CREATE OR REPLACE VIEW public.available_conductors AS
|
||||
SELECT
|
||||
@@ -148,20 +118,18 @@ AND r.name = 'conductor';
|
||||
|
||||
GRANT SELECT ON public.experiments_with_phases TO authenticated;
|
||||
GRANT SELECT ON public.repetitions_with_phases TO authenticated;
|
||||
GRANT SELECT ON public.conductor_assignments_with_details TO authenticated;
|
||||
GRANT SELECT ON public.available_conductors TO authenticated;
|
||||
|
||||
-- =============================================
|
||||
-- 3. FINAL COMMENTS FOR DOCUMENTATION
|
||||
-- 3. COMMENTS FOR DOCUMENTATION
|
||||
-- =============================================
|
||||
|
||||
COMMENT ON VIEW public.experiments_with_phases IS 'Comprehensive view of experiments with all phase information and timing details';
|
||||
COMMENT ON VIEW public.repetitions_with_phases IS 'View of experiment repetitions with associated phase data';
|
||||
COMMENT ON VIEW public.conductor_assignments_with_details IS 'Detailed view of conductor assignments with experiment and conductor information';
|
||||
COMMENT ON VIEW public.available_conductors IS 'View of currently available conductors with their profile information';
|
||||
|
||||
-- =============================================
|
||||
-- 4. CREATE SAMPLE DATA FUNCTIONS (OPTIONAL)
|
||||
-- 4. SAMPLE DATA FUNCTIONS (OPTIONAL)
|
||||
-- =============================================
|
||||
|
||||
-- Function to create sample roles
|
||||
@@ -214,3 +182,4 @@ $$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
GRANT EXECUTE ON FUNCTION public.create_sample_roles() TO authenticated;
|
||||
GRANT EXECUTE ON FUNCTION public.create_sample_machine_types() TO authenticated;
|
||||
GRANT EXECUTE ON FUNCTION public.create_sample_experiment_phases() TO authenticated;
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
-- Experiments and Repetitions
|
||||
-- This migration creates the experiments and experiment repetitions tables with composite primary key
|
||||
|
||||
-- =============================================
|
||||
-- 1. EXPERIMENTS
|
||||
-- =============================================
|
||||
|
||||
-- Create experiments table with composite primary key (experiment_number, phase_id)
|
||||
CREATE TABLE IF NOT EXISTS public.experiments (
|
||||
id UUID DEFAULT uuid_generate_v4(),
|
||||
experiment_number INTEGER NOT NULL,
|
||||
reps_required INTEGER NOT NULL CHECK (reps_required > 0),
|
||||
weight_per_repetition_lbs DOUBLE PRECISION NOT NULL DEFAULT 5.0 CHECK (weight_per_repetition_lbs > 0),
|
||||
results_status TEXT NOT NULL DEFAULT 'valid' CHECK (results_status IN ('valid', 'invalid')),
|
||||
completion_status BOOLEAN NOT NULL DEFAULT false,
|
||||
phase_id UUID NOT NULL REFERENCES public.experiment_phases(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
created_by UUID NOT NULL REFERENCES public.user_profiles(id),
|
||||
|
||||
-- Composite primary key allows each phase to have its own experiment numbering starting from 1
|
||||
PRIMARY KEY (experiment_number, phase_id)
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 2. EXPERIMENT REPETITIONS
|
||||
-- =============================================
|
||||
|
||||
-- Create experiment repetitions table
|
||||
CREATE TABLE IF NOT EXISTS public.experiment_repetitions (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
experiment_id UUID NOT NULL REFERENCES public.experiments(id) ON DELETE CASCADE,
|
||||
repetition_number INTEGER NOT NULL CHECK (repetition_number > 0),
|
||||
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'in_progress', 'completed', 'cancelled')),
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
created_by UUID NOT NULL REFERENCES public.user_profiles(id),
|
||||
|
||||
-- Ensure unique repetition numbers per experiment
|
||||
UNIQUE(experiment_id, repetition_number)
|
||||
);
|
||||
|
||||
-- =============================================
|
||||
-- 3. INDEXES FOR PERFORMANCE
|
||||
-- =============================================
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_experiments_phase_id ON public.experiments(phase_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiments_experiment_number ON public.experiments(experiment_number);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiments_created_by ON public.experiments(created_by);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiment_repetitions_experiment_id ON public.experiment_repetitions(experiment_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_experiment_repetitions_created_by ON public.experiment_repetitions(created_by);
|
||||
|
||||
-- =============================================
|
||||
-- 4. TRIGGERS
|
||||
-- =============================================
|
||||
|
||||
-- Create trigger for updated_at on experiments
|
||||
CREATE TRIGGER set_updated_at_experiments
|
||||
BEFORE UPDATE ON public.experiments
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
-- Create trigger for updated_at on experiment_repetitions
|
||||
CREATE TRIGGER set_updated_at_experiment_repetitions
|
||||
BEFORE UPDATE ON public.experiment_repetitions
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_updated_at();
|
||||
|
||||
-- =============================================
|
||||
-- 5. GRANT PERMISSIONS
|
||||
-- =============================================
|
||||
|
||||
GRANT ALL ON public.experiments TO authenticated;
|
||||
GRANT ALL ON public.experiment_repetitions TO authenticated;
|
||||
|
||||
-- =============================================
|
||||
-- 6. ENABLE ROW LEVEL SECURITY
|
||||
-- =============================================
|
||||
|
||||
ALTER TABLE public.experiments ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.experiment_repetitions ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- =============================================
|
||||
-- 7. CREATE RLS POLICIES
|
||||
-- =============================================
|
||||
|
||||
-- Create RLS policies for experiments
|
||||
CREATE POLICY "Experiments are viewable by authenticated users" ON public.experiments
|
||||
FOR SELECT USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Experiments are insertable by authenticated users" ON public.experiments
|
||||
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Experiments are updatable by authenticated users" ON public.experiments
|
||||
FOR UPDATE USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Experiments are deletable by authenticated users" ON public.experiments
|
||||
FOR DELETE USING (auth.role() = 'authenticated');
|
||||
|
||||
-- Create RLS policies for experiment_repetitions
|
||||
CREATE POLICY "Experiment repetitions are viewable by authenticated users" ON public.experiment_repetitions
|
||||
FOR SELECT USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Experiment repetitions are insertable by authenticated users" ON public.experiment_repetitions
|
||||
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Experiment repetitions are updatable by authenticated users" ON public.experiment_repetitions
|
||||
FOR UPDATE USING (auth.role() = 'authenticated');
|
||||
|
||||
CREATE POLICY "Experiment repetitions are deletable by authenticated users" ON public.experiment_repetitions
|
||||
FOR DELETE USING (auth.role() = 'authenticated');
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
-- Fix soaking duration column to use minutes instead of hours
|
||||
-- This aligns the database schema with frontend expectations and seed data
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 1) Add new soaking_duration_minutes column
|
||||
ALTER TABLE public.soaking ADD COLUMN IF NOT EXISTS soaking_duration_minutes INTEGER;
|
||||
|
||||
-- 2) Backfill soaking_duration_minutes from soaking_duration_hours
|
||||
UPDATE public.soaking
|
||||
SET soaking_duration_minutes = ROUND(soaking_duration_hours * 60)
|
||||
WHERE soaking_duration_minutes IS NULL;
|
||||
|
||||
-- 3) Make soaking_duration_minutes NOT NULL
|
||||
ALTER TABLE public.soaking ALTER COLUMN soaking_duration_minutes SET NOT NULL;
|
||||
|
||||
-- 4) Add check constraint for positive values
|
||||
ALTER TABLE public.soaking ADD CONSTRAINT check_soaking_duration_minutes_positive
|
||||
CHECK (soaking_duration_minutes > 0);
|
||||
|
||||
-- 5) Drop and recreate views to use the new column (must be done before dropping old column)
|
||||
DROP VIEW IF EXISTS public.experiments_with_phases;
|
||||
DROP VIEW IF EXISTS public.repetitions_with_phases;
|
||||
|
||||
CREATE VIEW public.experiments_with_phases AS
|
||||
SELECT
|
||||
e.id,
|
||||
e.experiment_number,
|
||||
e.reps_required,
|
||||
e.weight_per_repetition_lbs,
|
||||
e.results_status,
|
||||
e.completion_status,
|
||||
e.phase_id,
|
||||
e.soaking_id,
|
||||
e.airdrying_id,
|
||||
e.cracking_id,
|
||||
e.shelling_id,
|
||||
e.created_at,
|
||||
e.updated_at,
|
||||
e.created_by,
|
||||
ep.name as phase_name,
|
||||
ep.description as phase_description,
|
||||
ep.has_soaking,
|
||||
ep.has_airdrying,
|
||||
ep.has_cracking,
|
||||
ep.has_shelling,
|
||||
s.scheduled_start_time as soaking_scheduled_start,
|
||||
s.actual_start_time as soaking_actual_start,
|
||||
s.soaking_duration_minutes,
|
||||
s.scheduled_end_time as soaking_scheduled_end,
|
||||
s.actual_end_time as soaking_actual_end,
|
||||
ad.scheduled_start_time as airdrying_scheduled_start,
|
||||
ad.actual_start_time as airdrying_actual_start,
|
||||
ad.duration_minutes as airdrying_duration,
|
||||
ad.scheduled_end_time as airdrying_scheduled_end,
|
||||
ad.actual_end_time as airdrying_actual_end,
|
||||
c.scheduled_start_time as cracking_scheduled_start,
|
||||
c.actual_start_time as cracking_actual_start,
|
||||
c.actual_end_time as cracking_actual_end,
|
||||
mt.name as machine_type_name,
|
||||
sh.scheduled_start_time as shelling_scheduled_start,
|
||||
sh.actual_start_time as shelling_actual_start,
|
||||
sh.actual_end_time as shelling_actual_end
|
||||
FROM public.experiments e
|
||||
LEFT JOIN public.experiment_phases ep ON e.phase_id = ep.id
|
||||
LEFT JOIN public.soaking s ON e.soaking_id = s.id
|
||||
LEFT JOIN public.airdrying ad ON e.airdrying_id = ad.id
|
||||
LEFT JOIN public.cracking c ON e.cracking_id = c.id
|
||||
LEFT JOIN public.machine_types mt ON c.machine_type_id = mt.id
|
||||
LEFT JOIN public.shelling sh ON e.shelling_id = sh.id;
|
||||
|
||||
CREATE VIEW public.repetitions_with_phases AS
|
||||
SELECT
|
||||
er.id,
|
||||
er.experiment_number,
|
||||
er.experiment_phase_id,
|
||||
er.repetition_number,
|
||||
er.status,
|
||||
er.created_at,
|
||||
er.updated_at,
|
||||
er.created_by,
|
||||
e.weight_per_repetition_lbs,
|
||||
ep.name as phase_name,
|
||||
ep.has_soaking,
|
||||
ep.has_airdrying,
|
||||
ep.has_cracking,
|
||||
ep.has_shelling,
|
||||
s.scheduled_start_time as soaking_scheduled_start,
|
||||
s.actual_start_time as soaking_actual_start,
|
||||
s.soaking_duration_minutes,
|
||||
s.scheduled_end_time as soaking_scheduled_end,
|
||||
s.actual_end_time as soaking_actual_end,
|
||||
ad.scheduled_start_time as airdrying_scheduled_start,
|
||||
ad.actual_start_time as airdrying_actual_start,
|
||||
ad.duration_minutes as airdrying_duration,
|
||||
ad.scheduled_end_time as airdrying_scheduled_end,
|
||||
ad.actual_end_time as airdrying_actual_end,
|
||||
c.scheduled_start_time as cracking_scheduled_start,
|
||||
c.actual_start_time as cracking_actual_start,
|
||||
c.actual_end_time as cracking_actual_end,
|
||||
mt.name as machine_type_name,
|
||||
sh.scheduled_start_time as shelling_scheduled_start,
|
||||
sh.actual_start_time as shelling_actual_start,
|
||||
sh.actual_end_time as shelling_actual_end
|
||||
FROM public.experiment_repetitions er
|
||||
JOIN public.experiments e ON er.experiment_number = e.experiment_number AND er.experiment_phase_id = e.phase_id
|
||||
LEFT JOIN public.experiment_phases ep ON e.phase_id = ep.id
|
||||
LEFT JOIN public.soaking s ON er.id = s.repetition_id
|
||||
LEFT JOIN public.airdrying ad ON er.id = ad.repetition_id
|
||||
LEFT JOIN public.cracking c ON er.id = c.repetition_id
|
||||
LEFT JOIN public.machine_types mt ON c.machine_type_id = mt.id
|
||||
LEFT JOIN public.shelling sh ON er.id = sh.repetition_id;
|
||||
|
||||
-- 6) Update the trigger function to use minutes
|
||||
CREATE OR REPLACE FUNCTION calculate_soaking_scheduled_end_time()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.scheduled_end_time = NEW.scheduled_start_time + (NEW.soaking_duration_minutes || ' minutes')::INTERVAL;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- 7) Update the trigger to use the new column
|
||||
DROP TRIGGER IF EXISTS trigger_calculate_soaking_scheduled_end_time ON public.soaking;
|
||||
CREATE TRIGGER trigger_calculate_soaking_scheduled_end_time
|
||||
BEFORE INSERT OR UPDATE ON public.soaking
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION calculate_soaking_scheduled_end_time();
|
||||
|
||||
-- 8) Drop the old soaking_duration_hours column
|
||||
ALTER TABLE public.soaking DROP COLUMN IF EXISTS soaking_duration_hours;
|
||||
|
||||
COMMIT;
|
||||
@@ -1,44 +0,0 @@
|
||||
-- Change experiments primary key to (id, experiment_number)
|
||||
-- Preserve uniqueness on (experiment_number, phase_id) for legacy FKs
|
||||
-- Ensure experiments.id is unique so existing FKs to id remain valid
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 1) Ensure experiments.id is unique for FKs to reference
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_constraint WHERE conname = 'experiments_id_key'
|
||||
) THEN
|
||||
ALTER TABLE public.experiments
|
||||
ADD CONSTRAINT experiments_id_key UNIQUE (id);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 2) Ensure (experiment_number, phase_id) remains unique before dropping PK
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_constraint WHERE conname = 'experiments_experiment_number_phase_id_key'
|
||||
) THEN
|
||||
ALTER TABLE public.experiments
|
||||
ADD CONSTRAINT experiments_experiment_number_phase_id_key UNIQUE (experiment_number, phase_id);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 3) Do NOT drop the existing primary key because dependent FKs reference it.
|
||||
-- Instead, add a UNIQUE constraint on (id, experiment_number) to satisfy
|
||||
-- application-level requirements without breaking dependencies.
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_constraint WHERE conname = 'experiments_id_experiment_number_key'
|
||||
) THEN
|
||||
ALTER TABLE public.experiments
|
||||
ADD CONSTRAINT experiments_id_experiment_number_key UNIQUE (id, experiment_number);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
COMMIT;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user