Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions database/migration/20260323_restore_study_delete_cascade.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
-- ============================================================================
-- Migration: Restore Study Delete Cascade
-- Date: March 23, 2026
-- ============================================================================
--
-- OVERVIEW:
-- Restore ON DELETE CASCADE behavior for foreign keys that reference
-- public.study(id). This preserves the pre-20251022 behavior and ensures study
-- cleanup removes dependent rows from repo, study_fitbit_credentials,
-- study_invite, and study_subject.
--
-- ============================================================================

BEGIN;

ALTER TABLE ONLY public.repo
DROP CONSTRAINT IF EXISTS "repo_studyId_fkey",
ADD CONSTRAINT "repo_studyId_fkey"
FOREIGN KEY (study_id) REFERENCES public.study(id) ON DELETE CASCADE;

ALTER TABLE ONLY public.study_fitbit_credentials
DROP CONSTRAINT IF EXISTS "study_fitbit_credentials_studyId_fkey",
ADD CONSTRAINT "study_fitbit_credentials_studyId_fkey"
FOREIGN KEY (study_id) REFERENCES public.study(id) ON DELETE CASCADE;

ALTER TABLE ONLY public.study_invite
DROP CONSTRAINT IF EXISTS "study_invite_studyId_fkey",
ADD CONSTRAINT "study_invite_studyId_fkey"
FOREIGN KEY (study_id) REFERENCES public.study(id) ON DELETE CASCADE;

ALTER TABLE ONLY public.study_subject
DROP CONSTRAINT IF EXISTS "study_subject_studyId_fkey",
ADD CONSTRAINT "study_subject_studyId_fkey"
FOREIGN KEY (study_id) REFERENCES public.study(id) ON DELETE CASCADE;

COMMIT;
8 changes: 4 additions & 4 deletions database/studyu-schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ ALTER TABLE ONLY "public"."subject_progress"


ALTER TABLE ONLY "public"."repo"
ADD CONSTRAINT "repo_studyId_fkey" FOREIGN KEY ("study_id") REFERENCES "public"."study"("id");
ADD CONSTRAINT "repo_studyId_fkey" FOREIGN KEY ("study_id") REFERENCES "public"."study"("id") ON DELETE CASCADE;



Expand All @@ -650,12 +650,12 @@ ALTER TABLE ONLY "public"."repo"


ALTER TABLE ONLY "public"."study_fitbit_credentials"
ADD CONSTRAINT "study_fitbit_credentials_studyId_fkey" FOREIGN KEY ("study_id") REFERENCES "public"."study"("id");
ADD CONSTRAINT "study_fitbit_credentials_studyId_fkey" FOREIGN KEY ("study_id") REFERENCES "public"."study"("id") ON DELETE CASCADE;



ALTER TABLE ONLY "public"."study_invite"
ADD CONSTRAINT "study_invite_studyId_fkey" FOREIGN KEY ("study_id") REFERENCES "public"."study"("id");
ADD CONSTRAINT "study_invite_studyId_fkey" FOREIGN KEY ("study_id") REFERENCES "public"."study"("id") ON DELETE CASCADE;



Expand All @@ -665,7 +665,7 @@ ALTER TABLE ONLY "public"."study_subject"


ALTER TABLE ONLY "public"."study_subject"
ADD CONSTRAINT "study_subject_studyId_fkey" FOREIGN KEY ("study_id") REFERENCES "public"."study"("id");
ADD CONSTRAINT "study_subject_studyId_fkey" FOREIGN KEY ("study_id") REFERENCES "public"."study"("id") ON DELETE CASCADE;



Expand Down
97 changes: 96 additions & 1 deletion supabase/tests/010-study.sql
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ INSERT INTO public.study (
--

-- plan tests in advance, this ensures the proper number of tests have been run.
SELECT plan(17);
SELECT plan(23);

-- UNRESTRICTED TESTS

Expand Down Expand Up @@ -330,6 +330,101 @@ SELECT tests.is_either_true(
FROM
public.study;

-- DELETE CASCADE TESTS

SELECT tests.authenticate_as('test_creator_1');

INSERT INTO public.study (
contact,
title,
description,
icon_name,
status,
registry_published,
questionnaire,
eligibility_criteria,
observations,
interventions,
consent,
schedule,
report_specification,
results,
user_id,
participation,
result_sharing,
collaborator_emails
) VALUES (
'{"email":"cascade@example.com","phone":"0123456789","website":"https://studyu.health","researchers":"StudyU Researcher","organization":"StudyU","institutionalReviewBoard":"N/A","institutionalReviewBoardNumber":"N/A"}',
'Study: delete cascade regression',
'Verifies dependent rows are removed when a study is deleted.',
'accountHeart',
'draft',
false,
'[]',
'[]',
'[]',
'[]',
'[]',
'{"sequence":"alternating","phaseDuration":1,"numberOfCycles":1,"sequenceCustom":"AB","includeBaseline":false}',
'{"primary":{"id":"average","type":"average","title":"Average","aggregate":"day","description":"Average","resultProperty":{"task":"task","property":"value"}},"secondary":[]}',
'[]',
(tests.get_supabase_user('test_creator_1') ->> 'id')::uuid,
'invite',
'private',
'{}'
);

INSERT INTO public.study_invite (code, study_id, preselected_intervention_ids)
VALUES ('cascade-delete-code', (SELECT id FROM public.study WHERE title = 'Study: delete cascade regression'), ARRAY['intervention-a']);

INSERT INTO public.study_subject (study_id, user_id, selected_intervention_ids, invite_code)
VALUES (
(SELECT id FROM public.study WHERE title = 'Study: delete cascade regression'),
(tests.get_supabase_user('test_consumer') ->> 'id')::uuid,
ARRAY['intervention-a'],
'cascade-delete-code'
);

INSERT INTO public.study_fitbit_credentials (study_id, fitbit_credentials)
VALUES (
(SELECT id FROM public.study WHERE title = 'Study: delete cascade regression'),
'{"clientId":"test-client","clientSecret":"test-secret"}'
);

INSERT INTO public.repo (project_id, user_id, study_id, provider)
VALUES (
'cascade-delete-project',
(tests.get_supabase_user('test_creator_1') ->> 'id')::uuid,
(SELECT id FROM public.study WHERE title = 'Study: delete cascade regression'),
'gitlab'
);

SELECT is(count(*)::int, 1, 'Cascade test setup inserts one repo row for the target study')
FROM public.repo
WHERE study_id = (SELECT id FROM public.study WHERE title = 'Study: delete cascade regression');

DELETE FROM public.study
WHERE title = 'Study: delete cascade regression';

SELECT is(count(*)::int, 0, 'Deleting a study cascades to repo')
FROM public.repo
WHERE project_id = 'cascade-delete-project';

SELECT is(count(*)::int, 0, 'Deleting a study cascades to fitbit credentials')
FROM public.study_fitbit_credentials
WHERE fitbit_credentials = '{"clientId":"test-client","clientSecret":"test-secret"}';

SELECT is(count(*)::int, 0, 'Deleting a study cascades to invite codes')
FROM public.study_invite
WHERE code = 'cascade-delete-code';

SELECT is(count(*)::int, 0, 'Deleting a study cascades to study subjects')
FROM public.study_subject
WHERE invite_code = 'cascade-delete-code';

SELECT is(count(*)::int, 4, 'Deleting the cascade test study does not remove unrelated visible studies')
FROM public.study;

-- check the results of your test
select * from finish();

Expand Down
Loading