From fbba4d6d436737a731f6aefdabe84186a97ad8e1 Mon Sep 17 00:00:00 2001 From: minhtrannhat Date: Sun, 10 Mar 2024 14:43:51 -0400 Subject: [PATCH] fix(api): ON DELETE CASCADE for todos - Delete todos when the user associated with it are deleted - Updated tests to reflect new changes --- backend/src/neo_neo_todo/migrations/0.py | 2 +- .../src/neo_neo_todo/migrations/test_data.py | 28 ++++++++++++++++++- backend/src/neo_neo_todo/models/member.py | 24 ++++++++++++++++ backend/tests/test_model_member.py | 13 ++++++++- 4 files changed, 64 insertions(+), 3 deletions(-) diff --git a/backend/src/neo_neo_todo/migrations/0.py b/backend/src/neo_neo_todo/migrations/0.py index 141adca..a8d3188 100644 --- a/backend/src/neo_neo_todo/migrations/0.py +++ b/backend/src/neo_neo_todo/migrations/0.py @@ -56,7 +56,7 @@ def migrate() -> None: id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, complete BOOLEAN NOT NULL DEFAULT FALSE, due TIMESTAMPTZ, - member_id INT NOT NULL REFERENCES members(id), + member_id INT NOT NULL REFERENCES members(id) ON DELETE CASCADE, task TEXT NOT NULL )""" ) diff --git a/backend/src/neo_neo_todo/migrations/test_data.py b/backend/src/neo_neo_todo/migrations/test_data.py index 695999d..d9a0ba5 100644 --- a/backend/src/neo_neo_todo/migrations/test_data.py +++ b/backend/src/neo_neo_todo/migrations/test_data.py @@ -29,7 +29,6 @@ def generate_test_data() -> None: dbname=dbname, user=user_name, password=password, host=host, port=port ) as conn: with conn.cursor() as cur: - # create the members table cur.execute( sql.SQL( """ @@ -40,6 +39,16 @@ def generate_test_data() -> None: ) ) + cur.execute( + sql.SQL( + """ + INSERT INTO members (email, password_hash) + VALUES ('member1@todo.test', + '$2b$14$6yXjNza30kPCg3LhzZJfqeCWOLM.zyTiQFD4rdWlFHBTfYzzKJMJe') + """ + ) + ) + cur.execute( sql.SQL( """ @@ -67,6 +76,23 @@ def generate_test_data() -> None: ) ) + cur.execute( + sql.SQL( + """ + INSERT INTO todos (member_id, task) + VALUES (2, 'Test Task 4') + """ + ) + ) + + cur.execute( + sql.SQL( + """ + INSERT INTO todos (member_id, task) + VALUES (2, 'Test Task 5') + """ + ) + ) # Commit the changes conn.commit() diff --git a/backend/src/neo_neo_todo/models/member.py b/backend/src/neo_neo_todo/models/member.py index 8f787f7..03d4520 100644 --- a/backend/src/neo_neo_todo/models/member.py +++ b/backend/src/neo_neo_todo/models/member.py @@ -137,3 +137,27 @@ async def update_member_email_verified(db: AsyncConnectionPool, id: int) -> bool ) return curr.rowcount > 0 + + +async def delete_member(db: AsyncConnectionPool, id: int) -> bool: + """ + Remove a member from the database + Member's todos will also be deleted due to 'ON DELETE CASCADE' constraint + + Return True if deletion was successful or False if not + """ + + async with db.connection() as conn: + async with conn.cursor(row_factory=class_row(Member)) as curr: + query = sql.SQL( + """ + DELETE FROM members + WHERE id = (%s) + """ + ) + await curr.execute( + query, + (id,), + ) + + return curr.rowcount > 0 diff --git a/backend/tests/test_model_member.py b/backend/tests/test_model_member.py index d9f1c7e..ff3fe3e 100644 --- a/backend/tests/test_model_member.py +++ b/backend/tests/test_model_member.py @@ -2,6 +2,7 @@ import pytest from psycopg.errors import UniqueViolation from src.neo_neo_todo.models.member import ( + delete_member, insert_member, select_member_by_email, select_member_by_id, @@ -27,7 +28,7 @@ async def test_model_member_insert(db_pool): db_pool, "member_inserted@todo.test", "alkasdjfhasldkfjh12341238989" ) assert member is not None - assert member.id == 2 + assert member.id == 3 assert member.email == "member_inserted@todo.test" assert member.password_hash == "alkasdjfhasldkfjh12341238989" @@ -63,3 +64,13 @@ async def test_model_member_email_verified(db_pool): ) assert update_member_email_verified_fail is False + + +async def test_model_member_delete_member(db_pool): + deletion_success = await delete_member(db_pool, id=2) + + assert deletion_success + + deletion_fail = await delete_member(db_pool, id=99) + + assert not deletion_fail