- Updated ExperimentForm to handle additional phase parameters and improved initial state management. - Modified ExperimentModal to fetch experiment data with phase configuration and ensure unique experiment numbers within the same phase. - Renamed references from "phases" to "books" across ExperimentPhases, PhaseExperiments, and related components for consistency with the new terminology. - Enhanced error handling and validation for new shelling parameters in ExperimentForm. - Updated Supabase interface definitions to reflect changes in experiment and phase data structures.
400 lines
17 KiB
PL/PgSQL
400 lines
17 KiB
PL/PgSQL
-- Rename table experiment_phases to experiment_books
|
|
-- This migration renames the table and updates all dependent objects (views, functions, triggers, indexes, RLS).
|
|
|
|
-- =============================================
|
|
-- 1. RENAME TABLE
|
|
-- =============================================
|
|
|
|
ALTER TABLE public.experiment_phases RENAME TO experiment_books;
|
|
|
|
-- =============================================
|
|
-- 2. RENAME TRIGGER
|
|
-- =============================================
|
|
|
|
DROP TRIGGER IF EXISTS set_updated_at_experiment_phases ON public.experiment_books;
|
|
CREATE TRIGGER set_updated_at_experiment_books
|
|
BEFORE UPDATE ON public.experiment_books
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION public.handle_updated_at();
|
|
|
|
-- =============================================
|
|
-- 3. RENAME CONSTRAINT
|
|
-- =============================================
|
|
|
|
ALTER TABLE public.experiment_books
|
|
RENAME CONSTRAINT ck_experiment_phases_machine_required_when_cracking
|
|
TO ck_experiment_books_machine_required_when_cracking;
|
|
|
|
-- =============================================
|
|
-- 4. RENAME INDEXES
|
|
-- =============================================
|
|
|
|
ALTER INDEX IF EXISTS public.idx_experiment_phases_name RENAME TO idx_experiment_books_name;
|
|
ALTER INDEX IF EXISTS public.idx_experiment_phases_cracking_machine_type_id RENAME TO idx_experiment_books_cracking_machine_type_id;
|
|
|
|
-- =============================================
|
|
-- 5. RLS POLICIES (drop old, create new with updated names)
|
|
-- =============================================
|
|
|
|
DROP POLICY IF EXISTS "Experiment phases are viewable by authenticated users" ON public.experiment_books;
|
|
DROP POLICY IF EXISTS "Experiment phases are insertable by authenticated users" ON public.experiment_books;
|
|
DROP POLICY IF EXISTS "Experiment phases are updatable by authenticated users" ON public.experiment_books;
|
|
DROP POLICY IF EXISTS "Experiment phases are deletable by authenticated users" ON public.experiment_books;
|
|
|
|
CREATE POLICY "Experiment books are viewable by authenticated users" ON public.experiment_books
|
|
FOR SELECT USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Experiment books are insertable by authenticated users" ON public.experiment_books
|
|
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Experiment books are updatable by authenticated users" ON public.experiment_books
|
|
FOR UPDATE USING (auth.role() = 'authenticated');
|
|
|
|
CREATE POLICY "Experiment books are deletable by authenticated users" ON public.experiment_books
|
|
FOR DELETE USING (auth.role() = 'authenticated');
|
|
|
|
-- =============================================
|
|
-- 6. UPDATE FUNCTION: create_phase_executions_for_repetition (references experiment_phases)
|
|
-- =============================================
|
|
|
|
CREATE OR REPLACE FUNCTION create_phase_executions_for_repetition()
|
|
RETURNS TRIGGER AS $$
|
|
DECLARE
|
|
exp_phase_config RECORD;
|
|
phase_type_list TEXT[] := ARRAY[]::TEXT[];
|
|
phase_name TEXT;
|
|
BEGIN
|
|
SELECT
|
|
ep.has_soaking,
|
|
ep.has_airdrying,
|
|
ep.has_cracking,
|
|
ep.has_shelling,
|
|
ep.cracking_machine_type_id
|
|
INTO exp_phase_config
|
|
FROM public.experiments e
|
|
JOIN public.experiment_books ep ON e.phase_id = ep.id
|
|
WHERE e.id = NEW.experiment_id;
|
|
|
|
IF exp_phase_config.has_soaking THEN
|
|
phase_type_list := array_append(phase_type_list, 'soaking');
|
|
END IF;
|
|
IF exp_phase_config.has_airdrying THEN
|
|
phase_type_list := array_append(phase_type_list, 'airdrying');
|
|
END IF;
|
|
IF exp_phase_config.has_cracking THEN
|
|
phase_type_list := array_append(phase_type_list, 'cracking');
|
|
END IF;
|
|
IF exp_phase_config.has_shelling THEN
|
|
phase_type_list := array_append(phase_type_list, 'shelling');
|
|
END IF;
|
|
|
|
FOREACH phase_name IN ARRAY phase_type_list
|
|
LOOP
|
|
INSERT INTO public.experiment_phase_executions (
|
|
repetition_id,
|
|
phase_type,
|
|
scheduled_start_time,
|
|
status,
|
|
created_by,
|
|
soaking_duration_minutes,
|
|
duration_minutes,
|
|
machine_type_id
|
|
)
|
|
VALUES (
|
|
NEW.id,
|
|
phase_name,
|
|
NOW(),
|
|
'pending',
|
|
NEW.created_by,
|
|
NULL,
|
|
NULL,
|
|
CASE WHEN phase_name = 'cracking'
|
|
THEN exp_phase_config.cracking_machine_type_id
|
|
ELSE NULL END
|
|
);
|
|
END LOOP;
|
|
|
|
RETURN NEW;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- =============================================
|
|
-- 7. UPDATE FUNCTION: create_sample_experiment_phases (INSERT into experiment_books)
|
|
-- =============================================
|
|
|
|
CREATE OR REPLACE FUNCTION public.create_sample_experiment_phases()
|
|
RETURNS VOID AS $$
|
|
DECLARE
|
|
jc_cracker_id UUID;
|
|
meyer_cracker_id UUID;
|
|
BEGIN
|
|
SELECT id INTO jc_cracker_id FROM public.machine_types WHERE name = 'JC Cracker';
|
|
SELECT id INTO meyer_cracker_id FROM public.machine_types WHERE name = 'Meyer Cracker';
|
|
|
|
INSERT INTO public.experiment_books (name, description, has_soaking, has_airdrying, has_cracking, has_shelling, cracking_machine_type_id, created_by) VALUES
|
|
('Full Process - JC Cracker', 'Complete pecan processing with JC Cracker', true, true, true, true, jc_cracker_id, (SELECT id FROM public.user_profiles LIMIT 1)),
|
|
('Full Process - Meyer Cracker', 'Complete pecan processing with Meyer Cracker', true, true, true, true, meyer_cracker_id, (SELECT id FROM public.user_profiles LIMIT 1)),
|
|
('Cracking Only - JC Cracker', 'JC Cracker cracking process only', false, false, true, false, jc_cracker_id, (SELECT id FROM public.user_profiles LIMIT 1)),
|
|
('Cracking Only - Meyer Cracker', 'Meyer Cracker cracking process only', false, false, true, false, meyer_cracker_id, (SELECT id FROM public.user_profiles LIMIT 1))
|
|
ON CONFLICT (name) DO NOTHING;
|
|
END;
|
|
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
|
|
|
-- =============================================
|
|
-- 8. UPDATE VIEWS (from 00014 - experiments_with_phases, repetitions_with_phases, experiments_with_all_reps_and_phases, get_experiment_with_reps_and_phases)
|
|
-- =============================================
|
|
|
|
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.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,
|
|
er.id as first_repetition_id,
|
|
er.repetition_number as first_repetition_number,
|
|
soaking_e.id as soaking_id,
|
|
soaking_e.scheduled_start_time as soaking_scheduled_start,
|
|
soaking_e.actual_start_time as soaking_actual_start,
|
|
soaking_e.soaking_duration_minutes,
|
|
soaking_e.scheduled_end_time as soaking_scheduled_end,
|
|
soaking_e.actual_end_time as soaking_actual_end,
|
|
airdrying_e.id as airdrying_id,
|
|
airdrying_e.scheduled_start_time as airdrying_scheduled_start,
|
|
airdrying_e.actual_start_time as airdrying_actual_start,
|
|
airdrying_e.duration_minutes as airdrying_duration,
|
|
airdrying_e.scheduled_end_time as airdrying_scheduled_end,
|
|
airdrying_e.actual_end_time as airdrying_actual_end,
|
|
cracking_e.id as cracking_id,
|
|
cracking_e.scheduled_start_time as cracking_scheduled_start,
|
|
cracking_e.actual_start_time as cracking_actual_start,
|
|
cracking_e.actual_end_time as cracking_actual_end,
|
|
mt.name as machine_type_name,
|
|
shelling_e.id as shelling_id,
|
|
shelling_e.scheduled_start_time as shelling_scheduled_start,
|
|
shelling_e.actual_start_time as shelling_actual_start,
|
|
shelling_e.actual_end_time as shelling_actual_end
|
|
FROM public.experiments e
|
|
LEFT JOIN public.experiment_books ep ON e.phase_id = ep.id
|
|
LEFT JOIN LATERAL (
|
|
SELECT id, repetition_number
|
|
FROM public.experiment_repetitions
|
|
WHERE experiment_id = e.id
|
|
ORDER BY repetition_number
|
|
LIMIT 1
|
|
) er ON true
|
|
LEFT JOIN public.experiment_phase_executions soaking_e
|
|
ON soaking_e.repetition_id = er.id AND soaking_e.phase_type = 'soaking'
|
|
LEFT JOIN public.experiment_phase_executions airdrying_e
|
|
ON airdrying_e.repetition_id = er.id AND airdrying_e.phase_type = 'airdrying'
|
|
LEFT JOIN public.experiment_phase_executions cracking_e
|
|
ON cracking_e.repetition_id = er.id AND cracking_e.phase_type = 'cracking'
|
|
LEFT JOIN public.experiment_phase_executions shelling_e
|
|
ON shelling_e.repetition_id = er.id AND shelling_e.phase_type = 'shelling'
|
|
LEFT JOIN public.machine_types mt ON cracking_e.machine_type_id = mt.id;
|
|
|
|
CREATE OR REPLACE VIEW public.repetitions_with_phases AS
|
|
SELECT
|
|
er.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,
|
|
ep.has_airdrying,
|
|
ep.has_cracking,
|
|
ep.has_shelling,
|
|
soaking_e.scheduled_start_time as soaking_scheduled_start,
|
|
soaking_e.actual_start_time as soaking_actual_start,
|
|
soaking_e.soaking_duration_minutes,
|
|
soaking_e.scheduled_end_time as soaking_scheduled_end,
|
|
soaking_e.actual_end_time as soaking_actual_end,
|
|
airdrying_e.scheduled_start_time as airdrying_scheduled_start,
|
|
airdrying_e.actual_start_time as airdrying_actual_start,
|
|
airdrying_e.duration_minutes as airdrying_duration,
|
|
airdrying_e.scheduled_end_time as airdrying_scheduled_end,
|
|
airdrying_e.actual_end_time as airdrying_actual_end,
|
|
cracking_e.scheduled_start_time as cracking_scheduled_start,
|
|
cracking_e.actual_start_time as cracking_actual_start,
|
|
cracking_e.actual_end_time as cracking_actual_end,
|
|
mt.name as machine_type_name,
|
|
shelling_e.scheduled_start_time as shelling_scheduled_start,
|
|
shelling_e.actual_start_time as shelling_actual_start,
|
|
shelling_e.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_books ep ON e.phase_id = ep.id
|
|
LEFT JOIN public.experiment_phase_executions soaking_e
|
|
ON er.id = soaking_e.repetition_id AND soaking_e.phase_type = 'soaking'
|
|
LEFT JOIN public.experiment_phase_executions airdrying_e
|
|
ON er.id = airdrying_e.repetition_id AND airdrying_e.phase_type = 'airdrying'
|
|
LEFT JOIN public.experiment_phase_executions cracking_e
|
|
ON er.id = cracking_e.repetition_id AND cracking_e.phase_type = 'cracking'
|
|
LEFT JOIN public.experiment_phase_executions shelling_e
|
|
ON er.id = shelling_e.repetition_id AND shelling_e.phase_type = 'shelling'
|
|
LEFT JOIN public.machine_types mt ON cracking_e.machine_type_id = mt.id;
|
|
|
|
-- experiments_with_all_reps_and_phases
|
|
CREATE OR REPLACE VIEW public.experiments_with_all_reps_and_phases AS
|
|
SELECT
|
|
e.id as experiment_id,
|
|
e.experiment_number,
|
|
e.reps_required,
|
|
e.weight_per_repetition_lbs,
|
|
e.results_status,
|
|
e.completion_status,
|
|
e.phase_id,
|
|
e.created_at as experiment_created_at,
|
|
e.updated_at as experiment_updated_at,
|
|
e.created_by as experiment_created_by,
|
|
ep.name as phase_name,
|
|
ep.description as phase_description,
|
|
ep.has_soaking,
|
|
ep.has_airdrying,
|
|
ep.has_cracking,
|
|
ep.has_shelling,
|
|
ep.cracking_machine_type_id as phase_cracking_machine_type_id,
|
|
er.id as repetition_id,
|
|
er.repetition_number,
|
|
er.status as repetition_status,
|
|
er.scheduled_date,
|
|
er.created_at as repetition_created_at,
|
|
er.updated_at as repetition_updated_at,
|
|
er.created_by as repetition_created_by,
|
|
soaking_e.id as soaking_execution_id,
|
|
soaking_e.scheduled_start_time as soaking_scheduled_start,
|
|
soaking_e.actual_start_time as soaking_actual_start,
|
|
soaking_e.soaking_duration_minutes,
|
|
soaking_e.scheduled_end_time as soaking_scheduled_end,
|
|
soaking_e.actual_end_time as soaking_actual_end,
|
|
soaking_e.status as soaking_status,
|
|
airdrying_e.id as airdrying_execution_id,
|
|
airdrying_e.scheduled_start_time as airdrying_scheduled_start,
|
|
airdrying_e.actual_start_time as airdrying_actual_start,
|
|
airdrying_e.duration_minutes as airdrying_duration_minutes,
|
|
airdrying_e.scheduled_end_time as airdrying_scheduled_end,
|
|
airdrying_e.actual_end_time as airdrying_actual_end,
|
|
airdrying_e.status as airdrying_status,
|
|
cracking_e.id as cracking_execution_id,
|
|
cracking_e.scheduled_start_time as cracking_scheduled_start,
|
|
cracking_e.actual_start_time as cracking_actual_start,
|
|
cracking_e.scheduled_end_time as cracking_scheduled_end,
|
|
cracking_e.actual_end_time as cracking_actual_end,
|
|
cracking_e.machine_type_id as cracking_machine_type_id,
|
|
cracking_e.status as cracking_status,
|
|
mt.name as machine_type_name,
|
|
shelling_e.id as shelling_execution_id,
|
|
shelling_e.scheduled_start_time as shelling_scheduled_start,
|
|
shelling_e.actual_start_time as shelling_actual_start,
|
|
shelling_e.scheduled_end_time as shelling_scheduled_end,
|
|
shelling_e.actual_end_time as shelling_actual_end,
|
|
shelling_e.status as shelling_status
|
|
FROM public.experiments e
|
|
LEFT JOIN public.experiment_books ep ON e.phase_id = ep.id
|
|
LEFT JOIN public.experiment_repetitions er ON er.experiment_id = e.id
|
|
LEFT JOIN public.experiment_phase_executions soaking_e
|
|
ON soaking_e.repetition_id = er.id AND soaking_e.phase_type = 'soaking'
|
|
LEFT JOIN public.experiment_phase_executions airdrying_e
|
|
ON airdrying_e.repetition_id = er.id AND airdrying_e.phase_type = 'airdrying'
|
|
LEFT JOIN public.experiment_phase_executions cracking_e
|
|
ON cracking_e.repetition_id = er.id AND cracking_e.phase_type = 'cracking'
|
|
LEFT JOIN public.experiment_phase_executions shelling_e
|
|
ON shelling_e.repetition_id = er.id AND shelling_e.phase_type = 'shelling'
|
|
LEFT JOIN public.machine_types mt ON cracking_e.machine_type_id = mt.id
|
|
ORDER BY e.experiment_number, er.repetition_number;
|
|
|
|
-- get_experiment_with_reps_and_phases function
|
|
CREATE OR REPLACE FUNCTION public.get_experiment_with_reps_and_phases(p_experiment_id UUID)
|
|
RETURNS TABLE (
|
|
experiment_id UUID,
|
|
experiment_number INTEGER,
|
|
phase_name TEXT,
|
|
repetitions JSONB
|
|
) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT
|
|
e.id,
|
|
e.experiment_number,
|
|
ep.name,
|
|
COALESCE(
|
|
jsonb_agg(
|
|
jsonb_build_object(
|
|
'repetition_id', er.id,
|
|
'repetition_number', er.repetition_number,
|
|
'status', er.status,
|
|
'scheduled_date', er.scheduled_date,
|
|
'soaking', jsonb_build_object(
|
|
'scheduled_start', soaking_e.scheduled_start_time,
|
|
'actual_start', soaking_e.actual_start_time,
|
|
'duration_minutes', soaking_e.soaking_duration_minutes,
|
|
'scheduled_end', soaking_e.scheduled_end_time,
|
|
'actual_end', soaking_e.actual_end_time,
|
|
'status', soaking_e.status
|
|
),
|
|
'airdrying', jsonb_build_object(
|
|
'scheduled_start', airdrying_e.scheduled_start_time,
|
|
'actual_start', airdrying_e.actual_start_time,
|
|
'duration_minutes', airdrying_e.duration_minutes,
|
|
'scheduled_end', airdrying_e.scheduled_end_time,
|
|
'actual_end', airdrying_e.actual_end_time,
|
|
'status', airdrying_e.status
|
|
),
|
|
'cracking', jsonb_build_object(
|
|
'scheduled_start', cracking_e.scheduled_start_time,
|
|
'actual_start', cracking_e.actual_start_time,
|
|
'scheduled_end', cracking_e.scheduled_end_time,
|
|
'actual_end', cracking_e.actual_end_time,
|
|
'machine_type_id', cracking_e.machine_type_id,
|
|
'machine_type_name', mt.name,
|
|
'status', cracking_e.status
|
|
),
|
|
'shelling', jsonb_build_object(
|
|
'scheduled_start', shelling_e.scheduled_start_time,
|
|
'actual_start', shelling_e.actual_start_time,
|
|
'scheduled_end', shelling_e.scheduled_end_time,
|
|
'actual_end', shelling_e.actual_end_time,
|
|
'status', shelling_e.status
|
|
)
|
|
)
|
|
ORDER BY er.repetition_number
|
|
),
|
|
'[]'::jsonb
|
|
) as repetitions
|
|
FROM public.experiments e
|
|
LEFT JOIN public.experiment_books ep ON e.phase_id = ep.id
|
|
LEFT JOIN public.experiment_repetitions er ON er.experiment_id = e.id
|
|
LEFT JOIN public.experiment_phase_executions soaking_e
|
|
ON soaking_e.repetition_id = er.id AND soaking_e.phase_type = 'soaking'
|
|
LEFT JOIN public.experiment_phase_executions airdrying_e
|
|
ON airdrying_e.repetition_id = er.id AND airdrying_e.phase_type = 'airdrying'
|
|
LEFT JOIN public.experiment_phase_executions cracking_e
|
|
ON cracking_e.repetition_id = er.id AND cracking_e.phase_type = 'cracking'
|
|
LEFT JOIN public.experiment_phase_executions shelling_e
|
|
ON shelling_e.repetition_id = er.id AND shelling_e.phase_type = 'shelling'
|
|
LEFT JOIN public.machine_types mt ON cracking_e.machine_type_id = mt.id
|
|
WHERE e.id = p_experiment_id
|
|
GROUP BY e.id, e.experiment_number, ep.name;
|
|
END;
|
|
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
|
|
|
GRANT SELECT ON public.experiments_with_all_reps_and_phases TO authenticated;
|
|
GRANT EXECUTE ON FUNCTION public.get_experiment_with_reps_and_phases(UUID) TO authenticated;
|