- Renamed columns in the experimental run sheet CSV for clarity. - Updated the ExperimentForm component to include new fields for weight per repetition and additional parameters specific to Meyer Cracker experiments. - Enhanced the data entry logic to handle new experiment phases and machine types. - Refactored repetition scheduling logic to use scheduled_date instead of schedule_status for better clarity in status representation. - Improved the user interface for displaying experiment phases and their associated statuses. - Removed outdated seed data and updated database migration scripts to reflect the new schema changes.
635 lines
28 KiB
PL/PgSQL
635 lines
28 KiB
PL/PgSQL
-- Complete Database Schema for USDA Vision Pecan Experiments System
|
|
-- This migration creates the entire database schema from scratch
|
|
-- Supports both JC Cracker and Meyer Cracker experiments
|
|
|
|
-- =============================================
|
|
-- 1. EXTENSIONS
|
|
-- =============================================
|
|
|
|
-- 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,
|
|
description TEXT,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
|
);
|
|
|
|
-- Create 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,
|
|
first_name TEXT,
|
|
last_name TEXT,
|
|
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'inactive', 'suspended')),
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
|
);
|
|
|
|
-- Create 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,
|
|
role_id UUID NOT NULL REFERENCES public.roles(id) ON DELETE CASCADE,
|
|
assigned_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
assigned_by UUID REFERENCES public.user_profiles(id),
|
|
UNIQUE(user_id, role_id)
|
|
);
|
|
|
|
-- =============================================
|
|
-- 3. MACHINE TYPES
|
|
-- =============================================
|
|
|
|
-- 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)
|
|
);
|
|
|
|
-- =============================================
|
|
-- 4. 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,
|
|
description TEXT,
|
|
has_soaking BOOLEAN NOT NULL DEFAULT false,
|
|
has_airdrying BOOLEAN NOT NULL DEFAULT false,
|
|
has_cracking BOOLEAN NOT NULL DEFAULT false,
|
|
has_shelling BOOLEAN NOT NULL DEFAULT false,
|
|
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 at least one phase is selected
|
|
CONSTRAINT check_at_least_one_phase
|
|
CHECK (has_soaking = true OR has_airdrying = true OR has_cracking = true OR has_shelling = true)
|
|
);
|
|
|
|
-- =============================================
|
|
-- 5. EXPERIMENTS
|
|
-- =============================================
|
|
|
|
-- Create experiments table
|
|
CREATE TABLE IF NOT EXISTS public.experiments (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
experiment_number INTEGER UNIQUE 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 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)
|
|
);
|
|
|
|
-- =============================================
|
|
-- 6. 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)
|
|
);
|
|
|
|
-- =============================================
|
|
-- 7. PHASE-SPECIFIC TABLES
|
|
-- =============================================
|
|
|
|
-- 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_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(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
created_by UUID NOT NULL REFERENCES public.user_profiles(id),
|
|
|
|
-- Ensure only one soaking per experiment or repetition
|
|
CONSTRAINT unique_soaking_per_experiment UNIQUE (experiment_id),
|
|
CONSTRAINT unique_soaking_per_repetition UNIQUE (repetition_id)
|
|
);
|
|
|
|
-- 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,
|
|
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,
|
|
duration_minutes INTEGER NOT NULL CHECK (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(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
created_by UUID NOT NULL REFERENCES public.user_profiles(id),
|
|
|
|
-- Ensure only one airdrying per experiment or repetition
|
|
CONSTRAINT unique_airdrying_per_experiment UNIQUE (experiment_id),
|
|
CONSTRAINT unique_airdrying_per_repetition UNIQUE (repetition_id)
|
|
);
|
|
|
|
-- 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),
|
|
scheduled_start_time TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
actual_start_time TIMESTAMP WITH TIME ZONE,
|
|
actual_end_time TIMESTAMP WITH TIME ZONE,
|
|
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 only one cracking per experiment or repetition
|
|
CONSTRAINT unique_cracking_per_experiment UNIQUE (experiment_id),
|
|
CONSTRAINT unique_cracking_per_repetition UNIQUE (repetition_id)
|
|
);
|
|
|
|
-- 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,
|
|
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,
|
|
actual_end_time TIMESTAMP WITH TIME ZONE,
|
|
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 only one shelling per experiment or repetition
|
|
CONSTRAINT unique_shelling_per_experiment UNIQUE (experiment_id),
|
|
CONSTRAINT unique_shelling_per_repetition UNIQUE (repetition_id)
|
|
);
|
|
|
|
-- =============================================
|
|
-- 8. 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(),
|
|
cracking_id UUID NOT NULL REFERENCES public.cracking(id) ON DELETE CASCADE,
|
|
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(),
|
|
|
|
-- Ensure only one parameter set per cracking
|
|
CONSTRAINT unique_jc_params_per_cracking UNIQUE (cracking_id)
|
|
);
|
|
|
|
-- Create Meyer Cracker parameters table
|
|
CREATE TABLE IF NOT EXISTS public.meyer_cracker_parameters (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
cracking_id UUID NOT NULL REFERENCES public.cracking(id) ON DELETE CASCADE,
|
|
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(),
|
|
|
|
-- Ensure only one parameter set per cracking
|
|
CONSTRAINT unique_meyer_params_per_cracking UNIQUE (cracking_id)
|
|
);
|
|
|
|
-- =============================================
|
|
-- 9. ADD FOREIGN KEY CONSTRAINTS TO EXPERIMENTS
|
|
-- =============================================
|
|
|
|
-- Add foreign key constraints to experiments table for phase associations
|
|
ALTER TABLE public.experiments
|
|
ADD COLUMN IF NOT EXISTS soaking_id UUID REFERENCES public.soaking(id) ON DELETE SET NULL,
|
|
ADD COLUMN IF NOT EXISTS airdrying_id UUID REFERENCES public.airdrying(id) ON DELETE SET NULL,
|
|
ADD COLUMN IF NOT EXISTS cracking_id UUID REFERENCES public.cracking(id) ON DELETE SET NULL,
|
|
ADD COLUMN IF NOT EXISTS shelling_id UUID REFERENCES public.shelling(id) ON DELETE SET NULL;
|
|
|
|
-- =============================================
|
|
-- 10. CREATE INDEXES FOR PERFORMANCE
|
|
-- =============================================
|
|
|
|
-- Create indexes for better query performance
|
|
CREATE INDEX IF NOT EXISTS idx_user_profiles_email ON public.user_profiles(email);
|
|
CREATE INDEX IF NOT EXISTS idx_user_roles_user_id ON public.user_roles(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_user_roles_role_id ON public.user_roles(role_id);
|
|
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_experiment_repetitions_experiment_id ON public.experiment_repetitions(experiment_id);
|
|
CREATE INDEX IF NOT EXISTS idx_soaking_experiment_id ON public.soaking(experiment_id);
|
|
CREATE INDEX IF NOT EXISTS idx_soaking_repetition_id ON public.soaking(repetition_id);
|
|
CREATE INDEX IF NOT EXISTS idx_airdrying_experiment_id ON public.airdrying(experiment_id);
|
|
CREATE INDEX IF NOT EXISTS idx_airdrying_repetition_id ON public.airdrying(repetition_id);
|
|
CREATE INDEX IF NOT EXISTS idx_cracking_experiment_id ON public.cracking(experiment_id);
|
|
CREATE INDEX IF NOT EXISTS idx_cracking_repetition_id ON public.cracking(repetition_id);
|
|
CREATE INDEX IF NOT EXISTS idx_cracking_machine_type_id ON public.cracking(machine_type_id);
|
|
CREATE INDEX IF NOT EXISTS idx_shelling_experiment_id ON public.shelling(experiment_id);
|
|
CREATE INDEX IF NOT EXISTS idx_shelling_repetition_id ON public.shelling(repetition_id);
|
|
|
|
-- =============================================
|
|
-- 11. CREATE TRIGGERS 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_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 $$
|
|
BEGIN
|
|
NEW.scheduled_end_time = NEW.scheduled_start_time + (NEW.duration_minutes || ' minutes')::INTERVAL;
|
|
RETURN NEW;
|
|
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 $$
|
|
BEGIN
|
|
-- If this is a new airdrying record and no scheduled_start_time is provided,
|
|
-- try to get it from the associated soaking's scheduled_end_time
|
|
IF NEW.scheduled_start_time IS NULL THEN
|
|
SELECT s.scheduled_end_time INTO NEW.scheduled_start_time
|
|
FROM public.soaking s
|
|
WHERE s.experiment_id = NEW.experiment_id
|
|
LIMIT 1;
|
|
END IF;
|
|
RETURN NEW;
|
|
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 $$
|
|
BEGIN
|
|
-- If this is a new cracking record and no scheduled_start_time is provided,
|
|
-- try to get it from the associated airdrying's scheduled_end_time
|
|
IF NEW.scheduled_start_time IS NULL THEN
|
|
SELECT a.scheduled_end_time INTO NEW.scheduled_start_time
|
|
FROM public.airdrying a
|
|
WHERE a.experiment_id = NEW.experiment_id
|
|
LIMIT 1;
|
|
END IF;
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Trigger for cracking 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();
|
|
|
|
-- =============================================
|
|
-- 12. CREATE VIEWS FOR EASIER QUERYING
|
|
-- =============================================
|
|
|
|
-- View for experiments with all phase information
|
|
CREATE OR REPLACE 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;
|
|
|
|
-- View for repetitions with phase information
|
|
CREATE OR REPLACE VIEW public.repetitions_with_phases AS
|
|
SELECT
|
|
er.*,
|
|
e.experiment_number,
|
|
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_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
|
|
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;
|
|
|
|
-- =============================================
|
|
-- 13. GRANT PERMISSIONS
|
|
-- =============================================
|
|
|
|
-- Grant permissions for all tables
|
|
GRANT ALL ON public.roles TO authenticated;
|
|
GRANT ALL ON public.user_profiles TO authenticated;
|
|
GRANT ALL ON public.user_roles TO authenticated;
|
|
GRANT ALL ON public.machine_types TO authenticated;
|
|
GRANT ALL ON public.experiment_phases TO authenticated;
|
|
GRANT ALL ON public.experiments TO authenticated;
|
|
GRANT ALL ON public.experiment_repetitions TO authenticated;
|
|
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;
|
|
|
|
-- Grant permissions for views
|
|
GRANT SELECT ON public.experiments_with_phases TO authenticated;
|
|
GRANT SELECT ON public.repetitions_with_phases TO authenticated;
|
|
|
|
-- =============================================
|
|
-- 14. ENABLE ROW LEVEL SECURITY
|
|
-- =============================================
|
|
|
|
-- Enable RLS on all tables
|
|
ALTER TABLE public.roles ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.user_profiles ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.user_roles ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.machine_types ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.experiment_phases ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.experiments ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.experiment_repetitions 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;
|
|
|
|
-- =============================================
|
|
-- 15. CREATE RLS POLICIES
|
|
-- =============================================
|
|
|
|
-- Create RLS policies for roles (read-only for all authenticated users)
|
|
CREATE POLICY "Roles are viewable by authenticated users" ON public.roles
|
|
FOR SELECT USING (auth.role() = 'authenticated');
|
|
|
|
-- Create RLS policies for user_profiles
|
|
CREATE POLICY "User profiles are viewable by authenticated users" ON public.user_profiles
|
|
FOR SELECT USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "User profiles are insertable by authenticated users" ON public.user_profiles
|
|
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "User profiles are updatable by authenticated users" ON public.user_profiles
|
|
FOR UPDATE USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "User profiles are deletable by authenticated users" ON public.user_profiles
|
|
FOR DELETE USING (auth.role() = 'authenticated');
|
|
|
|
-- Create RLS policies for user_roles
|
|
CREATE POLICY "User roles are viewable by authenticated users" ON public.user_roles
|
|
FOR SELECT USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "User roles are insertable by authenticated users" ON public.user_roles
|
|
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "User roles are updatable by authenticated users" ON public.user_roles
|
|
FOR UPDATE USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "User roles are deletable by authenticated users" ON public.user_roles
|
|
FOR DELETE USING (auth.role() = 'authenticated');
|
|
|
|
-- Create RLS policies for machine_types (read-only for all authenticated users)
|
|
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');
|
|
|
|
CREATE POLICY "Experiment phases are insertable by authenticated users" ON public.experiment_phases
|
|
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Experiment phases are updatable by authenticated users" ON public.experiment_phases
|
|
FOR UPDATE USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Experiment phases are deletable by authenticated users" ON public.experiment_phases
|
|
FOR DELETE USING (auth.role() = 'authenticated');
|
|
|
|
-- 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');
|
|
|
|
-- Create RLS policies for phase tables
|
|
CREATE POLICY "Soaking data is viewable by authenticated users" ON public.soaking
|
|
FOR SELECT USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Soaking data is insertable by authenticated users" ON public.soaking
|
|
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Soaking data is updatable by authenticated users" ON public.soaking
|
|
FOR UPDATE USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Soaking data is deletable by authenticated users" ON public.soaking
|
|
FOR DELETE USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Airdrying data is viewable by authenticated users" ON public.airdrying
|
|
FOR SELECT USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Airdrying data is insertable by authenticated users" ON public.airdrying
|
|
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Airdrying data is updatable by authenticated users" ON public.airdrying
|
|
FOR UPDATE USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Airdrying data is deletable by authenticated users" ON public.airdrying
|
|
FOR DELETE USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Cracking data is viewable by authenticated users" ON public.cracking
|
|
FOR SELECT USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Cracking data is insertable by authenticated users" ON public.cracking
|
|
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Cracking data is updatable by authenticated users" ON public.cracking
|
|
FOR UPDATE USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Cracking data is deletable by authenticated users" ON public.cracking
|
|
FOR DELETE USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Shelling data is viewable by authenticated users" ON public.shelling
|
|
FOR SELECT USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Shelling data is insertable by authenticated users" ON public.shelling
|
|
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Shelling data is updatable by authenticated users" ON public.shelling
|
|
FOR UPDATE USING (auth.role() = 'authenticated');
|
|
|
|
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');
|