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:
salirezav
2025-11-03 23:07:22 -05:00
parent 4acad772f9
commit de46753f15
28 changed files with 461 additions and 5193 deletions

View File

@@ -249,3 +249,5 @@ docker compose restart api
## Session Date
Session completed with focus on MQTT debugging and enhanced logging for troubleshooting auto-recording functionality.

View File

@@ -160,3 +160,5 @@ if __name__ == "__main__":
main()

View File

@@ -1 +1 @@
v2.54.10
v2.54.11

View File

@@ -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;

View File

@@ -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

View File

@@ -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');

View File

@@ -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

View File

@@ -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');

View File

@@ -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');

View File

@@ -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');

View File

@@ -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');

View File

@@ -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';

View File

@@ -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;

View File

@@ -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');

View File

@@ -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;

View File

@@ -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;

View File

@@ -1,785 +0,0 @@
-- Complete Database Schema for USDA Vision Pecan Experiments System
-- This migration creates the entire database schema from scratch
-- Enable necessary extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- =============================================
-- 1. ROLES AND USER MANAGEMENT
-- =============================================
-- Create roles table
CREATE TABLE IF NOT EXISTS public.roles (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name TEXT UNIQUE NOT NULL CHECK (name IN ('admin', 'conductor', 'analyst', 'data recorder')),
description TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Create user_profiles table to extend auth.users
CREATE TABLE IF NOT EXISTS public.user_profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
email TEXT NOT NULL,
status TEXT DEFAULT 'active' CHECK (status IN ('active', 'disabled')),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Create user_roles junction table for many-to-many relationship
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)
);
-- =============================================
-- 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,
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)
);
-- =============================================
-- 3. 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),
soaking_duration_hr FLOAT NOT NULL CHECK (soaking_duration_hr >= 0),
air_drying_time_min INTEGER NOT NULL CHECK (air_drying_time_min >= 0),
plate_contact_frequency_hz FLOAT NOT NULL CHECK (plate_contact_frequency_hz > 0),
throughput_rate_pecans_sec FLOAT NOT NULL CHECK (throughput_rate_pecans_sec > 0),
crush_amount_in FLOAT NOT NULL CHECK (crush_amount_in >= 0),
entry_exit_height_diff_in FLOAT NOT NULL,
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)
);
-- =============================================
-- 4. 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),
scheduled_date TIMESTAMP WITH TIME ZONE,
schedule_status TEXT NOT NULL DEFAULT 'pending schedule'
CHECK (schedule_status IN ('pending schedule', 'scheduled', 'canceled', 'aborted')),
completion_status BOOLEAN NOT NULL DEFAULT false,
is_locked BOOLEAN NOT NULL DEFAULT false,
locked_at TIMESTAMP WITH TIME ZONE,
locked_by UUID REFERENCES public.user_profiles(id),
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
CONSTRAINT unique_repetition_per_experiment UNIQUE (experiment_id, repetition_number)
);
-- =============================================
-- 5. DATA ENTRY SYSTEM
-- =============================================
-- Create experiment_phase_drafts table for phase-specific draft management
CREATE TABLE IF NOT EXISTS public.experiment_phase_drafts (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
experiment_id UUID NOT NULL REFERENCES public.experiments(id) ON DELETE CASCADE,
repetition_id UUID NOT NULL REFERENCES public.experiment_repetitions(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES public.user_profiles(id),
phase_name TEXT NOT NULL CHECK (phase_name IN ('pre-soaking', 'air-drying', 'cracking', 'shelling')),
status TEXT NOT NULL DEFAULT 'draft' CHECK (status IN ('draft', 'submitted', 'withdrawn')),
draft_name TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
submitted_at TIMESTAMP WITH TIME ZONE,
withdrawn_at TIMESTAMP WITH TIME ZONE
);
-- Create experiment_phase_data table for phase-specific measurements
CREATE TABLE IF NOT EXISTS public.experiment_phase_data (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
phase_draft_id UUID NOT NULL REFERENCES public.experiment_phase_drafts(id) ON DELETE CASCADE,
phase_name TEXT NOT NULL CHECK (phase_name IN ('pre-soaking', 'air-drying', 'cracking', 'shelling')),
-- Pre-soaking phase data
batch_initial_weight_lbs FLOAT CHECK (batch_initial_weight_lbs >= 0),
initial_shell_moisture_pct FLOAT CHECK (initial_shell_moisture_pct >= 0 AND initial_shell_moisture_pct <= 100),
initial_kernel_moisture_pct FLOAT CHECK (initial_kernel_moisture_pct >= 0 AND initial_kernel_moisture_pct <= 100),
soaking_start_time TIMESTAMP WITH TIME ZONE,
-- Air-drying phase data
airdrying_start_time TIMESTAMP WITH TIME ZONE,
post_soak_weight_lbs FLOAT CHECK (post_soak_weight_lbs >= 0),
post_soak_kernel_moisture_pct FLOAT CHECK (post_soak_kernel_moisture_pct >= 0 AND post_soak_kernel_moisture_pct <= 100),
post_soak_shell_moisture_pct FLOAT CHECK (post_soak_shell_moisture_pct >= 0 AND post_soak_shell_moisture_pct <= 100),
avg_pecan_diameter_in FLOAT CHECK (avg_pecan_diameter_in >= 0),
-- Cracking phase data
cracking_start_time TIMESTAMP WITH TIME ZONE,
-- Shelling phase data
shelling_start_time TIMESTAMP WITH TIME ZONE,
bin_1_weight_lbs FLOAT CHECK (bin_1_weight_lbs >= 0),
bin_2_weight_lbs FLOAT CHECK (bin_2_weight_lbs >= 0),
bin_3_weight_lbs FLOAT CHECK (bin_3_weight_lbs >= 0),
discharge_bin_weight_lbs FLOAT CHECK (discharge_bin_weight_lbs >= 0),
bin_1_full_yield_oz FLOAT CHECK (bin_1_full_yield_oz >= 0),
bin_2_full_yield_oz FLOAT CHECK (bin_2_full_yield_oz >= 0),
bin_3_full_yield_oz FLOAT CHECK (bin_3_full_yield_oz >= 0),
bin_1_half_yield_oz FLOAT CHECK (bin_1_half_yield_oz >= 0),
bin_2_half_yield_oz FLOAT CHECK (bin_2_half_yield_oz >= 0),
bin_3_half_yield_oz FLOAT CHECK (bin_3_half_yield_oz >= 0),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
-- Constraint: One record per phase draft
CONSTRAINT unique_phase_per_draft UNIQUE (phase_draft_id, phase_name)
);
-- Create pecan_diameter_measurements table for individual diameter measurements
CREATE TABLE IF NOT EXISTS public.pecan_diameter_measurements (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
phase_data_id UUID NOT NULL REFERENCES public.experiment_phase_data(id) ON DELETE CASCADE,
measurement_number INTEGER NOT NULL CHECK (measurement_number >= 1 AND measurement_number <= 10),
diameter_in FLOAT NOT NULL CHECK (diameter_in >= 0),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
-- Constraint: Unique measurement number per phase data
CONSTRAINT unique_measurement_per_phase UNIQUE (phase_data_id, measurement_number)
);
-- =============================================
-- 6. INDEXES FOR PERFORMANCE
-- =============================================
-- User management indexes
CREATE INDEX IF NOT EXISTS idx_user_profiles_email ON public.user_profiles(email);
CREATE INDEX IF NOT EXISTS idx_user_profiles_status ON public.user_profiles(status);
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);
-- Experiment phases indexes
CREATE INDEX IF NOT EXISTS idx_experiment_phases_name ON public.experiment_phases(name);
CREATE INDEX IF NOT EXISTS idx_experiment_phases_created_by ON public.experiment_phases(created_by);
-- Experiments indexes
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_results_status ON public.experiments(results_status);
CREATE INDEX IF NOT EXISTS idx_experiments_completion_status ON public.experiments(completion_status);
CREATE INDEX IF NOT EXISTS idx_experiments_created_at ON public.experiments(created_at);
CREATE INDEX IF NOT EXISTS idx_experiments_phase_id ON public.experiments(phase_id);
-- Experiment repetitions indexes
CREATE INDEX IF NOT EXISTS idx_experiment_repetitions_experiment_id ON public.experiment_repetitions(experiment_id);
CREATE INDEX IF NOT EXISTS idx_experiment_repetitions_schedule_status ON public.experiment_repetitions(schedule_status);
CREATE INDEX IF NOT EXISTS idx_experiment_repetitions_completion_status ON public.experiment_repetitions(completion_status);
CREATE INDEX IF NOT EXISTS idx_experiment_repetitions_scheduled_date ON public.experiment_repetitions(scheduled_date);
CREATE INDEX IF NOT EXISTS idx_experiment_repetitions_created_by ON public.experiment_repetitions(created_by);
CREATE INDEX IF NOT EXISTS idx_experiment_repetitions_created_at ON public.experiment_repetitions(created_at);
CREATE INDEX IF NOT EXISTS idx_experiment_repetitions_is_locked ON public.experiment_repetitions(is_locked);
-- Data entry system indexes
CREATE INDEX IF NOT EXISTS idx_experiment_phase_drafts_experiment_id ON public.experiment_phase_drafts(experiment_id);
CREATE INDEX IF NOT EXISTS idx_experiment_phase_drafts_repetition_id ON public.experiment_phase_drafts(repetition_id);
CREATE INDEX IF NOT EXISTS idx_experiment_phase_drafts_user_id ON public.experiment_phase_drafts(user_id);
CREATE INDEX IF NOT EXISTS idx_experiment_phase_drafts_phase_name ON public.experiment_phase_drafts(phase_name);
CREATE INDEX IF NOT EXISTS idx_experiment_phase_drafts_status ON public.experiment_phase_drafts(status);
CREATE INDEX IF NOT EXISTS idx_experiment_phase_data_draft_id ON public.experiment_phase_data(phase_draft_id);
CREATE INDEX IF NOT EXISTS idx_experiment_phase_data_phase_name ON public.experiment_phase_data(phase_name);
CREATE INDEX IF NOT EXISTS idx_pecan_diameter_measurements_phase_data_id ON public.pecan_diameter_measurements(phase_data_id);
-- =============================================
-- 7. TRIGGERS AND FUNCTIONS
-- =============================================
-- Create updated_at trigger function
CREATE OR REPLACE FUNCTION public.handle_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Create triggers for updated_at
CREATE TRIGGER set_updated_at_roles
BEFORE UPDATE ON public.roles
FOR EACH ROW
EXECUTE FUNCTION public.handle_updated_at();
CREATE TRIGGER set_updated_at_user_profiles
BEFORE UPDATE ON public.user_profiles
FOR EACH ROW
EXECUTE FUNCTION public.handle_updated_at();
CREATE TRIGGER set_updated_at_experiment_phases
BEFORE UPDATE ON public.experiment_phases
FOR EACH ROW
EXECUTE FUNCTION public.handle_updated_at();
CREATE TRIGGER set_updated_at_experiments
BEFORE UPDATE ON public.experiments
FOR EACH ROW
EXECUTE FUNCTION public.handle_updated_at();
CREATE TRIGGER set_updated_at_experiment_repetitions
BEFORE UPDATE ON public.experiment_repetitions
FOR EACH ROW
EXECUTE FUNCTION public.handle_updated_at();
CREATE TRIGGER set_updated_at_experiment_phase_drafts
BEFORE UPDATE ON public.experiment_phase_drafts
FOR EACH ROW
EXECUTE FUNCTION public.handle_updated_at();
CREATE TRIGGER set_updated_at_experiment_phase_data
BEFORE UPDATE ON public.experiment_phase_data
FOR EACH ROW
EXECUTE FUNCTION public.handle_updated_at();
-- Function to validate repetition number doesn't exceed experiment's reps_required
CREATE OR REPLACE FUNCTION validate_repetition_number()
RETURNS TRIGGER AS $$
DECLARE
max_reps INTEGER;
BEGIN
-- Get the reps_required for this experiment
SELECT reps_required INTO max_reps
FROM public.experiments
WHERE id = NEW.experiment_id;
-- Check if repetition number exceeds the limit
IF NEW.repetition_number > max_reps THEN
RAISE EXCEPTION 'Repetition number % exceeds maximum allowed repetitions % for experiment',
NEW.repetition_number, max_reps;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Create trigger to validate repetition number
CREATE TRIGGER trigger_validate_repetition_number
BEFORE INSERT OR UPDATE ON public.experiment_repetitions
FOR EACH ROW
EXECUTE FUNCTION validate_repetition_number();
-- Function to handle phase draft status changes
CREATE OR REPLACE FUNCTION public.handle_phase_draft_status_change()
RETURNS TRIGGER AS $$
BEGIN
-- Set submitted_at when status changes to 'submitted'
IF NEW.status = 'submitted' AND OLD.status != 'submitted' THEN
NEW.submitted_at = NOW();
NEW.withdrawn_at = NULL;
END IF;
-- Set withdrawn_at when status changes to 'withdrawn'
IF NEW.status = 'withdrawn' AND OLD.status = 'submitted' THEN
NEW.withdrawn_at = NOW();
END IF;
-- Clear timestamps when status changes back to 'draft'
IF NEW.status = 'draft' AND OLD.status IN ('submitted', 'withdrawn') THEN
NEW.submitted_at = NULL;
NEW.withdrawn_at = NULL;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER set_timestamps_experiment_phase_drafts
BEFORE UPDATE ON public.experiment_phase_drafts
FOR EACH ROW
EXECUTE FUNCTION public.handle_phase_draft_status_change();
-- =============================================
-- 8. HELPER FUNCTIONS
-- =============================================
-- 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;
-- Function to generate secure temporary password
CREATE OR REPLACE FUNCTION public.generate_temp_password()
RETURNS TEXT AS $$
DECLARE
chars TEXT := 'ABCDEFGHJKMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789';
result TEXT := '';
i INTEGER;
BEGIN
FOR i IN 1..12 LOOP
result := result || substr(chars, floor(random() * length(chars) + 1)::integer, 1);
END LOOP;
RETURN result;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- Function to create user with roles (for admin use)
CREATE OR REPLACE FUNCTION public.create_user_with_roles(
user_email TEXT,
role_names TEXT[],
temp_password TEXT DEFAULT NULL
)
RETURNS JSON AS $$
DECLARE
new_user_id UUID;
role_record RECORD;
generated_password TEXT;
result JSON;
role_count INTEGER;
BEGIN
-- Only admins can create users
IF NOT public.is_admin() THEN
RAISE EXCEPTION 'Only administrators can create users';
END IF;
-- Validate that at least one role is provided
IF array_length(role_names, 1) IS NULL OR array_length(role_names, 1) = 0 THEN
RAISE EXCEPTION 'At least one role must be assigned to the user';
END IF;
-- Validate that all provided roles exist
SELECT COUNT(*) INTO role_count
FROM public.roles
WHERE name = ANY(role_names);
IF role_count != array_length(role_names, 1) THEN
RAISE EXCEPTION 'One or more specified roles do not exist';
END IF;
-- Check if user already exists
IF EXISTS (SELECT 1 FROM auth.users WHERE email = user_email) THEN
RAISE EXCEPTION 'User with email % already exists', user_email;
END IF;
-- Generate password if not provided
IF temp_password IS NULL THEN
generated_password := public.generate_temp_password();
ELSE
generated_password := temp_password;
END IF;
-- Generate new user ID
new_user_id := uuid_generate_v4();
-- Insert into auth.users (simulating user creation)
INSERT INTO auth.users (
instance_id,
id,
aud,
role,
email,
encrypted_password,
email_confirmed_at,
created_at,
updated_at,
confirmation_token,
email_change,
email_change_token_new,
recovery_token
) VALUES (
'00000000-0000-0000-0000-000000000000',
new_user_id,
'authenticated',
'authenticated',
user_email,
crypt(generated_password, gen_salt('bf')),
NOW(),
NOW(),
NOW(),
'',
'',
'',
''
);
-- Insert user profile
INSERT INTO public.user_profiles (id, email, status)
VALUES (new_user_id, user_email, 'active');
-- Assign roles through the user_roles junction table
FOR role_record IN
SELECT id FROM public.roles WHERE name = ANY(role_names)
LOOP
INSERT INTO public.user_roles (user_id, role_id, assigned_by)
VALUES (new_user_id, role_record.id, auth.uid());
END LOOP;
-- Return result
result := json_build_object(
'user_id', new_user_id,
'email', user_email,
'temp_password', generated_password,
'roles', role_names,
'status', 'active'
);
RETURN result;
EXCEPTION
WHEN OTHERS THEN
-- Clean up any partial inserts
DELETE FROM public.user_roles WHERE user_id = new_user_id;
DELETE FROM public.user_profiles WHERE id = new_user_id;
DELETE FROM auth.users WHERE id = new_user_id;
RAISE;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- =============================================
-- 9. ROW LEVEL SECURITY (RLS)
-- =============================================
-- 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.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.experiment_phase_drafts ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.experiment_phase_data ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.pecan_diameter_measurements ENABLE ROW LEVEL SECURITY;
-- Roles table policies
CREATE POLICY "Anyone can read roles" ON public.roles
FOR SELECT USING (true);
CREATE POLICY "Only admins can insert roles" ON public.roles
FOR INSERT WITH CHECK (public.is_admin());
CREATE POLICY "Only admins can update roles" ON public.roles
FOR UPDATE USING (public.is_admin());
CREATE POLICY "Only admins can delete roles" ON public.roles
FOR DELETE USING (public.is_admin());
-- User profiles policies
CREATE POLICY "Users can read own profile, admins can read all" ON public.user_profiles
FOR SELECT USING (
auth.uid() = id OR public.is_admin()
);
CREATE POLICY "Only admins can insert user profiles" ON public.user_profiles
FOR INSERT WITH CHECK (public.is_admin());
CREATE POLICY "Users can update own profile, admins can update any" ON public.user_profiles
FOR UPDATE USING (
auth.uid() = id OR public.is_admin()
);
CREATE POLICY "Only admins can delete user profiles" ON public.user_profiles
FOR DELETE USING (public.is_admin());
-- User roles policies
CREATE POLICY "Users can read own roles, admins can read all" ON public.user_roles
FOR SELECT USING (
user_id = auth.uid() OR public.is_admin()
);
CREATE POLICY "Only admins can assign roles" ON public.user_roles
FOR INSERT WITH CHECK (public.is_admin());
CREATE POLICY "Only admins can update role assignments" ON public.user_roles
FOR UPDATE USING (public.is_admin());
CREATE POLICY "Only admins can remove role assignments" ON public.user_roles
FOR DELETE USING (public.is_admin());
-- Experiment phases policies
CREATE POLICY "experiment_phases_select_policy" ON public.experiment_phases
FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "experiment_phases_insert_policy" ON public.experiment_phases
FOR INSERT
TO authenticated
WITH CHECK (public.can_manage_experiments());
CREATE POLICY "experiment_phases_update_policy" ON public.experiment_phases
FOR UPDATE
TO authenticated
USING (public.can_manage_experiments())
WITH CHECK (public.can_manage_experiments());
CREATE POLICY "experiment_phases_delete_policy" ON public.experiment_phases
FOR DELETE
TO authenticated
USING (public.is_admin());
-- Experiments policies
CREATE POLICY "experiments_select_policy" ON public.experiments
FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "experiments_insert_policy" ON public.experiments
FOR INSERT
TO authenticated
WITH CHECK (public.can_manage_experiments());
CREATE POLICY "experiments_update_policy" ON public.experiments
FOR UPDATE
TO authenticated
USING (public.can_manage_experiments())
WITH CHECK (public.can_manage_experiments());
CREATE POLICY "experiments_delete_policy" ON public.experiments
FOR DELETE
TO authenticated
USING (public.is_admin());
-- Experiment repetitions policies
CREATE POLICY "Users can view experiment repetitions" ON public.experiment_repetitions
FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "Users can create experiment repetitions" ON public.experiment_repetitions
FOR INSERT WITH CHECK (
experiment_id IN (
SELECT id FROM public.experiments
WHERE created_by = auth.uid()
)
OR public.is_admin()
);
CREATE POLICY "Users can update experiment repetitions" ON public.experiment_repetitions
FOR UPDATE USING (
experiment_id IN (
SELECT id FROM public.experiments
WHERE created_by = auth.uid()
)
OR public.is_admin()
);
CREATE POLICY "Users can delete experiment repetitions" ON public.experiment_repetitions
FOR DELETE USING (
experiment_id IN (
SELECT id FROM public.experiments
WHERE created_by = auth.uid()
)
OR public.is_admin()
);
-- Experiment phase drafts policies
CREATE POLICY "experiment_phase_drafts_select_policy" ON public.experiment_phase_drafts
FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "experiment_phase_drafts_insert_policy" ON public.experiment_phase_drafts
FOR INSERT
TO authenticated
WITH CHECK (user_id = auth.uid());
CREATE POLICY "experiment_phase_drafts_update_policy" ON public.experiment_phase_drafts
FOR UPDATE
TO authenticated
USING (
(user_id = auth.uid() AND NOT EXISTS (
SELECT 1 FROM public.experiment_repetitions
WHERE id = repetition_id AND is_locked = true
)) OR public.is_admin()
)
WITH CHECK (
(user_id = auth.uid() AND NOT EXISTS (
SELECT 1 FROM public.experiment_repetitions
WHERE id = repetition_id AND is_locked = true
)) OR public.is_admin()
);
CREATE POLICY "experiment_phase_drafts_delete_policy" ON public.experiment_phase_drafts
FOR DELETE
TO authenticated
USING (
(user_id = auth.uid() AND status = 'draft' AND NOT EXISTS (
SELECT 1 FROM public.experiment_repetitions
WHERE id = repetition_id AND is_locked = true
)) OR public.is_admin()
);
-- Experiment phase data policies
CREATE POLICY "experiment_phase_data_select_policy" ON public.experiment_phase_data
FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "experiment_phase_data_insert_policy" ON public.experiment_phase_data
FOR INSERT
TO authenticated
WITH CHECK (
EXISTS (
SELECT 1 FROM public.experiment_phase_drafts epd
WHERE epd.id = phase_draft_id AND epd.user_id = auth.uid()
)
);
CREATE POLICY "experiment_phase_data_update_policy" ON public.experiment_phase_data
FOR UPDATE
TO authenticated
USING (
EXISTS (
SELECT 1 FROM public.experiment_phase_drafts epd
WHERE epd.id = phase_draft_id AND epd.user_id = auth.uid()
)
)
WITH CHECK (
EXISTS (
SELECT 1 FROM public.experiment_phase_drafts epd
WHERE epd.id = phase_draft_id AND epd.user_id = auth.uid()
)
);
CREATE POLICY "experiment_phase_data_delete_policy" ON public.experiment_phase_data
FOR DELETE
TO authenticated
USING (
EXISTS (
SELECT 1 FROM public.experiment_phase_drafts epd
WHERE epd.id = phase_draft_id AND epd.user_id = auth.uid() AND epd.status = 'draft'
)
);
-- Pecan diameter measurements policies
CREATE POLICY "pecan_diameter_measurements_select_policy" ON public.pecan_diameter_measurements
FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "pecan_diameter_measurements_insert_policy" ON public.pecan_diameter_measurements
FOR INSERT
TO authenticated
WITH CHECK (
EXISTS (
SELECT 1 FROM public.experiment_phase_data epd
JOIN public.experiment_phase_drafts epdr ON epd.phase_draft_id = epdr.id
WHERE epd.id = phase_data_id AND epdr.user_id = auth.uid()
)
);
CREATE POLICY "pecan_diameter_measurements_update_policy" ON public.pecan_diameter_measurements
FOR UPDATE
TO authenticated
USING (
EXISTS (
SELECT 1 FROM public.experiment_phase_data epd
JOIN public.experiment_phase_drafts epdr ON epd.phase_draft_id = epdr.id
WHERE epd.id = phase_data_id AND epdr.user_id = auth.uid()
)
)
WITH CHECK (
EXISTS (
SELECT 1 FROM public.experiment_phase_data epd
JOIN public.experiment_phase_drafts epdr ON epd.phase_draft_id = epdr.id
WHERE epd.id = phase_data_id AND epdr.user_id = auth.uid()
)
);
CREATE POLICY "pecan_diameter_measurements_delete_policy" ON public.pecan_diameter_measurements
FOR DELETE
TO authenticated
USING (
EXISTS (
SELECT 1 FROM public.experiment_phase_data epd
JOIN public.experiment_phase_drafts epdr ON epd.phase_draft_id = epdr.id
WHERE epd.id = phase_data_id AND epdr.user_id = auth.uid() AND epdr.status = 'draft'
)
);
-- =============================================
-- 10. COMMENTS FOR DOCUMENTATION
-- =============================================
COMMENT ON TABLE public.roles IS 'System roles for user access control';
COMMENT ON TABLE public.user_profiles IS 'Extended user profiles linked to auth.users';
COMMENT ON TABLE public.user_roles IS 'Many-to-many relationship between users and roles';
COMMENT ON TABLE public.experiment_phases IS 'Groups experiments into logical phases for better organization and navigation';
COMMENT ON TABLE public.experiments IS 'Stores experiment definitions for pecan processing with parameters and status tracking';
COMMENT ON TABLE public.experiment_repetitions IS 'Individual repetitions of experiment blueprints that can be scheduled and executed';
COMMENT ON TABLE public.experiment_phase_drafts IS 'Phase-specific draft records for experiment data entry with status tracking';
COMMENT ON TABLE public.experiment_phase_data IS 'Phase-specific measurement data for experiments';
COMMENT ON TABLE public.pecan_diameter_measurements IS 'Individual pecan diameter measurements (up to 10 per phase)';

View File

@@ -1,341 +0,0 @@
-- Add Conductor Availability and Experiment Phase Assignment Tables
-- This migration adds tables for conductor availability management and future experiment scheduling
-- =============================================
-- 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,
available_from TIMESTAMP WITH TIME ZONE NOT NULL,
available_to TIMESTAMP WITH TIME ZONE NOT NULL,
notes TEXT, -- Optional notes about the availability
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', '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 available_to is after available_from
CONSTRAINT valid_time_range CHECK (available_to > available_from),
-- Ensure availability is in the future (can be modified if needed for past records)
CONSTRAINT future_availability CHECK (available_from >= NOW() - INTERVAL '1 day')
);
-- =============================================
-- 2. EXPERIMENT PHASE ASSIGNMENTS TABLE (Future Scheduling)
-- =============================================
-- 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_id UUID NOT NULL REFERENCES public.experiments(id) ON DELETE CASCADE,
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),
-- 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);
CREATE INDEX IF NOT EXISTS idx_conductor_availability_status ON public.conductor_availability(status);
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_id ON public.experiment_phase_assignments(experiment_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
-- =============================================
-- Function to check for overlapping availabilities
CREATE OR REPLACE FUNCTION public.check_availability_overlap()
RETURNS TRIGGER AS $$
DECLARE
overlap_count INTEGER;
BEGIN
-- Check for overlapping availabilities for the same user
SELECT COUNT(*) INTO overlap_count
FROM public.conductor_availability
WHERE user_id = NEW.user_id
AND id != COALESCE(NEW.id, '00000000-0000-0000-0000-000000000000'::UUID)
AND status = 'active'
AND (
-- New availability starts during an existing one
(NEW.available_from >= available_from AND NEW.available_from < available_to) OR
-- New availability ends during an existing one
(NEW.available_to > available_from AND NEW.available_to <= available_to) OR
-- New availability completely contains an existing one
(NEW.available_from <= available_from AND NEW.available_to >= available_to) OR
-- Existing availability completely contains the new one
(available_from <= NEW.available_from AND available_to >= NEW.available_to)
);
IF overlap_count > 0 THEN
RAISE EXCEPTION 'Availability overlaps with existing availability for user %. Please adjust the time range or cancel the conflicting availability.', NEW.user_id;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Function to automatically adjust overlapping availabilities (alternative approach)
CREATE OR REPLACE FUNCTION public.adjust_overlapping_availability()
RETURNS TRIGGER AS $$
DECLARE
overlapping_record RECORD;
BEGIN
-- Find overlapping availabilities and adjust them
FOR overlapping_record IN
SELECT id, available_from, available_to
FROM public.conductor_availability
WHERE user_id = NEW.user_id
AND id != COALESCE(NEW.id, '00000000-0000-0000-0000-000000000000'::UUID)
AND status = 'active'
AND (
(NEW.available_from >= available_from AND NEW.available_from < available_to) OR
(NEW.available_to > available_from AND NEW.available_to <= available_to) OR
(NEW.available_from <= available_from AND NEW.available_to >= available_to) OR
(available_from <= NEW.available_from AND available_to >= NEW.available_to)
)
LOOP
-- Adjust the overlapping record to end where the new one starts
IF overlapping_record.available_from < NEW.available_from AND overlapping_record.available_to > NEW.available_from THEN
UPDATE public.conductor_availability
SET available_to = NEW.available_from,
updated_at = NOW()
WHERE id = overlapping_record.id;
END IF;
-- If the overlapping record starts after the new one, adjust it to start where the new one ends
IF overlapping_record.available_from < NEW.available_to AND overlapping_record.available_to > NEW.available_to THEN
UPDATE public.conductor_availability
SET available_from = NEW.available_to,
updated_at = NOW()
WHERE id = overlapping_record.id;
END IF;
-- If the overlapping record is completely contained within the new one, cancel it
IF overlapping_record.available_from >= NEW.available_from AND overlapping_record.available_to <= NEW.available_to THEN
UPDATE public.conductor_availability
SET status = 'cancelled',
updated_at = NOW()
WHERE id = overlapping_record.id;
END IF;
END LOOP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- =============================================
-- 5. TRIGGERS
-- =============================================
-- Create trigger for updated_at on conductor_availability
CREATE TRIGGER set_updated_at_conductor_availability
BEFORE UPDATE ON public.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 (strict approach)
CREATE TRIGGER trigger_check_availability_overlap
BEFORE INSERT OR UPDATE ON public.conductor_availability
FOR EACH ROW
EXECUTE FUNCTION public.check_availability_overlap();
-- Alternative trigger to automatically adjust overlapping availabilities (uncomment if preferred)
-- CREATE TRIGGER trigger_adjust_overlapping_availability
-- BEFORE INSERT OR UPDATE ON public.conductor_availability
-- FOR EACH ROW
-- EXECUTE FUNCTION public.adjust_overlapping_availability();
-- =============================================
-- 6. 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,
end_time TIMESTAMP WITH TIME ZONE
)
RETURNS TABLE (
user_id UUID,
email TEXT,
available_from TIMESTAMP WITH TIME ZONE,
available_to TIMESTAMP WITH TIME ZONE
) AS $$
BEGIN
RETURN QUERY
SELECT
ca.user_id,
up.email,
ca.available_from,
ca.available_to
FROM public.conductor_availability ca
JOIN public.user_profiles up ON ca.user_id = up.id
JOIN public.user_roles ur ON up.id = ur.user_id
JOIN public.roles r ON ur.role_id = r.id
WHERE ca.status = 'active'
AND r.name = 'conductor'
AND ca.available_from <= start_time
AND ca.available_to >= end_time
ORDER BY up.email;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- Function to check if a conductor is available for a specific time range
CREATE OR REPLACE FUNCTION public.is_conductor_available(
conductor_user_id UUID,
start_time TIMESTAMP WITH TIME ZONE,
end_time TIMESTAMP WITH TIME ZONE
)
RETURNS BOOLEAN AS $$
DECLARE
availability_count INTEGER;
BEGIN
SELECT COUNT(*) INTO availability_count
FROM public.conductor_availability
WHERE user_id = conductor_user_id
AND status = 'active'
AND available_from <= start_time
AND available_to >= end_time;
RETURN availability_count > 0;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- =============================================
-- 7. ROW LEVEL SECURITY (RLS)
-- =============================================
-- Enable RLS on new tables
ALTER TABLE public.conductor_availability ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.experiment_phase_assignments ENABLE ROW LEVEL SECURITY;
-- Conductor availability policies
CREATE POLICY "conductor_availability_select_policy" ON public.conductor_availability
FOR SELECT
TO authenticated
USING (
-- Users can view their own availability, admins can view all
user_id = auth.uid() OR public.is_admin()
);
CREATE POLICY "conductor_availability_insert_policy" ON public.conductor_availability
FOR INSERT
TO authenticated
WITH CHECK (
-- Users can create their own availability, admins can create for anyone
(user_id = auth.uid() AND created_by = auth.uid()) OR public.is_admin()
);
CREATE POLICY "conductor_availability_update_policy" ON public.conductor_availability
FOR UPDATE
TO authenticated
USING (
-- Users can update their own availability, admins can update any
user_id = auth.uid() OR public.is_admin()
)
WITH CHECK (
-- Users can update their own availability, admins can update any
user_id = auth.uid() OR public.is_admin()
);
CREATE POLICY "conductor_availability_delete_policy" ON public.conductor_availability
FOR DELETE
TO authenticated
USING (
-- Users can delete their own availability, admins can delete any
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()
);
-- =============================================
-- 8. 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';

View File

@@ -1,474 +0,0 @@
-- Migration: Restructure experiment phases and add machine types
-- This migration restructures the experiment system to support separate phase tables
-- and machine-specific parameters
-- =============================================
-- 1. 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)
);
-- Machine types will be inserted in seed.sql after user profiles are created
-- =============================================
-- 2. UPDATE EXPERIMENT_PHASES TABLE
-- =============================================
-- Add phase selection columns to experiment_phases
ALTER TABLE public.experiment_phases
ADD COLUMN IF NOT EXISTS has_soaking BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN IF NOT EXISTS has_airdrying BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN IF NOT EXISTS has_cracking BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN IF NOT EXISTS has_shelling BOOLEAN NOT NULL DEFAULT false;
-- Add constraint to ensure at least one phase is selected
ALTER TABLE public.experiment_phases
ADD CONSTRAINT check_at_least_one_phase
CHECK (has_soaking = true OR has_airdrying = true OR has_cracking = true OR has_shelling = true);
-- =============================================
-- 3. CREATE 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)
);
-- =============================================
-- 4. 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 CHECK (jig_displacement_inches >= 0),
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)
);
-- =============================================
-- 5. UPDATE EXPERIMENTS TABLE
-- =============================================
-- Add weight_per_repetition column
ALTER TABLE public.experiments
ADD COLUMN IF NOT EXISTS weight_per_repetition_lbs DOUBLE PRECISION NOT NULL DEFAULT 0 CHECK (weight_per_repetition_lbs > 0);
-- Remove phase-specific parameters (these will be moved to phase tables)
-- Note: We'll keep these columns for now to avoid data loss, but they should be deprecated
-- Make old columns nullable to support new schema experiments
ALTER TABLE public.experiments
ALTER COLUMN soaking_duration_hr DROP NOT NULL,
ALTER COLUMN air_drying_time_min DROP NOT NULL,
ALTER COLUMN plate_contact_frequency_hz DROP NOT NULL,
ALTER COLUMN throughput_rate_pecans_sec DROP NOT NULL,
ALTER COLUMN crush_amount_in DROP NOT NULL,
ALTER COLUMN entry_exit_height_diff_in DROP NOT NULL;
-- =============================================
-- 6. ADD FOREIGN KEY CONSTRAINTS
-- =============================================
-- 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;
-- =============================================
-- 7. CREATE INDEXES FOR PERFORMANCE
-- =============================================
-- Create indexes for better query performance
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);
-- =============================================
-- 8. 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();
-- =============================================
-- 9. 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.id as soaking_id,
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.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.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;
-- =============================================
-- 10. GRANT PERMISSIONS
-- =============================================
-- Grant permissions for new tables
GRANT ALL ON public.machine_types 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;
-- =============================================
-- 11. UPDATE RLS POLICIES
-- =============================================
-- Enable RLS on new tables
ALTER TABLE public.machine_types 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;
-- 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 RLS policies for phase tables (similar to experiments)
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');
-- Similar policies for other phase tables
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');

View File

@@ -1,49 +0,0 @@
-- Add password reset function for admin use
-- This migration adds a function to reset user passwords back to the default "password123"
-- Function to reset user password (admin only)
CREATE OR REPLACE FUNCTION public.reset_user_password(
target_user_id UUID
)
RETURNS JSON AS $$
DECLARE
user_email TEXT;
result JSON;
BEGIN
-- Only admins can reset passwords
IF NOT public.is_admin() THEN
RAISE EXCEPTION 'Only administrators can reset user passwords';
END IF;
-- Check if target user exists
SELECT email INTO user_email
FROM public.user_profiles
WHERE id = target_user_id;
IF user_email IS NULL THEN
RAISE EXCEPTION 'User not found';
END IF;
-- Update the password in auth.users table
UPDATE auth.users
SET
encrypted_password = crypt('password123', gen_salt('bf')),
updated_at = NOW()
WHERE id = target_user_id;
-- Return result
result := json_build_object(
'user_id', target_user_id,
'email', user_email,
'new_password', 'password123',
'reset_at', NOW()
);
RETURN result;
EXCEPTION
WHEN OTHERS THEN
RAISE;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

View File

@@ -1,12 +0,0 @@
-- Add first_name and last_name fields to user_profiles table
-- This migration adds name fields to store user's first and last names
-- Add first_name and last_name columns to user_profiles table
ALTER TABLE public.user_profiles
ADD COLUMN first_name TEXT,
ADD COLUMN last_name TEXT;
-- Add comments for documentation
COMMENT ON COLUMN public.user_profiles.first_name IS 'User first name';
COMMENT ON COLUMN public.user_profiles.last_name IS 'User last name';

View File

@@ -1,62 +0,0 @@
-- Add change password function for users
-- This migration adds a function to allow users to change their own password
-- Function to change user password (user can only change their own password)
CREATE OR REPLACE FUNCTION public.change_user_password(
current_password TEXT,
new_password TEXT
)
RETURNS JSON AS $$
DECLARE
user_id UUID;
user_email TEXT;
result JSON;
BEGIN
-- Get current user ID
user_id := auth.uid();
IF user_id IS NULL THEN
RAISE EXCEPTION 'User not authenticated';
END IF;
-- Get user email
SELECT email INTO user_email
FROM public.user_profiles
WHERE id = user_id;
IF user_email IS NULL THEN
RAISE EXCEPTION 'User profile not found';
END IF;
-- Verify current password
IF NOT EXISTS (
SELECT 1
FROM auth.users
WHERE id = user_id
AND encrypted_password = crypt(current_password, encrypted_password)
) THEN
RAISE EXCEPTION 'Current password is incorrect';
END IF;
-- Update the password in auth.users table
UPDATE auth.users
SET
encrypted_password = crypt(new_password, gen_salt('bf')),
updated_at = NOW()
WHERE id = user_id;
-- Return result
result := json_build_object(
'user_id', user_id,
'email', user_email,
'password_changed_at', NOW()
);
RETURN result;
EXCEPTION
WHEN OTHERS THEN
RAISE;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

View File

@@ -1,364 +0,0 @@
-- Phase 2 JC Experiments Seed Data (Corrected)
-- This file contains all Phase 2 JC experiments from phase_2_JC_experimental_run_sheet.csv
-- Each experiment has 3 repetitions, and each row represents one repetition
-- Updated to match the actual CSV data with correct experiment numbers and parameters
-- =============================================
-- INSERT PHASE 2 JC EXPERIMENTS
-- =============================================
-- First, insert unique experiments (based on experiment_number from CSV: 0-19)
INSERT INTO public.experiments (
experiment_number,
reps_required,
results_status,
completion_status,
phase_id,
created_by
) VALUES
-- Phase 2 JC Experiments 0-19 (matching CSV data)
(0, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(1, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(2, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(3, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(4, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(5, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(6, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(7, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(8, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(9, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(10, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(11, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(12, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(13, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(14, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(15, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(16, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(17, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(18, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(19, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com'))
ON CONFLICT (experiment_number, phase_id) DO NOTHING;
-- =============================================
-- CREATE SOAKING PHASE RECORDS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create soaking records for Phase 2 JC experiments (0-19) with data from CSV
INSERT INTO public.soaking (
experiment_id,
scheduled_start_time,
soaking_duration_minutes,
scheduled_end_time,
created_by
)
SELECT
e.id,
NOW() + (e.experiment_number + 1) * INTERVAL '1 day',
CASE e.experiment_number
WHEN 0 THEN 34 * 60 -- 34 hours = 2040 minutes
WHEN 1 THEN 24 * 60 -- 24 hours = 1440 minutes
WHEN 2 THEN 38 * 60 -- 38 hours = 2280 minutes
WHEN 3 THEN 11 * 60 -- 11 hours = 660 minutes
WHEN 4 THEN 13 * 60 -- 13 hours = 780 minutes
WHEN 5 THEN 30 * 60 -- 30 hours = 1800 minutes
WHEN 6 THEN 10 * 60 -- 10 hours = 600 minutes
WHEN 7 THEN 15 * 60 -- 15 hours = 900 minutes
WHEN 8 THEN 27 * 60 -- 27 hours = 1620 minutes
WHEN 9 THEN 32 * 60 -- 32 hours = 1920 minutes
WHEN 10 THEN 26 * 60 -- 26 hours = 1560 minutes
WHEN 11 THEN 24 * 60 -- 24 hours = 1440 minutes
WHEN 12 THEN 28 * 60 -- 28 hours = 1680 minutes
WHEN 13 THEN 21 * 60 -- 21 hours = 1260 minutes
WHEN 14 THEN 22 * 60 -- 22 hours = 1320 minutes
WHEN 15 THEN 16 * 60 -- 16 hours = 960 minutes
WHEN 16 THEN 20 * 60 -- 20 hours = 1200 minutes
WHEN 17 THEN 34 * 60 -- 34 hours = 2040 minutes
WHEN 18 THEN 18 * 60 -- 18 hours = 1080 minutes
WHEN 19 THEN 11 * 60 -- 11 hours = 660 minutes
END,
NOW() + (e.experiment_number + 1) * INTERVAL '1 day' +
CASE e.experiment_number
WHEN 0 THEN 34 * 60 * INTERVAL '1 minute' -- 34 hours = 2040 minutes
WHEN 1 THEN 24 * 60 * INTERVAL '1 minute' -- 24 hours = 1440 minutes
WHEN 2 THEN 38 * 60 * INTERVAL '1 minute' -- 38 hours = 2280 minutes
WHEN 3 THEN 11 * 60 * INTERVAL '1 minute' -- 11 hours = 660 minutes
WHEN 4 THEN 13 * 60 * INTERVAL '1 minute' -- 13 hours = 780 minutes
WHEN 5 THEN 30 * 60 * INTERVAL '1 minute' -- 30 hours = 1800 minutes
WHEN 6 THEN 10 * 60 * INTERVAL '1 minute' -- 10 hours = 600 minutes
WHEN 7 THEN 15 * 60 * INTERVAL '1 minute' -- 15 hours = 900 minutes
WHEN 8 THEN 27 * 60 * INTERVAL '1 minute' -- 27 hours = 1620 minutes
WHEN 9 THEN 32 * 60 * INTERVAL '1 minute' -- 32 hours = 1920 minutes
WHEN 10 THEN 26 * 60 * INTERVAL '1 minute' -- 26 hours = 1560 minutes
WHEN 11 THEN 24 * 60 * INTERVAL '1 minute' -- 24 hours = 1440 minutes
WHEN 12 THEN 28 * 60 * INTERVAL '1 minute' -- 28 hours = 1680 minutes
WHEN 13 THEN 21 * 60 * INTERVAL '1 minute' -- 21 hours = 1260 minutes
WHEN 14 THEN 22 * 60 * INTERVAL '1 minute' -- 22 hours = 1320 minutes
WHEN 15 THEN 16 * 60 * INTERVAL '1 minute' -- 16 hours = 960 minutes
WHEN 16 THEN 20 * 60 * INTERVAL '1 minute' -- 20 hours = 1200 minutes
WHEN 17 THEN 34 * 60 * INTERVAL '1 minute' -- 34 hours = 2040 minutes
WHEN 18 THEN 18 * 60 * INTERVAL '1 minute' -- 18 hours = 1080 minutes
WHEN 19 THEN 11 * 60 * INTERVAL '1 minute' -- 11 hours = 660 minutes
END,
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 0 AND 19
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE AIRDRYING PHASE RECORDS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create airdrying records for Phase 2 JC experiments (0-19) with data from CSV
INSERT INTO public.airdrying (
experiment_id,
scheduled_start_time,
duration_minutes,
scheduled_end_time,
created_by
)
SELECT
e.id,
NOW() + (e.experiment_number + 1) * INTERVAL '1 day' + INTERVAL '2 days', -- Start 2 days after soaking
CASE e.experiment_number
WHEN 0 THEN 19 -- 19 minutes
WHEN 1 THEN 27 -- 27 minutes
WHEN 2 THEN 10 -- 10 minutes
WHEN 3 THEN 36 -- 36 minutes
WHEN 4 THEN 41 -- 41 minutes
WHEN 5 THEN 33 -- 33 minutes
WHEN 6 THEN 22 -- 22 minutes
WHEN 7 THEN 30 -- 30 minutes
WHEN 8 THEN 12 -- 12 minutes
WHEN 9 THEN 26 -- 26 minutes
WHEN 10 THEN 60 -- 60 minutes
WHEN 11 THEN 59 -- 59 minutes
WHEN 12 THEN 59 -- 59 minutes
WHEN 13 THEN 59 -- 59 minutes
WHEN 14 THEN 59 -- 59 minutes
WHEN 15 THEN 60 -- 60 minutes
WHEN 16 THEN 59 -- 59 minutes
WHEN 17 THEN 60 -- 60 minutes
WHEN 18 THEN 49 -- 49 minutes
WHEN 19 THEN 25 -- 25 minutes
END,
NOW() + (e.experiment_number + 1) * INTERVAL '1 day' + INTERVAL '2 days' +
CASE e.experiment_number
WHEN 0 THEN 19 * INTERVAL '1 minute' -- 19 minutes
WHEN 1 THEN 27 * INTERVAL '1 minute' -- 27 minutes
WHEN 2 THEN 10 * INTERVAL '1 minute' -- 10 minutes
WHEN 3 THEN 36 * INTERVAL '1 minute' -- 36 minutes
WHEN 4 THEN 41 * INTERVAL '1 minute' -- 41 minutes
WHEN 5 THEN 33 * INTERVAL '1 minute' -- 33 minutes
WHEN 6 THEN 22 * INTERVAL '1 minute' -- 22 minutes
WHEN 7 THEN 30 * INTERVAL '1 minute' -- 30 minutes
WHEN 8 THEN 12 * INTERVAL '1 minute' -- 12 minutes
WHEN 9 THEN 26 * INTERVAL '1 minute' -- 26 minutes
WHEN 10 THEN 60 * INTERVAL '1 minute' -- 60 minutes
WHEN 11 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 12 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 13 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 14 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 15 THEN 60 * INTERVAL '1 minute' -- 60 minutes
WHEN 16 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 17 THEN 60 * INTERVAL '1 minute' -- 60 minutes
WHEN 18 THEN 49 * INTERVAL '1 minute' -- 49 minutes
WHEN 19 THEN 25 * INTERVAL '1 minute' -- 25 minutes
END,
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 0 AND 19
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE CRACKING PHASE RECORDS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create cracking records for Phase 2 JC experiments (0-19)
INSERT INTO public.cracking (
experiment_id,
machine_type_id,
scheduled_start_time,
created_by
)
SELECT
e.id,
(SELECT id FROM public.machine_types WHERE name = 'JC Cracker'),
NOW() + (e.experiment_number + 1) * INTERVAL '1 day' + INTERVAL '3 days', -- Start 3 days after soaking
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 0 AND 19
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE JC CRACKER PARAMETERS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create JC cracker parameters for Phase 2 JC experiments (0-19) with data from CSV
INSERT INTO public.jc_cracker_parameters (
cracking_id,
plate_contact_frequency_hz,
throughput_rate_pecans_sec,
crush_amount_in,
entry_exit_height_diff_in
)
SELECT
c.id,
CASE e.experiment_number
WHEN 0 THEN 53.0
WHEN 1 THEN 34.0
WHEN 2 THEN 60.0
WHEN 3 THEN 42.0
WHEN 4 THEN 41.0
WHEN 5 THEN 30.0
WHEN 6 THEN 37.0
WHEN 7 THEN 35.0
WHEN 8 THEN 55.0
WHEN 9 THEN 47.0
WHEN 10 THEN 44.0
WHEN 11 THEN 42.0
WHEN 12 THEN 37.0
WHEN 13 THEN 41.0
WHEN 14 THEN 45.0
WHEN 15 THEN 30.0
WHEN 16 THEN 41.0
WHEN 17 THEN 34.0
WHEN 18 THEN 38.0
WHEN 19 THEN 56.0
END,
CASE e.experiment_number
WHEN 0 THEN 28.0
WHEN 1 THEN 29.0
WHEN 2 THEN 28.0
WHEN 3 THEN 13.0
WHEN 4 THEN 38.0
WHEN 5 THEN 36.0
WHEN 6 THEN 30.0
WHEN 7 THEN 32.0
WHEN 8 THEN 24.0
WHEN 9 THEN 26.0
WHEN 10 THEN 12.0
WHEN 11 THEN 25.0
WHEN 12 THEN 23.0
WHEN 13 THEN 21.0
WHEN 14 THEN 17.0
WHEN 15 THEN 24.0
WHEN 16 THEN 14.0
WHEN 17 THEN 29.0
WHEN 18 THEN 35.0
WHEN 19 THEN 34.0
END,
CASE e.experiment_number
WHEN 0 THEN 0.05
WHEN 1 THEN 0.03
WHEN 2 THEN 0.06
WHEN 3 THEN 0.07
WHEN 4 THEN 0.05
WHEN 5 THEN 0.05
WHEN 6 THEN 0.06
WHEN 7 THEN 0.05
WHEN 8 THEN 0.04
WHEN 9 THEN 0.07
WHEN 10 THEN 0.08
WHEN 11 THEN 0.07
WHEN 12 THEN 0.06
WHEN 13 THEN 0.06
WHEN 14 THEN 0.07
WHEN 15 THEN 0.07
WHEN 16 THEN 0.07
WHEN 17 THEN 0.07
WHEN 18 THEN 0.07
WHEN 19 THEN 0.06
END,
CASE e.experiment_number
WHEN 0 THEN -0.09
WHEN 1 THEN 0.01
WHEN 2 THEN -0.10
WHEN 3 THEN -0.07
WHEN 4 THEN 0.03
WHEN 5 THEN -0.04
WHEN 6 THEN 0.02
WHEN 7 THEN -0.07
WHEN 8 THEN 0.04
WHEN 9 THEN 0.03
WHEN 10 THEN -0.10
WHEN 11 THEN -0.05
WHEN 12 THEN -0.08
WHEN 13 THEN -0.09
WHEN 14 THEN -0.08
WHEN 15 THEN 0.02
WHEN 16 THEN 0.04
WHEN 17 THEN -0.09
WHEN 18 THEN -0.08
WHEN 19 THEN -0.09
END
FROM public.experiments e
JOIN public.cracking c ON c.experiment_id = e.id
WHERE e.experiment_number BETWEEN 0 AND 19
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE EXPERIMENT REPETITIONS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create experiment repetitions for Phase 2 JC experiments
-- Each experiment needs 3 repetitions
INSERT INTO public.experiment_repetitions (
experiment_id,
repetition_number,
completion_status,
created_by
)
SELECT
e.id,
rep_num,
false,
e.created_by
FROM public.experiments e
CROSS JOIN generate_series(1, 3) AS rep_num
WHERE e.experiment_number BETWEEN 0 AND 19
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;

View File

@@ -1,364 +0,0 @@
-- Phase 2 JC Experiments Seed Data
-- This file contains all Phase 2 JC experiments from phase_2_experimental_run_sheet.csv
-- Each experiment has 3 repetitions, and each row represents one repetition
-- Updated to use 1-based numbering per phase and composite primary key
-- =============================================
-- INSERT PHASE 2 JC EXPERIMENTS
-- =============================================
-- First, insert unique experiments (based on experiment_number)
INSERT INTO public.experiments (
experiment_number,
reps_required,
results_status,
completion_status,
phase_id,
created_by
) VALUES
-- Phase 2 JC Experiments 1-20 (1-based numbering)
(1, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(2, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(3, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(4, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(5, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(6, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(7, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(8, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(9, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(10, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(11, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(12, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(13, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(14, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(15, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(16, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(17, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(18, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(19, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(20, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com'))
ON CONFLICT (experiment_number, phase_id) DO NOTHING;
-- =============================================
-- CREATE SOAKING PHASE RECORDS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create soaking records for Phase 2 JC experiments (1-20)
INSERT INTO public.soaking (
experiment_id,
scheduled_start_time,
soaking_duration_hours,
scheduled_end_time,
created_by
)
SELECT
e.id,
NOW() + (e.experiment_number) * INTERVAL '1 day',
CASE e.experiment_number
WHEN 1 THEN 34 -- hours
WHEN 2 THEN 24
WHEN 3 THEN 38
WHEN 4 THEN 11
WHEN 5 THEN 13
WHEN 6 THEN 30
WHEN 7 THEN 10
WHEN 8 THEN 15
WHEN 9 THEN 27
WHEN 10 THEN 32
WHEN 11 THEN 26
WHEN 12 THEN 24
WHEN 13 THEN 28
WHEN 14 THEN 21
WHEN 15 THEN 22
WHEN 16 THEN 16
WHEN 17 THEN 20
WHEN 18 THEN 34
WHEN 19 THEN 18
WHEN 20 THEN 11
END,
NOW() + (e.experiment_number) * INTERVAL '1 day' +
CASE e.experiment_number
WHEN 1 THEN 34 * INTERVAL '1 hour'
WHEN 2 THEN 24 * INTERVAL '1 hour'
WHEN 3 THEN 38 * INTERVAL '1 hour'
WHEN 4 THEN 11 * INTERVAL '1 hour'
WHEN 5 THEN 13 * INTERVAL '1 hour'
WHEN 6 THEN 30 * INTERVAL '1 hour'
WHEN 7 THEN 10 * INTERVAL '1 hour'
WHEN 8 THEN 15 * INTERVAL '1 hour'
WHEN 9 THEN 27 * INTERVAL '1 hour'
WHEN 10 THEN 32 * INTERVAL '1 hour'
WHEN 11 THEN 26 * INTERVAL '1 hour'
WHEN 12 THEN 24 * INTERVAL '1 hour'
WHEN 13 THEN 28 * INTERVAL '1 hour'
WHEN 14 THEN 21 * INTERVAL '1 hour'
WHEN 15 THEN 22 * INTERVAL '1 hour'
WHEN 16 THEN 16 * INTERVAL '1 hour'
WHEN 17 THEN 20 * INTERVAL '1 hour'
WHEN 18 THEN 34 * INTERVAL '1 hour'
WHEN 19 THEN 18 * INTERVAL '1 hour'
WHEN 20 THEN 11 * INTERVAL '1 hour'
END,
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 20
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE AIRDRYING PHASE RECORDS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create airdrying records for Phase 2 JC experiments (1-20)
INSERT INTO public.airdrying (
experiment_id,
scheduled_start_time,
duration_minutes,
scheduled_end_time,
created_by
)
SELECT
e.id,
NOW() + (e.experiment_number) * INTERVAL '1 day' + INTERVAL '2 days', -- Start 2 days after soaking
CASE e.experiment_number
WHEN 1 THEN 19 -- 19 minutes
WHEN 2 THEN 27 -- 27 minutes
WHEN 3 THEN 10 -- 10 minutes
WHEN 4 THEN 36 -- 36 minutes
WHEN 5 THEN 41 -- 41 minutes
WHEN 6 THEN 33 -- 33 minutes
WHEN 7 THEN 22 -- 22 minutes
WHEN 8 THEN 30 -- 30 minutes
WHEN 9 THEN 12 -- 12 minutes
WHEN 10 THEN 26 -- 26 minutes
WHEN 11 THEN 60 -- 60 minutes
WHEN 12 THEN 59 -- 59 minutes
WHEN 13 THEN 59 -- 59 minutes
WHEN 14 THEN 59 -- 59 minutes
WHEN 15 THEN 60 -- 60 minutes
WHEN 16 THEN 59 -- 59 minutes
WHEN 17 THEN 60 -- 60 minutes
WHEN 18 THEN 49 -- 49 minutes
WHEN 19 THEN 25 -- 25 minutes
WHEN 20 THEN 25 -- 25 minutes
END,
NOW() + (e.experiment_number) * INTERVAL '1 day' + INTERVAL '2 days' +
CASE e.experiment_number
WHEN 1 THEN 19 * INTERVAL '1 minute' -- 19 minutes
WHEN 2 THEN 27 * INTERVAL '1 minute' -- 27 minutes
WHEN 3 THEN 10 * INTERVAL '1 minute' -- 10 minutes
WHEN 4 THEN 36 * INTERVAL '1 minute' -- 36 minutes
WHEN 5 THEN 41 * INTERVAL '1 minute' -- 41 minutes
WHEN 6 THEN 33 * INTERVAL '1 minute' -- 33 minutes
WHEN 7 THEN 22 * INTERVAL '1 minute' -- 22 minutes
WHEN 8 THEN 30 * INTERVAL '1 minute' -- 30 minutes
WHEN 9 THEN 12 * INTERVAL '1 minute' -- 12 minutes
WHEN 10 THEN 26 * INTERVAL '1 minute' -- 26 minutes
WHEN 11 THEN 60 * INTERVAL '1 minute' -- 60 minutes
WHEN 12 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 13 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 14 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 15 THEN 60 * INTERVAL '1 minute' -- 60 minutes
WHEN 16 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 17 THEN 60 * INTERVAL '1 minute' -- 60 minutes
WHEN 18 THEN 49 * INTERVAL '1 minute' -- 49 minutes
WHEN 19 THEN 25 * INTERVAL '1 minute' -- 25 minutes
WHEN 20 THEN 25 * INTERVAL '1 minute' -- 25 minutes
END,
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 20
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE CRACKING PHASE RECORDS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create cracking records for Phase 2 JC experiments (1-20)
INSERT INTO public.cracking (
experiment_id,
machine_type_id,
scheduled_start_time,
created_by
)
SELECT
e.id,
(SELECT id FROM public.machine_types WHERE name = 'JC Cracker'),
NOW() + (e.experiment_number) * INTERVAL '1 day' + INTERVAL '3 days', -- Start 3 days after soaking
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 20
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE JC CRACKER PARAMETERS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create JC cracker parameters for Phase 2 JC experiments (1-20)
INSERT INTO public.jc_cracker_parameters (
cracking_id,
plate_contact_frequency_hz,
throughput_rate_pecans_sec,
crush_amount_in,
entry_exit_height_diff_in
)
SELECT
c.id,
CASE e.experiment_number
WHEN 1 THEN 53.0
WHEN 2 THEN 34.0
WHEN 3 THEN 60.0
WHEN 4 THEN 42.0
WHEN 5 THEN 41.0
WHEN 6 THEN 30.0
WHEN 7 THEN 37.0
WHEN 8 THEN 35.0
WHEN 9 THEN 55.0
WHEN 10 THEN 47.0
WHEN 11 THEN 44.0
WHEN 12 THEN 42.0
WHEN 13 THEN 37.0
WHEN 14 THEN 41.0
WHEN 15 THEN 45.0
WHEN 16 THEN 30.0
WHEN 17 THEN 41.0
WHEN 18 THEN 34.0
WHEN 19 THEN 38.0
WHEN 20 THEN 56.0
END,
CASE e.experiment_number
WHEN 1 THEN 28.0
WHEN 2 THEN 29.0
WHEN 3 THEN 28.0
WHEN 4 THEN 13.0
WHEN 5 THEN 38.0
WHEN 6 THEN 36.0
WHEN 7 THEN 30.0
WHEN 8 THEN 32.0
WHEN 9 THEN 24.0
WHEN 10 THEN 26.0
WHEN 11 THEN 12.0
WHEN 12 THEN 25.0
WHEN 13 THEN 23.0
WHEN 14 THEN 21.0
WHEN 15 THEN 17.0
WHEN 16 THEN 24.0
WHEN 17 THEN 14.0
WHEN 18 THEN 29.0
WHEN 19 THEN 35.0
WHEN 20 THEN 34.0
END,
CASE e.experiment_number
WHEN 1 THEN 0.05
WHEN 2 THEN 0.03
WHEN 3 THEN 0.06
WHEN 4 THEN 0.07
WHEN 5 THEN 0.05
WHEN 6 THEN 0.05
WHEN 7 THEN 0.06
WHEN 8 THEN 0.05
WHEN 9 THEN 0.04
WHEN 10 THEN 0.07
WHEN 11 THEN 0.08
WHEN 12 THEN 0.07
WHEN 13 THEN 0.06
WHEN 14 THEN 0.06
WHEN 15 THEN 0.07
WHEN 16 THEN 0.07
WHEN 17 THEN 0.07
WHEN 18 THEN 0.07
WHEN 19 THEN 0.07
WHEN 20 THEN 0.06
END,
CASE e.experiment_number
WHEN 1 THEN -0.09
WHEN 2 THEN 0.01
WHEN 3 THEN -0.10
WHEN 4 THEN -0.07
WHEN 5 THEN 0.03
WHEN 6 THEN -0.04
WHEN 7 THEN 0.02
WHEN 8 THEN -0.07
WHEN 9 THEN 0.04
WHEN 10 THEN 0.03
WHEN 11 THEN -0.10
WHEN 12 THEN -0.05
WHEN 13 THEN -0.08
WHEN 14 THEN -0.09
WHEN 15 THEN -0.08
WHEN 16 THEN 0.02
WHEN 17 THEN 0.04
WHEN 18 THEN -0.09
WHEN 19 THEN -0.08
WHEN 20 THEN -0.09
END
FROM public.experiments e
JOIN public.cracking c ON c.experiment_id = e.id
WHERE e.experiment_number BETWEEN 1 AND 20
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE EXPERIMENT REPETITIONS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create experiment repetitions for Phase 2 JC experiments
-- Each experiment needs 3 repetitions
INSERT INTO public.experiment_repetitions (
experiment_id,
repetition_number,
status,
created_by
)
SELECT
e.id,
rep_num,
'pending',
e.created_by
FROM public.experiments e
CROSS JOIN generate_series(1, 3) AS rep_num
WHERE e.experiment_number BETWEEN 1 AND 20
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;

View File

@@ -1,384 +0,0 @@
-- Phase 2 JC Experiments Seed Data
-- This file contains all Phase 2 JC experiments from phase_2_experimental_run_sheet.csv
-- Each experiment has 3 repetitions, and each row represents one repetition
-- Updated to use 1-based numbering per phase and composite primary key
-- =============================================
-- INSERT PHASE 2 JC EXPERIMENTS
-- =============================================
-- First, insert unique experiments (based on experiment_number)
INSERT INTO public.experiments (
experiment_number,
reps_required,
results_status,
completion_status,
phase_id,
created_by
) VALUES
-- Phase 2 JC Experiments 1-20 (1-based numbering)
(1, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(2, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(3, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(4, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(5, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(6, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(7, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(8, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(9, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(10, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(11, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(12, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(13, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(14, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(15, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(16, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(17, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(18, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(19, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(20, 3, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com'))
ON CONFLICT (experiment_number, phase_id) DO NOTHING;
-- =============================================
-- CREATE SOAKING PHASE RECORDS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create soaking records for Phase 2 JC experiments (1-20)
INSERT INTO public.soaking (
experiment_id,
scheduled_start_time,
soaking_duration_minutes,
scheduled_end_time,
created_by
)
SELECT
e.id,
NOW() + (e.experiment_number) * INTERVAL '1 day',
CASE e.experiment_number
WHEN 1 THEN 34 * 60 -- 34 hours = 2040 minutes
WHEN 2 THEN 24 * 60 -- 24 hours = 1440 minutes
WHEN 3 THEN 38 * 60 -- 38 hours = 2280 minutes
WHEN 4 THEN 11 * 60 -- 11 hours = 660 minutes
WHEN 5 THEN 13 * 60 -- 13 hours = 780 minutes
WHEN 6 THEN 30 * 60 -- 30 hours = 1800 minutes
WHEN 7 THEN 10 * 60 -- 10 hours = 600 minutes
WHEN 8 THEN 15 * 60 -- 15 hours = 900 minutes
WHEN 9 THEN 27 * 60 -- 27 hours = 1620 minutes
WHEN 10 THEN 32 * 60 -- 32 hours = 1920 minutes
WHEN 11 THEN 26 * 60 -- 26 hours = 1560 minutes
WHEN 12 THEN 24 * 60 -- 24 hours = 1440 minutes
WHEN 13 THEN 28 * 60 -- 28 hours = 1680 minutes
WHEN 14 THEN 21 * 60 -- 21 hours = 1260 minutes
WHEN 15 THEN 22 * 60 -- 22 hours = 1320 minutes
WHEN 16 THEN 16 * 60 -- 16 hours = 960 minutes
WHEN 17 THEN 20 * 60 -- 20 hours = 1200 minutes
WHEN 18 THEN 34 * 60 -- 34 hours = 2040 minutes
WHEN 19 THEN 18 * 60 -- 18 hours = 1080 minutes
WHEN 20 THEN 11 * 60 -- 11 hours = 660 minutes
END,
NOW() + (e.experiment_number) * INTERVAL '1 day' +
CASE e.experiment_number
WHEN 1 THEN 34 * 60 * INTERVAL '1 minute' -- 34 hours = 2040 minutes
WHEN 2 THEN 24 * 60 * INTERVAL '1 minute' -- 24 hours = 1440 minutes
WHEN 3 THEN 38 * 60 * INTERVAL '1 minute' -- 38 hours = 2280 minutes
WHEN 4 THEN 11 * 60 * INTERVAL '1 minute' -- 11 hours = 660 minutes
WHEN 5 THEN 13 * 60 * INTERVAL '1 minute' -- 13 hours = 780 minutes
WHEN 6 THEN 30 * 60 * INTERVAL '1 minute' -- 30 hours = 1800 minutes
WHEN 7 THEN 10 * 60 * INTERVAL '1 minute' -- 10 hours = 600 minutes
WHEN 8 THEN 15 * 60 * INTERVAL '1 minute' -- 15 hours = 900 minutes
WHEN 9 THEN 27 * 60 * INTERVAL '1 minute' -- 27 hours = 1620 minutes
WHEN 10 THEN 32 * 60 * INTERVAL '1 minute' -- 32 hours = 1920 minutes
WHEN 11 THEN 26 * 60 * INTERVAL '1 minute' -- 26 hours = 1560 minutes
WHEN 12 THEN 24 * 60 * INTERVAL '1 minute' -- 24 hours = 1440 minutes
WHEN 13 THEN 28 * 60 * INTERVAL '1 minute' -- 28 hours = 1680 minutes
WHEN 14 THEN 21 * 60 * INTERVAL '1 minute' -- 21 hours = 1260 minutes
WHEN 15 THEN 22 * 60 * INTERVAL '1 minute' -- 22 hours = 1320 minutes
WHEN 16 THEN 16 * 60 * INTERVAL '1 minute' -- 16 hours = 960 minutes
WHEN 17 THEN 20 * 60 * INTERVAL '1 minute' -- 20 hours = 1200 minutes
WHEN 18 THEN 34 * 60 * INTERVAL '1 minute' -- 34 hours = 2040 minutes
WHEN 19 THEN 18 * 60 * INTERVAL '1 minute' -- 18 hours = 1080 minutes
WHEN 20 THEN 11 * 60 * INTERVAL '1 minute' -- 11 hours = 660 minutes
END,
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 20
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE AIRDRYING PHASE RECORDS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create airdrying records for Phase 2 JC experiments (1-20)
INSERT INTO public.airdrying (
experiment_id,
scheduled_start_time,
duration_minutes,
scheduled_end_time,
created_by
)
SELECT
e.id,
NOW() + (e.experiment_number) * INTERVAL '1 day' + INTERVAL '2 days', -- Start 2 days after soaking
CASE e.experiment_number
WHEN 1 THEN 19 -- 19 minutes
WHEN 2 THEN 27 -- 27 minutes
WHEN 3 THEN 10 -- 10 minutes
WHEN 4 THEN 36 -- 36 minutes
WHEN 5 THEN 41 -- 41 minutes
WHEN 6 THEN 33 -- 33 minutes
WHEN 7 THEN 22 -- 22 minutes
WHEN 8 THEN 30 -- 30 minutes
WHEN 9 THEN 12 -- 12 minutes
WHEN 10 THEN 26 -- 26 minutes
WHEN 11 THEN 60 -- 60 minutes
WHEN 12 THEN 59 -- 59 minutes
WHEN 13 THEN 59 -- 59 minutes
WHEN 14 THEN 59 -- 59 minutes
WHEN 15 THEN 60 -- 60 minutes
WHEN 16 THEN 59 -- 59 minutes
WHEN 17 THEN 60 -- 60 minutes
WHEN 18 THEN 49 -- 49 minutes
WHEN 19 THEN 25 -- 25 minutes
WHEN 20 THEN 25 -- 25 minutes
END,
NOW() + (e.experiment_number) * INTERVAL '1 day' + INTERVAL '2 days' +
CASE e.experiment_number
WHEN 1 THEN 19 * INTERVAL '1 minute' -- 19 minutes
WHEN 2 THEN 27 * INTERVAL '1 minute' -- 27 minutes
WHEN 3 THEN 10 * INTERVAL '1 minute' -- 10 minutes
WHEN 4 THEN 36 * INTERVAL '1 minute' -- 36 minutes
WHEN 5 THEN 41 * INTERVAL '1 minute' -- 41 minutes
WHEN 6 THEN 33 * INTERVAL '1 minute' -- 33 minutes
WHEN 7 THEN 22 * INTERVAL '1 minute' -- 22 minutes
WHEN 8 THEN 30 * INTERVAL '1 minute' -- 30 minutes
WHEN 9 THEN 12 * INTERVAL '1 minute' -- 12 minutes
WHEN 10 THEN 26 * INTERVAL '1 minute' -- 26 minutes
WHEN 11 THEN 60 * INTERVAL '1 minute' -- 60 minutes
WHEN 12 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 13 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 14 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 15 THEN 60 * INTERVAL '1 minute' -- 60 minutes
WHEN 16 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 17 THEN 60 * INTERVAL '1 minute' -- 60 minutes
WHEN 18 THEN 49 * INTERVAL '1 minute' -- 49 minutes
WHEN 19 THEN 25 * INTERVAL '1 minute' -- 25 minutes
WHEN 20 THEN 25 * INTERVAL '1 minute' -- 25 minutes
END,
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 20
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE CRACKING PHASE RECORDS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create cracking records for Phase 2 JC experiments (1-20)
INSERT INTO public.cracking (
experiment_id,
machine_type_id,
scheduled_start_time,
created_by
)
SELECT
e.id,
(SELECT id FROM public.machine_types WHERE name = 'JC Cracker'),
NOW() + (e.experiment_number) * INTERVAL '1 day' + INTERVAL '3 days', -- Start 3 days after soaking
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 20
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE JC CRACKER PARAMETERS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create JC cracker parameters for Phase 2 JC experiments (1-20)
-- First create the JC cracker parameters
INSERT INTO public.jc_cracker_parameters (
plate_contact_frequency_hz,
throughput_rate_pecans_sec,
crush_amount_in,
entry_exit_height_diff_in
)
SELECT
CASE e.experiment_number
WHEN 1 THEN 53.0
WHEN 2 THEN 34.0
WHEN 3 THEN 60.0
WHEN 4 THEN 42.0
WHEN 5 THEN 41.0
WHEN 6 THEN 30.0
WHEN 7 THEN 37.0
WHEN 8 THEN 35.0
WHEN 9 THEN 55.0
WHEN 10 THEN 47.0
WHEN 11 THEN 44.0
WHEN 12 THEN 42.0
WHEN 13 THEN 37.0
WHEN 14 THEN 41.0
WHEN 15 THEN 45.0
WHEN 16 THEN 30.0
WHEN 17 THEN 41.0
WHEN 18 THEN 34.0
WHEN 19 THEN 38.0
WHEN 20 THEN 56.0
END,
CASE e.experiment_number
WHEN 1 THEN 28.0
WHEN 2 THEN 29.0
WHEN 3 THEN 28.0
WHEN 4 THEN 13.0
WHEN 5 THEN 38.0
WHEN 6 THEN 36.0
WHEN 7 THEN 30.0
WHEN 8 THEN 32.0
WHEN 9 THEN 24.0
WHEN 10 THEN 26.0
WHEN 11 THEN 12.0
WHEN 12 THEN 25.0
WHEN 13 THEN 23.0
WHEN 14 THEN 21.0
WHEN 15 THEN 17.0
WHEN 16 THEN 24.0
WHEN 17 THEN 14.0
WHEN 18 THEN 29.0
WHEN 19 THEN 35.0
WHEN 20 THEN 34.0
END,
CASE e.experiment_number
WHEN 1 THEN 0.05
WHEN 2 THEN 0.03
WHEN 3 THEN 0.06
WHEN 4 THEN 0.07
WHEN 5 THEN 0.05
WHEN 6 THEN 0.05
WHEN 7 THEN 0.06
WHEN 8 THEN 0.05
WHEN 9 THEN 0.04
WHEN 10 THEN 0.07
WHEN 11 THEN 0.08
WHEN 12 THEN 0.07
WHEN 13 THEN 0.06
WHEN 14 THEN 0.06
WHEN 15 THEN 0.07
WHEN 16 THEN 0.07
WHEN 17 THEN 0.07
WHEN 18 THEN 0.07
WHEN 19 THEN 0.07
WHEN 20 THEN 0.06
END,
CASE e.experiment_number
WHEN 1 THEN -0.09
WHEN 2 THEN 0.01
WHEN 3 THEN -0.10
WHEN 4 THEN -0.07
WHEN 5 THEN 0.03
WHEN 6 THEN -0.04
WHEN 7 THEN 0.02
WHEN 8 THEN -0.07
WHEN 9 THEN 0.04
WHEN 10 THEN 0.03
WHEN 11 THEN -0.10
WHEN 12 THEN -0.05
WHEN 13 THEN -0.08
WHEN 14 THEN -0.09
WHEN 15 THEN -0.08
WHEN 16 THEN 0.02
WHEN 17 THEN 0.04
WHEN 18 THEN -0.09
WHEN 19 THEN -0.08
WHEN 20 THEN -0.09
END
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 20
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;
-- Now update the cracking records to reference the JC cracker parameters
-- Match them by the order they were created
WITH parameter_mapping AS (
SELECT
e.experiment_number,
jcp.id as param_id,
ROW_NUMBER() OVER (ORDER BY e.experiment_number) as exp_rn,
ROW_NUMBER() OVER (ORDER BY jcp.created_at) as param_rn
FROM public.experiments e
CROSS JOIN public.jc_cracker_parameters jcp
WHERE e.experiment_number BETWEEN 1 AND 20
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
)
UPDATE public.cracking c
SET jc_cracker_parameters_id = pm.param_id
FROM parameter_mapping pm
JOIN public.experiments e ON c.experiment_id = e.id
WHERE e.experiment_number = pm.experiment_number
AND pm.exp_rn = pm.param_rn
AND c.jc_cracker_parameters_id IS NULL;
-- =============================================
-- CREATE EXPERIMENT REPETITIONS FOR PHASE 2 JC EXPERIMENTS
-- =============================================
-- Create experiment repetitions for Phase 2 JC experiments
-- Each experiment needs 3 repetitions
INSERT INTO public.experiment_repetitions (
experiment_id,
repetition_number,
status,
created_by
)
SELECT
e.id,
rep_num,
'pending',
e.created_by
FROM public.experiments e
CROSS JOIN generate_series(1, 3) AS rep_num
WHERE e.experiment_number BETWEEN 1 AND 20
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Phase 2 of JC Experiments')
ON CONFLICT DO NOTHING;

View File

@@ -1,540 +0,0 @@
-- Meyer Experiments Seed Data (Corrected)
-- This file contains all 40 Meyer experiments from post_workshop_meyer_experiments.csv
-- Each experiment has only 1 repetition required
-- Updated to match the actual CSV data with correct experiment numbers and parameters
-- =============================================
-- INSERT MEYER EXPERIMENTS (Post Workshop)
-- =============================================
-- Insert Meyer experiments (experiments 1-40) with data from CSV
INSERT INTO public.experiments (
experiment_number,
reps_required,
results_status,
completion_status,
phase_id,
created_by
) VALUES
-- Meyer Experiments 1-40 (matching CSV data)
(1, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(2, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(3, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(4, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(5, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(6, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(7, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(8, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(9, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(10, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(11, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(12, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(13, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(14, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(15, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(16, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(17, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(18, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(19, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(20, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(21, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(22, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(23, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(24, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(25, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(26, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(27, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(28, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(29, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(30, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(31, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(32, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(33, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(34, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(35, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(36, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(37, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(38, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(39, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(40, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com'))
ON CONFLICT (experiment_number, phase_id) DO NOTHING;
-- =============================================
-- CREATE SOAKING PHASE RECORDS FOR MEYER EXPERIMENTS
-- =============================================
-- Create soaking records for Meyer experiments (1-40) with data from CSV
INSERT INTO public.soaking (
experiment_id,
scheduled_start_time,
soaking_duration_minutes,
scheduled_end_time,
created_by
)
SELECT
e.id,
NOW() + e.experiment_number * INTERVAL '1 day',
CASE e.experiment_number
WHEN 1 THEN 27 * 60 -- 27 hours = 1620 minutes
WHEN 2 THEN 37 * 60 -- 37 hours = 2220 minutes
WHEN 3 THEN 36 * 60 -- 36 hours = 2160 minutes
WHEN 4 THEN 12 * 60 -- 12 hours = 720 minutes
WHEN 5 THEN 34 * 60 -- 34 hours = 2040 minutes
WHEN 6 THEN 18 * 60 -- 18 hours = 1080 minutes
WHEN 7 THEN 14 * 60 -- 14 hours = 840 minutes
WHEN 8 THEN 18 * 60 -- 18 hours = 1080 minutes
WHEN 9 THEN 11 * 60 -- 11 hours = 660 minutes
WHEN 10 THEN 33 * 60 -- 33 hours = 1980 minutes
WHEN 11 THEN 23 * 60 -- 23 hours = 1380 minutes
WHEN 12 THEN 37 * 60 -- 37 hours = 2220 minutes
WHEN 13 THEN 15 * 60 -- 15 hours = 900 minutes
WHEN 14 THEN 24 * 60 -- 24 hours = 1440 minutes
WHEN 15 THEN 36 * 60 -- 36 hours = 2160 minutes
WHEN 16 THEN 32 * 60 -- 32 hours = 1920 minutes
WHEN 17 THEN 28 * 60 -- 28 hours = 1680 minutes
WHEN 18 THEN 31 * 60 -- 31 hours = 1860 minutes
WHEN 19 THEN 20 * 60 -- 20 hours = 1200 minutes
WHEN 20 THEN 10 * 60 -- 10 hours = 600 minutes
WHEN 21 THEN 16 * 60 -- 16 hours = 960 minutes
WHEN 22 THEN 21 * 60 -- 21 hours = 1260 minutes
WHEN 23 THEN 42 * 60 -- 42 hours = 2520 minutes
WHEN 24 THEN 29 * 60 -- 29 hours = 1740 minutes
WHEN 25 THEN 54 * 60 -- 54 hours = 3240 minutes
WHEN 26 THEN 29 * 60 -- 29 hours = 1740 minutes
WHEN 27 THEN 30 * 60 -- 30 hours = 1800 minutes
WHEN 28 THEN 35 * 60 -- 35 hours = 2100 minutes
WHEN 29 THEN 27 * 60 -- 27 hours = 1620 minutes
WHEN 30 THEN 27 * 60 -- 27 hours = 1620 minutes
WHEN 31 THEN 17 * 60 -- 17 hours = 1020 minutes
WHEN 32 THEN 13 * 60 -- 13 hours = 780 minutes
WHEN 33 THEN 19 * 60 -- 19 hours = 1140 minutes
WHEN 34 THEN 38 * 60 -- 38 hours = 2280 minutes
WHEN 35 THEN 26 * 60 -- 26 hours = 1560 minutes
WHEN 36 THEN 22 * 60 -- 22 hours = 1320 minutes
WHEN 37 THEN 12 * 60 -- 12 hours = 720 minutes
WHEN 38 THEN 16 * 60 -- 16 hours = 960 minutes
WHEN 39 THEN 22 * 60 -- 22 hours = 1320 minutes
WHEN 40 THEN 24 * 60 -- 24 hours = 1440 minutes
END,
NOW() + e.experiment_number * INTERVAL '1 day' +
CASE e.experiment_number
WHEN 1 THEN 27 * 60 * INTERVAL '1 minute' -- 27 hours = 1620 minutes
WHEN 2 THEN 37 * 60 * INTERVAL '1 minute' -- 37 hours = 2220 minutes
WHEN 3 THEN 36 * 60 * INTERVAL '1 minute' -- 36 hours = 2160 minutes
WHEN 4 THEN 12 * 60 * INTERVAL '1 minute' -- 12 hours = 720 minutes
WHEN 5 THEN 34 * 60 * INTERVAL '1 minute' -- 34 hours = 2040 minutes
WHEN 6 THEN 18 * 60 * INTERVAL '1 minute' -- 18 hours = 1080 minutes
WHEN 7 THEN 14 * 60 * INTERVAL '1 minute' -- 14 hours = 840 minutes
WHEN 8 THEN 18 * 60 * INTERVAL '1 minute' -- 18 hours = 1080 minutes
WHEN 9 THEN 11 * 60 * INTERVAL '1 minute' -- 11 hours = 660 minutes
WHEN 10 THEN 33 * 60 * INTERVAL '1 minute' -- 33 hours = 1980 minutes
WHEN 11 THEN 23 * 60 * INTERVAL '1 minute' -- 23 hours = 1380 minutes
WHEN 12 THEN 37 * 60 * INTERVAL '1 minute' -- 37 hours = 2220 minutes
WHEN 13 THEN 15 * 60 * INTERVAL '1 minute' -- 15 hours = 900 minutes
WHEN 14 THEN 24 * 60 * INTERVAL '1 minute' -- 24 hours = 1440 minutes
WHEN 15 THEN 36 * 60 * INTERVAL '1 minute' -- 36 hours = 2160 minutes
WHEN 16 THEN 32 * 60 * INTERVAL '1 minute' -- 32 hours = 1920 minutes
WHEN 17 THEN 28 * 60 * INTERVAL '1 minute' -- 28 hours = 1680 minutes
WHEN 18 THEN 31 * 60 * INTERVAL '1 minute' -- 31 hours = 1860 minutes
WHEN 19 THEN 20 * 60 * INTERVAL '1 minute' -- 20 hours = 1200 minutes
WHEN 20 THEN 10 * 60 * INTERVAL '1 minute' -- 10 hours = 600 minutes
WHEN 21 THEN 16 * 60 * INTERVAL '1 minute' -- 16 hours = 960 minutes
WHEN 22 THEN 21 * 60 * INTERVAL '1 minute' -- 21 hours = 1260 minutes
WHEN 23 THEN 42 * 60 * INTERVAL '1 minute' -- 42 hours = 2520 minutes
WHEN 24 THEN 29 * 60 * INTERVAL '1 minute' -- 29 hours = 1740 minutes
WHEN 25 THEN 54 * 60 * INTERVAL '1 minute' -- 54 hours = 3240 minutes
WHEN 26 THEN 29 * 60 * INTERVAL '1 minute' -- 29 hours = 1740 minutes
WHEN 27 THEN 30 * 60 * INTERVAL '1 minute' -- 30 hours = 1800 minutes
WHEN 28 THEN 35 * 60 * INTERVAL '1 minute' -- 35 hours = 2100 minutes
WHEN 29 THEN 27 * 60 * INTERVAL '1 minute' -- 27 hours = 1620 minutes
WHEN 30 THEN 27 * 60 * INTERVAL '1 minute' -- 27 hours = 1620 minutes
WHEN 31 THEN 17 * 60 * INTERVAL '1 minute' -- 17 hours = 1020 minutes
WHEN 32 THEN 13 * 60 * INTERVAL '1 minute' -- 13 hours = 780 minutes
WHEN 33 THEN 19 * 60 * INTERVAL '1 minute' -- 19 hours = 1140 minutes
WHEN 34 THEN 38 * 60 * INTERVAL '1 minute' -- 38 hours = 2280 minutes
WHEN 35 THEN 26 * 60 * INTERVAL '1 minute' -- 26 hours = 1560 minutes
WHEN 36 THEN 22 * 60 * INTERVAL '1 minute' -- 22 hours = 1320 minutes
WHEN 37 THEN 12 * 60 * INTERVAL '1 minute' -- 12 hours = 720 minutes
WHEN 38 THEN 16 * 60 * INTERVAL '1 minute' -- 16 hours = 960 minutes
WHEN 39 THEN 22 * 60 * INTERVAL '1 minute' -- 22 hours = 1320 minutes
WHEN 40 THEN 24 * 60 * INTERVAL '1 minute' -- 24 hours = 1440 minutes
END,
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE AIRDRYING PHASE RECORDS FOR MEYER EXPERIMENTS
-- =============================================
-- Create airdrying records for Meyer experiments (1-40) with data from CSV
INSERT INTO public.airdrying (
experiment_id,
scheduled_start_time,
duration_minutes,
scheduled_end_time,
created_by
)
SELECT
e.id,
NOW() + e.experiment_number * INTERVAL '1 day' + INTERVAL '2 days', -- Start 2 days after soaking
CASE e.experiment_number
WHEN 1 THEN 28 -- 28 minutes
WHEN 2 THEN 17 -- 17 minutes
WHEN 3 THEN 50 -- 50 minutes
WHEN 4 THEN 30 -- 30 minutes
WHEN 5 THEN 19 -- 19 minutes
WHEN 6 THEN 40 -- 40 minutes
WHEN 7 THEN 59 -- 59 minutes
WHEN 8 THEN 32 -- 32 minutes
WHEN 9 THEN 31 -- 31 minutes
WHEN 10 THEN 12 -- 12 minutes
WHEN 11 THEN 36 -- 36 minutes
WHEN 12 THEN 35 -- 35 minutes
WHEN 13 THEN 15 -- 15 minutes
WHEN 14 THEN 22 -- 22 minutes
WHEN 15 THEN 15 -- 15 minutes
WHEN 16 THEN 48 -- 48 minutes
WHEN 17 THEN 38 -- 38 minutes
WHEN 18 THEN 51 -- 51 minutes
WHEN 19 THEN 57 -- 57 minutes
WHEN 20 THEN 27 -- 27 minutes
WHEN 21 THEN 43 -- 43 minutes
WHEN 22 THEN 42 -- 42 minutes
WHEN 23 THEN 21 -- 21 minutes
WHEN 24 THEN 46 -- 46 minutes
WHEN 25 THEN 54 -- 54 minutes
WHEN 26 THEN 54 -- 54 minutes
WHEN 27 THEN 48 -- 48 minutes
WHEN 28 THEN 53 -- 53 minutes
WHEN 29 THEN 39 -- 39 minutes
WHEN 30 THEN 38 -- 38 minutes
WHEN 31 THEN 25 -- 25 minutes
WHEN 32 THEN 22 -- 22 minutes
WHEN 33 THEN 11 -- 11 minutes
WHEN 34 THEN 32 -- 32 minutes
WHEN 35 THEN 18 -- 18 minutes
WHEN 36 THEN 52 -- 52 minutes
WHEN 37 THEN 56 -- 56 minutes
WHEN 38 THEN 45 -- 45 minutes
WHEN 39 THEN 25 -- 25 minutes
WHEN 40 THEN 13 -- 13 minutes
END,
NOW() + e.experiment_number * INTERVAL '1 day' + INTERVAL '2 days' +
CASE e.experiment_number
WHEN 1 THEN 28 * INTERVAL '1 minute' -- 28 minutes
WHEN 2 THEN 17 * INTERVAL '1 minute' -- 17 minutes
WHEN 3 THEN 50 * INTERVAL '1 minute' -- 50 minutes
WHEN 4 THEN 30 * INTERVAL '1 minute' -- 30 minutes
WHEN 5 THEN 19 * INTERVAL '1 minute' -- 19 minutes
WHEN 6 THEN 40 * INTERVAL '1 minute' -- 40 minutes
WHEN 7 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 8 THEN 32 * INTERVAL '1 minute' -- 32 minutes
WHEN 9 THEN 31 * INTERVAL '1 minute' -- 31 minutes
WHEN 10 THEN 12 * INTERVAL '1 minute' -- 12 minutes
WHEN 11 THEN 36 * INTERVAL '1 minute' -- 36 minutes
WHEN 12 THEN 35 * INTERVAL '1 minute' -- 35 minutes
WHEN 13 THEN 15 * INTERVAL '1 minute' -- 15 minutes
WHEN 14 THEN 22 * INTERVAL '1 minute' -- 22 minutes
WHEN 15 THEN 15 * INTERVAL '1 minute' -- 15 minutes
WHEN 16 THEN 48 * INTERVAL '1 minute' -- 48 minutes
WHEN 17 THEN 38 * INTERVAL '1 minute' -- 38 minutes
WHEN 18 THEN 51 * INTERVAL '1 minute' -- 51 minutes
WHEN 19 THEN 57 * INTERVAL '1 minute' -- 57 minutes
WHEN 20 THEN 27 * INTERVAL '1 minute' -- 27 minutes
WHEN 21 THEN 43 * INTERVAL '1 minute' -- 43 minutes
WHEN 22 THEN 42 * INTERVAL '1 minute' -- 42 minutes
WHEN 23 THEN 21 * INTERVAL '1 minute' -- 21 minutes
WHEN 24 THEN 46 * INTERVAL '1 minute' -- 46 minutes
WHEN 25 THEN 54 * INTERVAL '1 minute' -- 54 minutes
WHEN 26 THEN 54 * INTERVAL '1 minute' -- 54 minutes
WHEN 27 THEN 48 * INTERVAL '1 minute' -- 48 minutes
WHEN 28 THEN 53 * INTERVAL '1 minute' -- 53 minutes
WHEN 29 THEN 39 * INTERVAL '1 minute' -- 39 minutes
WHEN 30 THEN 38 * INTERVAL '1 minute' -- 38 minutes
WHEN 31 THEN 25 * INTERVAL '1 minute' -- 25 minutes
WHEN 32 THEN 22 * INTERVAL '1 minute' -- 22 minutes
WHEN 33 THEN 11 * INTERVAL '1 minute' -- 11 minutes
WHEN 34 THEN 32 * INTERVAL '1 minute' -- 32 minutes
WHEN 35 THEN 18 * INTERVAL '1 minute' -- 18 minutes
WHEN 36 THEN 52 * INTERVAL '1 minute' -- 52 minutes
WHEN 37 THEN 56 * INTERVAL '1 minute' -- 56 minutes
WHEN 38 THEN 45 * INTERVAL '1 minute' -- 45 minutes
WHEN 39 THEN 25 * INTERVAL '1 minute' -- 25 minutes
WHEN 40 THEN 13 * INTERVAL '1 minute' -- 13 minutes
END,
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE CRACKING PHASE RECORDS FOR MEYER EXPERIMENTS
-- =============================================
-- Create cracking records for Meyer experiments (1-40)
INSERT INTO public.cracking (
experiment_id,
machine_type_id,
scheduled_start_time,
created_by
)
SELECT
e.id,
(SELECT id FROM public.machine_types WHERE name = 'Meyer Cracker'),
NOW() + e.experiment_number * INTERVAL '1 day' + INTERVAL '3 days', -- Start 3 days after soaking
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE MEYER CRACKER PARAMETERS FOR MEYER EXPERIMENTS
-- =============================================
-- Create Meyer cracker parameters for Meyer experiments (1-40) with data from CSV
INSERT INTO public.meyer_cracker_parameters (
cracking_id,
motor_speed_hz,
jig_displacement_inches,
spring_stiffness_nm
)
SELECT
c.id,
CASE e.experiment_number
WHEN 1 THEN 33.0
WHEN 2 THEN 30.0
WHEN 3 THEN 47.0
WHEN 4 THEN 42.0
WHEN 5 THEN 53.0
WHEN 6 THEN 37.0
WHEN 7 THEN 40.0
WHEN 8 THEN 39.0
WHEN 9 THEN 49.0
WHEN 10 THEN 47.0
WHEN 11 THEN 52.0
WHEN 12 THEN 59.0
WHEN 13 THEN 41.0
WHEN 14 THEN 46.0
WHEN 15 THEN 50.0
WHEN 16 THEN 36.0
WHEN 17 THEN 33.0
WHEN 18 THEN 35.0
WHEN 19 THEN 55.0
WHEN 20 THEN 44.0
WHEN 21 THEN 37.0
WHEN 22 THEN 56.0
WHEN 23 THEN 30.0
WHEN 24 THEN 60.0
WHEN 25 THEN 41.0
WHEN 26 THEN 55.0
WHEN 27 THEN 39.0
WHEN 28 THEN 34.0
WHEN 29 THEN 57.0
WHEN 30 THEN 45.0
WHEN 31 THEN 52.0
WHEN 32 THEN 51.0
WHEN 33 THEN 36.0
WHEN 34 THEN 44.0
WHEN 35 THEN 58.0
WHEN 36 THEN 32.0
WHEN 37 THEN 43.0
WHEN 38 THEN 60.0
WHEN 39 THEN 54.0
WHEN 40 THEN 48.0
END,
CASE e.experiment_number
WHEN 1 THEN -0.307
WHEN 2 THEN -0.311
WHEN 3 THEN -0.291
WHEN 4 THEN -0.314
WHEN 5 THEN -0.302
WHEN 6 THEN -0.301
WHEN 7 THEN -0.286
WHEN 8 THEN -0.309
WHEN 9 THEN -0.299
WHEN 10 THEN -0.295
WHEN 11 THEN -0.302
WHEN 12 THEN -0.299
WHEN 13 THEN -0.312
WHEN 14 THEN -0.303
WHEN 15 THEN -0.308
WHEN 16 THEN -0.306
WHEN 17 THEN -0.308
WHEN 18 THEN -0.311
WHEN 19 THEN -0.304
WHEN 20 THEN -0.313
WHEN 21 THEN -0.294
WHEN 22 THEN -0.310
WHEN 23 THEN -0.292
WHEN 24 THEN -0.294
WHEN 25 THEN -0.306
WHEN 26 THEN -0.296
WHEN 27 THEN -0.293
WHEN 28 THEN -0.285
WHEN 29 THEN -0.291
WHEN 30 THEN -0.296
WHEN 31 THEN -0.297
WHEN 32 THEN -0.288
WHEN 33 THEN -0.290
WHEN 34 THEN -0.315
WHEN 35 THEN -0.289
WHEN 36 THEN -0.288
WHEN 37 THEN -0.287
WHEN 38 THEN -0.298
WHEN 39 THEN -0.301
WHEN 40 THEN -0.305
END,
CASE e.experiment_number
WHEN 1 THEN 1800.0
WHEN 2 THEN 2000.0
WHEN 3 THEN 1800.0
WHEN 4 THEN 2000.0
WHEN 5 THEN 1800.0
WHEN 6 THEN 2200.0
WHEN 7 THEN 2000.0
WHEN 8 THEN 1800.0
WHEN 9 THEN 2200.0
WHEN 10 THEN 2000.0
WHEN 11 THEN 2000.0
WHEN 12 THEN 1800.0
WHEN 13 THEN 2000.0
WHEN 14 THEN 1800.0
WHEN 15 THEN 1800.0
WHEN 16 THEN 2200.0
WHEN 17 THEN 2200.0
WHEN 18 THEN 1800.0
WHEN 19 THEN 2000.0
WHEN 20 THEN 2200.0
WHEN 21 THEN 2000.0
WHEN 22 THEN 2200.0
WHEN 23 THEN 2200.0
WHEN 24 THEN 2200.0
WHEN 25 THEN 2000.0
WHEN 26 THEN 1800.0
WHEN 27 THEN 2200.0
WHEN 28 THEN 2200.0
WHEN 29 THEN 1800.0
WHEN 30 THEN 2200.0
WHEN 31 THEN 1800.0
WHEN 32 THEN 2200.0
WHEN 33 THEN 2000.0
WHEN 34 THEN 1800.0
WHEN 35 THEN 1800.0
WHEN 36 THEN 1800.0
WHEN 37 THEN 2200.0
WHEN 38 THEN 2200.0
WHEN 39 THEN 2000.0
WHEN 40 THEN 2000.0
END
FROM public.experiments e
JOIN public.cracking c ON c.experiment_id = e.id
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE EXPERIMENT REPETITIONS FOR MEYER EXPERIMENTS
-- =============================================
-- Create experiment repetitions for Meyer experiments
-- Each experiment needs only 1 repetition
INSERT INTO public.experiment_repetitions (
experiment_id,
repetition_number,
completion_status,
created_by
)
SELECT
e.id,
1,
false,
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;

View File

@@ -1,540 +0,0 @@
-- Meyer Experiments Seed Data
-- This file contains all 40 Meyer experiments from meyer experiments.csv
-- Each experiment has only 1 repetition required
-- Updated to use 1-based numbering per phase and composite primary key
-- =============================================
-- INSERT MEYER EXPERIMENTS (Post Workshop)
-- =============================================
-- Insert Meyer experiments (experiments 1-40)
INSERT INTO public.experiments (
experiment_number,
reps_required,
results_status,
completion_status,
phase_id,
created_by
) VALUES
-- Meyer Experiments 1-40 (1-based numbering)
(1, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(2, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(3, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(4, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(5, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(6, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(7, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(8, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(9, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(10, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(11, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(12, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(13, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(14, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(15, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(16, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(17, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(18, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(19, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(20, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(21, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(22, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(23, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(24, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(25, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(26, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(27, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(28, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(29, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(30, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(31, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(32, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(33, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(34, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(35, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(36, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(37, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(38, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(39, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(40, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com'))
ON CONFLICT (experiment_number, phase_id) DO NOTHING;
-- =============================================
-- CREATE SOAKING PHASE RECORDS FOR MEYER EXPERIMENTS
-- =============================================
-- Create soaking records for Meyer experiments (1-40)
INSERT INTO public.soaking (
experiment_id,
scheduled_start_time,
soaking_duration_hours,
scheduled_end_time,
created_by
)
SELECT
e.id,
NOW() + (e.experiment_number) * INTERVAL '1 day',
CASE e.experiment_number
WHEN 1 THEN 27 -- hours
WHEN 2 THEN 37
WHEN 3 THEN 36
WHEN 4 THEN 12
WHEN 5 THEN 34
WHEN 6 THEN 18
WHEN 7 THEN 14
WHEN 8 THEN 18
WHEN 9 THEN 11
WHEN 10 THEN 33
WHEN 11 THEN 23
WHEN 12 THEN 37
WHEN 13 THEN 15
WHEN 14 THEN 24
WHEN 15 THEN 36
WHEN 16 THEN 32
WHEN 17 THEN 28
WHEN 18 THEN 31
WHEN 19 THEN 20
WHEN 20 THEN 10
WHEN 21 THEN 16
WHEN 22 THEN 21
WHEN 23 THEN 42
WHEN 24 THEN 29
WHEN 25 THEN 54
WHEN 26 THEN 29
WHEN 27 THEN 30
WHEN 28 THEN 35
WHEN 29 THEN 27
WHEN 30 THEN 27
WHEN 31 THEN 17
WHEN 32 THEN 13
WHEN 33 THEN 19
WHEN 34 THEN 38
WHEN 35 THEN 26
WHEN 36 THEN 22
WHEN 37 THEN 12
WHEN 38 THEN 16
WHEN 39 THEN 22
WHEN 40 THEN 24
END,
NOW() + (e.experiment_number) * INTERVAL '1 day' +
CASE e.experiment_number
WHEN 1 THEN 27 * INTERVAL '1 hour'
WHEN 2 THEN 37 * INTERVAL '1 hour'
WHEN 3 THEN 36 * INTERVAL '1 hour'
WHEN 4 THEN 12 * INTERVAL '1 hour'
WHEN 5 THEN 34 * INTERVAL '1 hour'
WHEN 6 THEN 18 * INTERVAL '1 hour'
WHEN 7 THEN 14 * INTERVAL '1 hour'
WHEN 8 THEN 18 * INTERVAL '1 hour'
WHEN 9 THEN 11 * INTERVAL '1 hour'
WHEN 10 THEN 33 * INTERVAL '1 hour'
WHEN 11 THEN 23 * INTERVAL '1 hour'
WHEN 12 THEN 37 * INTERVAL '1 hour'
WHEN 13 THEN 15 * INTERVAL '1 hour'
WHEN 14 THEN 24 * INTERVAL '1 hour'
WHEN 15 THEN 36 * INTERVAL '1 hour'
WHEN 16 THEN 32 * INTERVAL '1 hour'
WHEN 17 THEN 28 * INTERVAL '1 hour'
WHEN 18 THEN 31 * INTERVAL '1 hour'
WHEN 19 THEN 20 * INTERVAL '1 hour'
WHEN 20 THEN 10 * INTERVAL '1 hour'
WHEN 21 THEN 16 * INTERVAL '1 hour'
WHEN 22 THEN 21 * INTERVAL '1 hour'
WHEN 23 THEN 42 * INTERVAL '1 hour'
WHEN 24 THEN 29 * INTERVAL '1 hour'
WHEN 25 THEN 54 * INTERVAL '1 hour'
WHEN 26 THEN 29 * INTERVAL '1 hour'
WHEN 27 THEN 30 * INTERVAL '1 hour'
WHEN 28 THEN 35 * INTERVAL '1 hour'
WHEN 29 THEN 27 * INTERVAL '1 hour'
WHEN 30 THEN 27 * INTERVAL '1 hour'
WHEN 31 THEN 17 * INTERVAL '1 hour'
WHEN 32 THEN 13 * INTERVAL '1 hour'
WHEN 33 THEN 19 * INTERVAL '1 hour'
WHEN 34 THEN 38 * INTERVAL '1 hour'
WHEN 35 THEN 26 * INTERVAL '1 hour'
WHEN 36 THEN 22 * INTERVAL '1 hour'
WHEN 37 THEN 12 * INTERVAL '1 hour'
WHEN 38 THEN 16 * INTERVAL '1 hour'
WHEN 39 THEN 22 * INTERVAL '1 hour'
WHEN 40 THEN 24 * INTERVAL '1 hour'
END,
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE AIRDRYING PHASE RECORDS FOR MEYER EXPERIMENTS
-- =============================================
-- Create airdrying records for Meyer experiments (1-40)
INSERT INTO public.airdrying (
experiment_id,
scheduled_start_time,
duration_minutes,
scheduled_end_time,
created_by
)
SELECT
e.id,
NOW() + (e.experiment_number) * INTERVAL '1 day' + INTERVAL '2 days', -- Start 2 days after soaking
CASE e.experiment_number
WHEN 1 THEN 28 -- 28 minutes
WHEN 2 THEN 17 -- 17 minutes
WHEN 3 THEN 50 -- 50 minutes
WHEN 4 THEN 30 -- 30 minutes
WHEN 5 THEN 19 -- 19 minutes
WHEN 6 THEN 40 -- 40 minutes
WHEN 7 THEN 59 -- 59 minutes
WHEN 8 THEN 32 -- 32 minutes
WHEN 9 THEN 31 -- 31 minutes
WHEN 10 THEN 12 -- 12 minutes
WHEN 11 THEN 36 -- 36 minutes
WHEN 12 THEN 35 -- 35 minutes
WHEN 13 THEN 15 -- 15 minutes
WHEN 14 THEN 22 -- 22 minutes
WHEN 15 THEN 15 -- 15 minutes
WHEN 16 THEN 48 -- 48 minutes
WHEN 17 THEN 38 -- 38 minutes
WHEN 18 THEN 51 -- 51 minutes
WHEN 19 THEN 57 -- 57 minutes
WHEN 20 THEN 27 -- 27 minutes
WHEN 21 THEN 43 -- 43 minutes
WHEN 22 THEN 42 -- 42 minutes
WHEN 23 THEN 21 -- 21 minutes
WHEN 24 THEN 46 -- 46 minutes
WHEN 25 THEN 54 -- 54 minutes
WHEN 26 THEN 54 -- 54 minutes
WHEN 27 THEN 48 -- 48 minutes
WHEN 28 THEN 53 -- 53 minutes
WHEN 29 THEN 39 -- 39 minutes
WHEN 30 THEN 38 -- 38 minutes
WHEN 31 THEN 25 -- 25 minutes
WHEN 32 THEN 22 -- 22 minutes
WHEN 33 THEN 11 -- 11 minutes
WHEN 34 THEN 32 -- 32 minutes
WHEN 35 THEN 18 -- 18 minutes
WHEN 36 THEN 52 -- 52 minutes
WHEN 37 THEN 56 -- 56 minutes
WHEN 38 THEN 45 -- 45 minutes
WHEN 39 THEN 25 -- 25 minutes
WHEN 40 THEN 13 -- 13 minutes
END,
NOW() + (e.experiment_number) * INTERVAL '1 day' + INTERVAL '2 days' +
CASE e.experiment_number
WHEN 1 THEN 28 * INTERVAL '1 minute' -- 28 minutes
WHEN 2 THEN 17 * INTERVAL '1 minute' -- 17 minutes
WHEN 3 THEN 50 * INTERVAL '1 minute' -- 50 minutes
WHEN 4 THEN 30 * INTERVAL '1 minute' -- 30 minutes
WHEN 5 THEN 19 * INTERVAL '1 minute' -- 19 minutes
WHEN 6 THEN 40 * INTERVAL '1 minute' -- 40 minutes
WHEN 7 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 8 THEN 32 * INTERVAL '1 minute' -- 32 minutes
WHEN 9 THEN 31 * INTERVAL '1 minute' -- 31 minutes
WHEN 10 THEN 12 * INTERVAL '1 minute' -- 12 minutes
WHEN 11 THEN 36 * INTERVAL '1 minute' -- 36 minutes
WHEN 12 THEN 35 * INTERVAL '1 minute' -- 35 minutes
WHEN 13 THEN 15 * INTERVAL '1 minute' -- 15 minutes
WHEN 14 THEN 22 * INTERVAL '1 minute' -- 22 minutes
WHEN 15 THEN 15 * INTERVAL '1 minute' -- 15 minutes
WHEN 16 THEN 48 * INTERVAL '1 minute' -- 48 minutes
WHEN 17 THEN 38 * INTERVAL '1 minute' -- 38 minutes
WHEN 18 THEN 51 * INTERVAL '1 minute' -- 51 minutes
WHEN 19 THEN 57 * INTERVAL '1 minute' -- 57 minutes
WHEN 20 THEN 27 * INTERVAL '1 minute' -- 27 minutes
WHEN 21 THEN 43 * INTERVAL '1 minute' -- 43 minutes
WHEN 22 THEN 42 * INTERVAL '1 minute' -- 42 minutes
WHEN 23 THEN 21 * INTERVAL '1 minute' -- 21 minutes
WHEN 24 THEN 46 * INTERVAL '1 minute' -- 46 minutes
WHEN 25 THEN 54 * INTERVAL '1 minute' -- 54 minutes
WHEN 26 THEN 54 * INTERVAL '1 minute' -- 54 minutes
WHEN 27 THEN 48 * INTERVAL '1 minute' -- 48 minutes
WHEN 28 THEN 53 * INTERVAL '1 minute' -- 53 minutes
WHEN 29 THEN 39 * INTERVAL '1 minute' -- 39 minutes
WHEN 30 THEN 38 * INTERVAL '1 minute' -- 38 minutes
WHEN 31 THEN 25 * INTERVAL '1 minute' -- 25 minutes
WHEN 32 THEN 22 * INTERVAL '1 minute' -- 22 minutes
WHEN 33 THEN 11 * INTERVAL '1 minute' -- 11 minutes
WHEN 34 THEN 32 * INTERVAL '1 minute' -- 32 minutes
WHEN 35 THEN 18 * INTERVAL '1 minute' -- 18 minutes
WHEN 36 THEN 52 * INTERVAL '1 minute' -- 52 minutes
WHEN 37 THEN 56 * INTERVAL '1 minute' -- 56 minutes
WHEN 38 THEN 45 * INTERVAL '1 minute' -- 45 minutes
WHEN 39 THEN 25 * INTERVAL '1 minute' -- 25 minutes
WHEN 40 THEN 13 * INTERVAL '1 minute' -- 13 minutes
END,
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE CRACKING PHASE RECORDS FOR MEYER EXPERIMENTS
-- =============================================
-- Create cracking records for Meyer experiments (1-40)
INSERT INTO public.cracking (
experiment_id,
machine_type_id,
scheduled_start_time,
created_by
)
SELECT
e.id,
(SELECT id FROM public.machine_types WHERE name = 'Meyer Cracker'),
NOW() + (e.experiment_number) * INTERVAL '1 day' + INTERVAL '3 days', -- Start 3 days after soaking
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE MEYER CRACKER PARAMETERS FOR MEYER EXPERIMENTS
-- =============================================
-- Create Meyer cracker parameters for Meyer experiments (1-40)
INSERT INTO public.meyer_cracker_parameters (
cracking_id,
motor_speed_hz,
jig_displacement_inches,
spring_stiffness_nm
)
SELECT
c.id,
CASE e.experiment_number
WHEN 1 THEN 33.0
WHEN 2 THEN 30.0
WHEN 3 THEN 47.0
WHEN 4 THEN 42.0
WHEN 5 THEN 53.0
WHEN 6 THEN 37.0
WHEN 7 THEN 40.0
WHEN 8 THEN 39.0
WHEN 9 THEN 49.0
WHEN 10 THEN 47.0
WHEN 11 THEN 52.0
WHEN 12 THEN 59.0
WHEN 13 THEN 41.0
WHEN 14 THEN 46.0
WHEN 15 THEN 50.0
WHEN 16 THEN 36.0
WHEN 17 THEN 33.0
WHEN 18 THEN 35.0
WHEN 19 THEN 55.0
WHEN 20 THEN 44.0
WHEN 21 THEN 37.0
WHEN 22 THEN 56.0
WHEN 23 THEN 30.0
WHEN 24 THEN 60.0
WHEN 25 THEN 41.0
WHEN 26 THEN 55.0
WHEN 27 THEN 39.0
WHEN 28 THEN 34.0
WHEN 29 THEN 57.0
WHEN 30 THEN 45.0
WHEN 31 THEN 52.0
WHEN 32 THEN 51.0
WHEN 33 THEN 36.0
WHEN 34 THEN 44.0
WHEN 35 THEN 58.0
WHEN 36 THEN 32.0
WHEN 37 THEN 43.0
WHEN 38 THEN 60.0
WHEN 39 THEN 54.0
WHEN 40 THEN 48.0
END,
CASE e.experiment_number
WHEN 1 THEN -0.307
WHEN 2 THEN -0.311
WHEN 3 THEN -0.291
WHEN 4 THEN -0.314
WHEN 5 THEN -0.302
WHEN 6 THEN -0.301
WHEN 7 THEN -0.286
WHEN 8 THEN -0.309
WHEN 9 THEN -0.299
WHEN 10 THEN -0.295
WHEN 11 THEN -0.302
WHEN 12 THEN -0.299
WHEN 13 THEN -0.312
WHEN 14 THEN -0.303
WHEN 15 THEN -0.308
WHEN 16 THEN -0.306
WHEN 17 THEN -0.308
WHEN 18 THEN -0.311
WHEN 19 THEN -0.304
WHEN 20 THEN -0.313
WHEN 21 THEN -0.294
WHEN 22 THEN -0.310
WHEN 23 THEN -0.292
WHEN 24 THEN -0.294
WHEN 25 THEN -0.306
WHEN 26 THEN -0.296
WHEN 27 THEN -0.293
WHEN 28 THEN -0.285
WHEN 29 THEN -0.291
WHEN 30 THEN -0.296
WHEN 31 THEN -0.297
WHEN 32 THEN -0.288
WHEN 33 THEN -0.290
WHEN 34 THEN -0.315
WHEN 35 THEN -0.289
WHEN 36 THEN -0.288
WHEN 37 THEN -0.287
WHEN 38 THEN -0.298
WHEN 39 THEN -0.301
WHEN 40 THEN -0.305
END,
CASE e.experiment_number
WHEN 1 THEN 1800.0
WHEN 2 THEN 2000.0
WHEN 3 THEN 1800.0
WHEN 4 THEN 2000.0
WHEN 5 THEN 1800.0
WHEN 6 THEN 2200.0
WHEN 7 THEN 2000.0
WHEN 8 THEN 1800.0
WHEN 9 THEN 2200.0
WHEN 10 THEN 2000.0
WHEN 11 THEN 2000.0
WHEN 12 THEN 1800.0
WHEN 13 THEN 2000.0
WHEN 14 THEN 1800.0
WHEN 15 THEN 1800.0
WHEN 16 THEN 2200.0
WHEN 17 THEN 2200.0
WHEN 18 THEN 1800.0
WHEN 19 THEN 2000.0
WHEN 20 THEN 2200.0
WHEN 21 THEN 2000.0
WHEN 22 THEN 2200.0
WHEN 23 THEN 2200.0
WHEN 24 THEN 2200.0
WHEN 25 THEN 2000.0
WHEN 26 THEN 1800.0
WHEN 27 THEN 2200.0
WHEN 28 THEN 2200.0
WHEN 29 THEN 1800.0
WHEN 30 THEN 2200.0
WHEN 31 THEN 1800.0
WHEN 32 THEN 2200.0
WHEN 33 THEN 2000.0
WHEN 34 THEN 1800.0
WHEN 35 THEN 1800.0
WHEN 36 THEN 1800.0
WHEN 37 THEN 2200.0
WHEN 38 THEN 2200.0
WHEN 39 THEN 2000.0
WHEN 40 THEN 2000.0
END
FROM public.experiments e
JOIN public.cracking c ON c.experiment_id = e.id
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE EXPERIMENT REPETITIONS FOR MEYER EXPERIMENTS
-- =============================================
-- Create experiment repetitions for Meyer experiments
-- Each experiment needs only 1 repetition
INSERT INTO public.experiment_repetitions (
experiment_id,
repetition_number,
status,
created_by
)
SELECT
e.id,
1,
'pending',
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;

View File

@@ -1,560 +0,0 @@
-- Meyer Experiments Seed Data
-- This file contains all 40 Meyer experiments from meyer experiments.csv
-- Each experiment has only 1 repetition required
-- Updated to use 1-based numbering per phase and composite primary key
-- =============================================
-- INSERT MEYER EXPERIMENTS (Post Workshop)
-- =============================================
-- Insert Meyer experiments (experiments 1-40)
INSERT INTO public.experiments (
experiment_number,
reps_required,
results_status,
completion_status,
phase_id,
created_by
) VALUES
-- Meyer Experiments 1-40 (1-based numbering)
(1, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(2, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(3, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(4, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(5, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(6, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(7, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(8, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(9, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(10, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(11, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(12, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(13, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(14, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(15, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(16, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(17, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(18, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(19, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(20, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(21, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(22, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(23, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(24, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(25, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(26, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(27, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(28, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(29, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(30, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(31, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(32, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(33, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(34, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(35, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(36, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(37, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(38, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(39, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com')),
(40, 1, 'valid', false,
(SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments'),
(SELECT id FROM public.user_profiles WHERE email = 's.alireza.v@gmail.com'))
ON CONFLICT (experiment_number, phase_id) DO NOTHING;
-- =============================================
-- CREATE SOAKING PHASE RECORDS FOR MEYER EXPERIMENTS
-- =============================================
-- Create soaking records for Meyer experiments (1-40)
INSERT INTO public.soaking (
experiment_id,
scheduled_start_time,
soaking_duration_minutes,
scheduled_end_time,
created_by
)
SELECT
e.id,
NOW() + (e.experiment_number) * INTERVAL '1 day',
CASE e.experiment_number
WHEN 1 THEN 27 * 60 -- 27 hours = 1620 minutes
WHEN 2 THEN 37 * 60 -- 37 hours = 2220 minutes
WHEN 3 THEN 36 * 60 -- 36 hours = 2160 minutes
WHEN 4 THEN 12 * 60 -- 12 hours = 720 minutes
WHEN 5 THEN 34 * 60 -- 34 hours = 2040 minutes
WHEN 6 THEN 18 * 60 -- 18 hours = 1080 minutes
WHEN 7 THEN 14 * 60 -- 14 hours = 840 minutes
WHEN 8 THEN 18 * 60 -- 18 hours = 1080 minutes
WHEN 9 THEN 11 * 60 -- 11 hours = 660 minutes
WHEN 10 THEN 33 * 60 -- 33 hours = 1980 minutes
WHEN 11 THEN 23 * 60 -- 23 hours = 1380 minutes
WHEN 12 THEN 37 * 60 -- 37 hours = 2220 minutes
WHEN 13 THEN 15 * 60 -- 15 hours = 900 minutes
WHEN 14 THEN 24 * 60 -- 24 hours = 1440 minutes
WHEN 15 THEN 36 * 60 -- 36 hours = 2160 minutes
WHEN 16 THEN 32 * 60 -- 32 hours = 1920 minutes
WHEN 17 THEN 28 * 60 -- 28 hours = 1680 minutes
WHEN 18 THEN 31 * 60 -- 31 hours = 1860 minutes
WHEN 19 THEN 20 * 60 -- 20 hours = 1200 minutes
WHEN 20 THEN 10 * 60 -- 10 hours = 600 minutes
WHEN 21 THEN 16 * 60 -- 16 hours = 960 minutes
WHEN 22 THEN 21 * 60 -- 21 hours = 1260 minutes
WHEN 23 THEN 42 * 60 -- 42 hours = 2520 minutes
WHEN 24 THEN 29 * 60 -- 29 hours = 1740 minutes
WHEN 25 THEN 54 * 60 -- 54 hours = 3240 minutes
WHEN 26 THEN 29 * 60 -- 29 hours = 1740 minutes
WHEN 27 THEN 30 * 60 -- 30 hours = 1800 minutes
WHEN 28 THEN 35 * 60 -- 35 hours = 2100 minutes
WHEN 29 THEN 27 * 60 -- 27 hours = 1620 minutes
WHEN 30 THEN 27 * 60 -- 27 hours = 1620 minutes
WHEN 31 THEN 17 * 60 -- 17 hours = 1020 minutes
WHEN 32 THEN 13 * 60 -- 13 hours = 780 minutes
WHEN 33 THEN 19 * 60 -- 19 hours = 1140 minutes
WHEN 34 THEN 38 * 60 -- 38 hours = 2280 minutes
WHEN 35 THEN 26 * 60 -- 26 hours = 1560 minutes
WHEN 36 THEN 22 * 60 -- 22 hours = 1320 minutes
WHEN 37 THEN 12 * 60 -- 12 hours = 720 minutes
WHEN 38 THEN 16 * 60 -- 16 hours = 960 minutes
WHEN 39 THEN 22 * 60 -- 22 hours = 1320 minutes
WHEN 40 THEN 24 * 60 -- 24 hours = 1440 minutes
END,
NOW() + (e.experiment_number) * INTERVAL '1 day' +
CASE e.experiment_number
WHEN 1 THEN 27 * 60 * INTERVAL '1 minute' -- 27 hours = 1620 minutes
WHEN 2 THEN 37 * 60 * INTERVAL '1 minute' -- 37 hours = 2220 minutes
WHEN 3 THEN 36 * 60 * INTERVAL '1 minute' -- 36 hours = 2160 minutes
WHEN 4 THEN 12 * 60 * INTERVAL '1 minute' -- 12 hours = 720 minutes
WHEN 5 THEN 34 * 60 * INTERVAL '1 minute' -- 34 hours = 2040 minutes
WHEN 6 THEN 18 * 60 * INTERVAL '1 minute' -- 18 hours = 1080 minutes
WHEN 7 THEN 14 * 60 * INTERVAL '1 minute' -- 14 hours = 840 minutes
WHEN 8 THEN 18 * 60 * INTERVAL '1 minute' -- 18 hours = 1080 minutes
WHEN 9 THEN 11 * 60 * INTERVAL '1 minute' -- 11 hours = 660 minutes
WHEN 10 THEN 33 * 60 * INTERVAL '1 minute' -- 33 hours = 1980 minutes
WHEN 11 THEN 23 * 60 * INTERVAL '1 minute' -- 23 hours = 1380 minutes
WHEN 12 THEN 37 * 60 * INTERVAL '1 minute' -- 37 hours = 2220 minutes
WHEN 13 THEN 15 * 60 * INTERVAL '1 minute' -- 15 hours = 900 minutes
WHEN 14 THEN 24 * 60 * INTERVAL '1 minute' -- 24 hours = 1440 minutes
WHEN 15 THEN 36 * 60 * INTERVAL '1 minute' -- 36 hours = 2160 minutes
WHEN 16 THEN 32 * 60 * INTERVAL '1 minute' -- 32 hours = 1920 minutes
WHEN 17 THEN 28 * 60 * INTERVAL '1 minute' -- 28 hours = 1680 minutes
WHEN 18 THEN 31 * 60 * INTERVAL '1 minute' -- 31 hours = 1860 minutes
WHEN 19 THEN 20 * 60 * INTERVAL '1 minute' -- 20 hours = 1200 minutes
WHEN 20 THEN 10 * 60 * INTERVAL '1 minute' -- 10 hours = 600 minutes
WHEN 21 THEN 16 * 60 * INTERVAL '1 minute' -- 16 hours = 960 minutes
WHEN 22 THEN 21 * 60 * INTERVAL '1 minute' -- 21 hours = 1260 minutes
WHEN 23 THEN 42 * 60 * INTERVAL '1 minute' -- 42 hours = 2520 minutes
WHEN 24 THEN 29 * 60 * INTERVAL '1 minute' -- 29 hours = 1740 minutes
WHEN 25 THEN 54 * 60 * INTERVAL '1 minute' -- 54 hours = 3240 minutes
WHEN 26 THEN 29 * 60 * INTERVAL '1 minute' -- 29 hours = 1740 minutes
WHEN 27 THEN 30 * 60 * INTERVAL '1 minute' -- 30 hours = 1800 minutes
WHEN 28 THEN 35 * 60 * INTERVAL '1 minute' -- 35 hours = 2100 minutes
WHEN 29 THEN 27 * 60 * INTERVAL '1 minute' -- 27 hours = 1620 minutes
WHEN 30 THEN 27 * 60 * INTERVAL '1 minute' -- 27 hours = 1620 minutes
WHEN 31 THEN 17 * 60 * INTERVAL '1 minute' -- 17 hours = 1020 minutes
WHEN 32 THEN 13 * 60 * INTERVAL '1 minute' -- 13 hours = 780 minutes
WHEN 33 THEN 19 * 60 * INTERVAL '1 minute' -- 19 hours = 1140 minutes
WHEN 34 THEN 38 * 60 * INTERVAL '1 minute' -- 38 hours = 2280 minutes
WHEN 35 THEN 26 * 60 * INTERVAL '1 minute' -- 26 hours = 1560 minutes
WHEN 36 THEN 22 * 60 * INTERVAL '1 minute' -- 22 hours = 1320 minutes
WHEN 37 THEN 12 * 60 * INTERVAL '1 minute' -- 12 hours = 720 minutes
WHEN 38 THEN 16 * 60 * INTERVAL '1 minute' -- 16 hours = 960 minutes
WHEN 39 THEN 22 * 60 * INTERVAL '1 minute' -- 22 hours = 1320 minutes
WHEN 40 THEN 24 * 60 * INTERVAL '1 minute' -- 24 hours = 1440 minutes
END,
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE AIRDRYING PHASE RECORDS FOR MEYER EXPERIMENTS
-- =============================================
-- Create airdrying records for Meyer experiments (1-40)
INSERT INTO public.airdrying (
experiment_id,
scheduled_start_time,
duration_minutes,
scheduled_end_time,
created_by
)
SELECT
e.id,
NOW() + (e.experiment_number) * INTERVAL '1 day' + INTERVAL '2 days', -- Start 2 days after soaking
CASE e.experiment_number
WHEN 1 THEN 28 -- 28 minutes
WHEN 2 THEN 17 -- 17 minutes
WHEN 3 THEN 50 -- 50 minutes
WHEN 4 THEN 30 -- 30 minutes
WHEN 5 THEN 19 -- 19 minutes
WHEN 6 THEN 40 -- 40 minutes
WHEN 7 THEN 59 -- 59 minutes
WHEN 8 THEN 32 -- 32 minutes
WHEN 9 THEN 31 -- 31 minutes
WHEN 10 THEN 12 -- 12 minutes
WHEN 11 THEN 36 -- 36 minutes
WHEN 12 THEN 35 -- 35 minutes
WHEN 13 THEN 15 -- 15 minutes
WHEN 14 THEN 22 -- 22 minutes
WHEN 15 THEN 15 -- 15 minutes
WHEN 16 THEN 48 -- 48 minutes
WHEN 17 THEN 38 -- 38 minutes
WHEN 18 THEN 51 -- 51 minutes
WHEN 19 THEN 57 -- 57 minutes
WHEN 20 THEN 27 -- 27 minutes
WHEN 21 THEN 43 -- 43 minutes
WHEN 22 THEN 42 -- 42 minutes
WHEN 23 THEN 21 -- 21 minutes
WHEN 24 THEN 46 -- 46 minutes
WHEN 25 THEN 54 -- 54 minutes
WHEN 26 THEN 54 -- 54 minutes
WHEN 27 THEN 48 -- 48 minutes
WHEN 28 THEN 53 -- 53 minutes
WHEN 29 THEN 39 -- 39 minutes
WHEN 30 THEN 38 -- 38 minutes
WHEN 31 THEN 25 -- 25 minutes
WHEN 32 THEN 22 -- 22 minutes
WHEN 33 THEN 11 -- 11 minutes
WHEN 34 THEN 32 -- 32 minutes
WHEN 35 THEN 18 -- 18 minutes
WHEN 36 THEN 52 -- 52 minutes
WHEN 37 THEN 56 -- 56 minutes
WHEN 38 THEN 45 -- 45 minutes
WHEN 39 THEN 25 -- 25 minutes
WHEN 40 THEN 13 -- 13 minutes
END,
NOW() + (e.experiment_number) * INTERVAL '1 day' + INTERVAL '2 days' +
CASE e.experiment_number
WHEN 1 THEN 28 * INTERVAL '1 minute' -- 28 minutes
WHEN 2 THEN 17 * INTERVAL '1 minute' -- 17 minutes
WHEN 3 THEN 50 * INTERVAL '1 minute' -- 50 minutes
WHEN 4 THEN 30 * INTERVAL '1 minute' -- 30 minutes
WHEN 5 THEN 19 * INTERVAL '1 minute' -- 19 minutes
WHEN 6 THEN 40 * INTERVAL '1 minute' -- 40 minutes
WHEN 7 THEN 59 * INTERVAL '1 minute' -- 59 minutes
WHEN 8 THEN 32 * INTERVAL '1 minute' -- 32 minutes
WHEN 9 THEN 31 * INTERVAL '1 minute' -- 31 minutes
WHEN 10 THEN 12 * INTERVAL '1 minute' -- 12 minutes
WHEN 11 THEN 36 * INTERVAL '1 minute' -- 36 minutes
WHEN 12 THEN 35 * INTERVAL '1 minute' -- 35 minutes
WHEN 13 THEN 15 * INTERVAL '1 minute' -- 15 minutes
WHEN 14 THEN 22 * INTERVAL '1 minute' -- 22 minutes
WHEN 15 THEN 15 * INTERVAL '1 minute' -- 15 minutes
WHEN 16 THEN 48 * INTERVAL '1 minute' -- 48 minutes
WHEN 17 THEN 38 * INTERVAL '1 minute' -- 38 minutes
WHEN 18 THEN 51 * INTERVAL '1 minute' -- 51 minutes
WHEN 19 THEN 57 * INTERVAL '1 minute' -- 57 minutes
WHEN 20 THEN 27 * INTERVAL '1 minute' -- 27 minutes
WHEN 21 THEN 43 * INTERVAL '1 minute' -- 43 minutes
WHEN 22 THEN 42 * INTERVAL '1 minute' -- 42 minutes
WHEN 23 THEN 21 * INTERVAL '1 minute' -- 21 minutes
WHEN 24 THEN 46 * INTERVAL '1 minute' -- 46 minutes
WHEN 25 THEN 54 * INTERVAL '1 minute' -- 54 minutes
WHEN 26 THEN 54 * INTERVAL '1 minute' -- 54 minutes
WHEN 27 THEN 48 * INTERVAL '1 minute' -- 48 minutes
WHEN 28 THEN 53 * INTERVAL '1 minute' -- 53 minutes
WHEN 29 THEN 39 * INTERVAL '1 minute' -- 39 minutes
WHEN 30 THEN 38 * INTERVAL '1 minute' -- 38 minutes
WHEN 31 THEN 25 * INTERVAL '1 minute' -- 25 minutes
WHEN 32 THEN 22 * INTERVAL '1 minute' -- 22 minutes
WHEN 33 THEN 11 * INTERVAL '1 minute' -- 11 minutes
WHEN 34 THEN 32 * INTERVAL '1 minute' -- 32 minutes
WHEN 35 THEN 18 * INTERVAL '1 minute' -- 18 minutes
WHEN 36 THEN 52 * INTERVAL '1 minute' -- 52 minutes
WHEN 37 THEN 56 * INTERVAL '1 minute' -- 56 minutes
WHEN 38 THEN 45 * INTERVAL '1 minute' -- 45 minutes
WHEN 39 THEN 25 * INTERVAL '1 minute' -- 25 minutes
WHEN 40 THEN 13 * INTERVAL '1 minute' -- 13 minutes
END,
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE CRACKING PHASE RECORDS FOR MEYER EXPERIMENTS
-- =============================================
-- Create cracking records for Meyer experiments (1-40)
INSERT INTO public.cracking (
experiment_id,
machine_type_id,
scheduled_start_time,
created_by
)
SELECT
e.id,
(SELECT id FROM public.machine_types WHERE name = 'Meyer Cracker'),
NOW() + (e.experiment_number) * INTERVAL '1 day' + INTERVAL '3 days', -- Start 3 days after soaking
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;
-- =============================================
-- CREATE MEYER CRACKER PARAMETERS FOR MEYER EXPERIMENTS
-- =============================================
-- Create Meyer cracker parameters for Meyer experiments (1-40)
-- First create the Meyer cracker parameters
INSERT INTO public.meyer_cracker_parameters (
motor_speed_hz,
jig_displacement_inches,
spring_stiffness_nm
)
SELECT
CASE e.experiment_number
WHEN 1 THEN 33.0
WHEN 2 THEN 30.0
WHEN 3 THEN 47.0
WHEN 4 THEN 42.0
WHEN 5 THEN 53.0
WHEN 6 THEN 37.0
WHEN 7 THEN 40.0
WHEN 8 THEN 39.0
WHEN 9 THEN 49.0
WHEN 10 THEN 47.0
WHEN 11 THEN 52.0
WHEN 12 THEN 59.0
WHEN 13 THEN 41.0
WHEN 14 THEN 46.0
WHEN 15 THEN 50.0
WHEN 16 THEN 36.0
WHEN 17 THEN 33.0
WHEN 18 THEN 35.0
WHEN 19 THEN 55.0
WHEN 20 THEN 44.0
WHEN 21 THEN 37.0
WHEN 22 THEN 56.0
WHEN 23 THEN 30.0
WHEN 24 THEN 60.0
WHEN 25 THEN 41.0
WHEN 26 THEN 55.0
WHEN 27 THEN 39.0
WHEN 28 THEN 34.0
WHEN 29 THEN 57.0
WHEN 30 THEN 45.0
WHEN 31 THEN 52.0
WHEN 32 THEN 51.0
WHEN 33 THEN 36.0
WHEN 34 THEN 44.0
WHEN 35 THEN 58.0
WHEN 36 THEN 32.0
WHEN 37 THEN 43.0
WHEN 38 THEN 60.0
WHEN 39 THEN 54.0
WHEN 40 THEN 48.0
END,
CASE e.experiment_number
WHEN 1 THEN -0.307
WHEN 2 THEN -0.311
WHEN 3 THEN -0.291
WHEN 4 THEN -0.314
WHEN 5 THEN -0.302
WHEN 6 THEN -0.301
WHEN 7 THEN -0.286
WHEN 8 THEN -0.309
WHEN 9 THEN -0.299
WHEN 10 THEN -0.295
WHEN 11 THEN -0.302
WHEN 12 THEN -0.299
WHEN 13 THEN -0.312
WHEN 14 THEN -0.303
WHEN 15 THEN -0.308
WHEN 16 THEN -0.306
WHEN 17 THEN -0.308
WHEN 18 THEN -0.311
WHEN 19 THEN -0.304
WHEN 20 THEN -0.313
WHEN 21 THEN -0.294
WHEN 22 THEN -0.310
WHEN 23 THEN -0.292
WHEN 24 THEN -0.294
WHEN 25 THEN -0.306
WHEN 26 THEN -0.296
WHEN 27 THEN -0.293
WHEN 28 THEN -0.285
WHEN 29 THEN -0.291
WHEN 30 THEN -0.296
WHEN 31 THEN -0.297
WHEN 32 THEN -0.288
WHEN 33 THEN -0.290
WHEN 34 THEN -0.315
WHEN 35 THEN -0.289
WHEN 36 THEN -0.288
WHEN 37 THEN -0.287
WHEN 38 THEN -0.298
WHEN 39 THEN -0.301
WHEN 40 THEN -0.305
END,
CASE e.experiment_number
WHEN 1 THEN 1800.0
WHEN 2 THEN 2000.0
WHEN 3 THEN 1800.0
WHEN 4 THEN 2000.0
WHEN 5 THEN 1800.0
WHEN 6 THEN 2200.0
WHEN 7 THEN 2000.0
WHEN 8 THEN 1800.0
WHEN 9 THEN 2200.0
WHEN 10 THEN 2000.0
WHEN 11 THEN 2000.0
WHEN 12 THEN 1800.0
WHEN 13 THEN 2000.0
WHEN 14 THEN 1800.0
WHEN 15 THEN 1800.0
WHEN 16 THEN 2200.0
WHEN 17 THEN 2200.0
WHEN 18 THEN 1800.0
WHEN 19 THEN 2000.0
WHEN 20 THEN 2200.0
WHEN 21 THEN 2000.0
WHEN 22 THEN 2200.0
WHEN 23 THEN 2200.0
WHEN 24 THEN 2200.0
WHEN 25 THEN 2000.0
WHEN 26 THEN 1800.0
WHEN 27 THEN 2200.0
WHEN 28 THEN 2200.0
WHEN 29 THEN 1800.0
WHEN 30 THEN 2200.0
WHEN 31 THEN 1800.0
WHEN 32 THEN 2200.0
WHEN 33 THEN 2000.0
WHEN 34 THEN 1800.0
WHEN 35 THEN 1800.0
WHEN 36 THEN 1800.0
WHEN 37 THEN 2200.0
WHEN 38 THEN 2200.0
WHEN 39 THEN 2000.0
WHEN 40 THEN 2000.0
END
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;
-- Now update the cracking records to reference the Meyer cracker parameters
-- Match them by the order they were created
WITH parameter_mapping AS (
SELECT
e.experiment_number,
mcp.id as param_id,
ROW_NUMBER() OVER (ORDER BY e.experiment_number) as exp_rn,
ROW_NUMBER() OVER (ORDER BY mcp.created_at) as param_rn
FROM public.experiments e
CROSS JOIN public.meyer_cracker_parameters mcp
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
)
UPDATE public.cracking c
SET meyer_cracker_parameters_id = pm.param_id
FROM parameter_mapping pm
JOIN public.experiments e ON c.experiment_id = e.id
WHERE e.experiment_number = pm.experiment_number
AND pm.exp_rn = pm.param_rn
AND c.meyer_cracker_parameters_id IS NULL;
-- =============================================
-- CREATE EXPERIMENT REPETITIONS FOR MEYER EXPERIMENTS
-- =============================================
-- Create experiment repetitions for Meyer experiments
-- Each experiment needs only 1 repetition
INSERT INTO public.experiment_repetitions (
experiment_id,
repetition_number,
status,
created_by
)
SELECT
e.id,
1,
'pending',
e.created_by
FROM public.experiments e
WHERE e.experiment_number BETWEEN 1 AND 40
AND e.phase_id = (SELECT id FROM public.experiment_phases WHERE name = 'Post Workshop Meyer Experiments')
ON CONFLICT DO NOTHING;