From fbd953748c45a21fc400b23cd658fa3f85667081 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 17:21:54 -0400 Subject: [PATCH 01/13] Create Prerequisite tables and enum Co-Authored-By: Nick Wang <122407085+NickWang8@users.noreply.github.com> --- carpi_data_model/models.py | 50 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/carpi_data_model/models.py b/carpi_data_model/models.py index 6eefe8c..ffa20ff 100644 --- a/carpi_data_model/models.py +++ b/carpi_data_model/models.py @@ -37,6 +37,11 @@ class SemesterEnum(str, PyEnum): SUMMER = "SUMMER" +class PrerequisiteNestingTypeEnum(str, PyEnum): + AND = "AND" + OR = "OR" + + RELATIONSHIP_TYPE_ENUM = SQLEnum( RelationshipTypeEnum, name="relationship_type", native_enum=True ) @@ -47,6 +52,11 @@ class SemesterEnum(str, PyEnum): RestrictionTypeEnum, name="restriction_type", native_enum=True ) SEMESTER_ENUM = SQLEnum(SemesterEnum, name="semester", native_enum=True) +PREREQUISITE_NESTING_TYPE_ENUM = SQLEnum( + PrerequisiteNestingTypeEnum, + name="prerequisite_nesting_type", + native_enum=True, +) class Subject(Base): @@ -194,3 +204,43 @@ class Course_Faculty(Base): ], ), ) + + +class Prerequisite_Nesting(Base): + __tablename__ = "prerequisite_nesting" + + og_subj_code: Mapped[str] = mapped_column(VARCHAR(4), primary_key=True) + og_code_num: Mapped[str] = mapped_column(VARCHAR(4), primary_key=True) + id: Mapped[int] = mapped_column(SMALLINT, primary_key=True) + relationship: Mapped[PrerequisiteNestingTypeEnum] = mapped_column( + PREREQUISITE_NESTING_TYPE_ENUM, + nullable=True, + ) + parent_id: Mapped[int] = mapped_column(SMALLINT, nullable=True) + + __table_args__ = ( + ForeignKeyConstraint( + ["og_subj_code", "og_code_num"], + ["course.subj_code", "course.code_num"], + ), + ) + + +class Prerequisite_Course(Base): + __tablename__ = "prerequisite_course" + + og_subj_code: Mapped[str] = mapped_column(VARCHAR(4), primary_key=True) + og_code_num: Mapped[str] = mapped_column(VARCHAR(4), primary_key=True) + parent_id: Mapped[int] = mapped_column(SMALLINT, primary_key=True) + new_subj_code: Mapped[str] = mapped_column(VARCHAR(4), primary_key=True) + new_code_num: Mapped[int] = mapped_column(SMALLINT, primary_key=True) + + __table_args__ = ( + ForeignKeyConstraint( + ["og_subj_code", "og_code_num"], ["course.subj_code", "course.code_num"] + ), + ForeignKeyConstraint(["parent_id"], ["prerequisite_nesting.id"]), + ForeignKeyConstraint( + ["new_subj_code, new_code_num"], ["course.subj_code", "course.code_num"] + ), + ) From fb780ac5b86c3a4a86bfe223d3d272cd8638f9c2 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 17:30:11 -0400 Subject: [PATCH 02/13] Fix misplaced comma in foreign key constraint --- carpi_data_model/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/carpi_data_model/models.py b/carpi_data_model/models.py index ffa20ff..e6ea8f8 100644 --- a/carpi_data_model/models.py +++ b/carpi_data_model/models.py @@ -241,6 +241,6 @@ class Prerequisite_Course(Base): ), ForeignKeyConstraint(["parent_id"], ["prerequisite_nesting.id"]), ForeignKeyConstraint( - ["new_subj_code, new_code_num"], ["course.subj_code", "course.code_num"] + ["new_subj_code", "new_code_num"], ["course.subj_code", "course.code_num"] ), ) From 1dda93c86e612fdf6a8e8405c4802fce3a845ce8 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 17:30:49 -0400 Subject: [PATCH 03/13] Align new_code_num data type with foreign key --- carpi_data_model/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/carpi_data_model/models.py b/carpi_data_model/models.py index e6ea8f8..d3dd16a 100644 --- a/carpi_data_model/models.py +++ b/carpi_data_model/models.py @@ -233,7 +233,7 @@ class Prerequisite_Course(Base): og_code_num: Mapped[str] = mapped_column(VARCHAR(4), primary_key=True) parent_id: Mapped[int] = mapped_column(SMALLINT, primary_key=True) new_subj_code: Mapped[str] = mapped_column(VARCHAR(4), primary_key=True) - new_code_num: Mapped[int] = mapped_column(SMALLINT, primary_key=True) + new_code_num: Mapped[int] = mapped_column(VARCHAR(4), primary_key=True) __table_args__ = ( ForeignKeyConstraint( From a13630cb4e3fb96d4274a5e29c4bdefaac7a7c4e Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 17:32:33 -0400 Subject: [PATCH 04/13] Consolidate prerequisite course foreign key constraint Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- carpi_data_model/models.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/carpi_data_model/models.py b/carpi_data_model/models.py index d3dd16a..2af7ddb 100644 --- a/carpi_data_model/models.py +++ b/carpi_data_model/models.py @@ -239,7 +239,14 @@ class Prerequisite_Course(Base): ForeignKeyConstraint( ["og_subj_code", "og_code_num"], ["course.subj_code", "course.code_num"] ), - ForeignKeyConstraint(["parent_id"], ["prerequisite_nesting.id"]), + ForeignKeyConstraint( + ["og_subj_code", "og_code_num", "parent_id"], + [ + "prerequisite_nesting.og_subj_code", + "prerequisite_nesting.og_code_num", + "prerequisite_nesting.id", + ], + ), ForeignKeyConstraint( ["new_subj_code", "new_code_num"], ["course.subj_code", "course.code_num"] ), From 2350a41fa30cb0fab213fda0d4d57959ef168a5d Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 17:33:08 -0400 Subject: [PATCH 05/13] Add self-referencing FK constraint in prerequisite nesting Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- carpi_data_model/models.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/carpi_data_model/models.py b/carpi_data_model/models.py index 2af7ddb..faf488a 100644 --- a/carpi_data_model/models.py +++ b/carpi_data_model/models.py @@ -223,6 +223,14 @@ class Prerequisite_Nesting(Base): ["og_subj_code", "og_code_num"], ["course.subj_code", "course.code_num"], ), + ForeignKeyConstraint( + ["og_subj_code", "og_code_num", "parent_id"], + [ + "prerequisite_nesting.og_subj_code", + "prerequisite_nesting.og_code_num", + "prerequisite_nesting.id", + ], + ), ) From 88fb0839ad2e86d287c5b389924fa4291fcd2d75 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 17:37:01 -0400 Subject: [PATCH 06/13] Remove redundant FK constraint from prerequisite course This constraint is fulfilled transiently by the Prerequisite_Nesting class --- carpi_data_model/models.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/carpi_data_model/models.py b/carpi_data_model/models.py index faf488a..073ebf6 100644 --- a/carpi_data_model/models.py +++ b/carpi_data_model/models.py @@ -244,9 +244,6 @@ class Prerequisite_Course(Base): new_code_num: Mapped[int] = mapped_column(VARCHAR(4), primary_key=True) __table_args__ = ( - ForeignKeyConstraint( - ["og_subj_code", "og_code_num"], ["course.subj_code", "course.code_num"] - ), ForeignKeyConstraint( ["og_subj_code", "og_code_num", "parent_id"], [ From 228f4751e22ff9dc470b924d9e05893f34195ff0 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 17:43:10 -0400 Subject: [PATCH 07/13] Add Nick Wang to package contributors --- pyproject.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index cbc5619..1470172 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,11 @@ name = "carpi-data-model" version = "1.0" dependencies = ["SQLAlchemy>=2.0.0"] requires-python = ">=3.7" -authors = [{ name = "Raymond Chen" }, { name = "Jack Zgombic" }] +authors = [ + { name = "Raymond Chen" }, + { name = "Jack Zgombic" }, + { name = "Nick Wang" }, +] maintainers = [{ name = "Raymond Chen" }] description = "The MySQL database schema used in Project CARPI." readme = "README.md" From 3f77562cdbc25faa9ffd5602c6cd0679e14464be Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 17:43:26 -0400 Subject: [PATCH 08/13] Remove keywords from pyproject.toml Not sure why we kept these in. --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1470172..01abc61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,6 @@ description = "The MySQL database schema used in Project CARPI." readme = "README.md" license = "MIT" license-files = ["LICENSE"] -keywords = ["egg", "bacon", "sausage", "tomatoes", "Lobster Thermidor"] classifiers = [ "Programming Language :: Python :: 3", "Operating System :: OS Independent", From 900eb283f6c13493fb30774db6c2631592196a47 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 17:53:30 -0400 Subject: [PATCH 09/13] Update requirements.txt --- requirements.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/requirements.txt b/requirements.txt index 27f8f50..95dde6d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,8 @@ +-e git+https://github.com/Project-CARPI/database-schema.git#egg=carpi_data_model +iniconfig==2.3.0 +packaging==26.0 +pluggy==1.6.0 +Pygments==2.20.0 +pytest==9.0.3 SQLAlchemy==2.0.44 typing_extensions==4.15.0 From c87ea9d08ad0105ad89f3415b117b72e728c3a95 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Tue, 7 Apr 2026 17:57:26 -0400 Subject: [PATCH 10/13] Revert "Update requirements.txt" This reverts commit 900eb283f6c13493fb30774db6c2631592196a47. --- requirements.txt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/requirements.txt b/requirements.txt index 95dde6d..27f8f50 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,2 @@ --e git+https://github.com/Project-CARPI/database-schema.git#egg=carpi_data_model -iniconfig==2.3.0 -packaging==26.0 -pluggy==1.6.0 -Pygments==2.20.0 -pytest==9.0.3 SQLAlchemy==2.0.44 typing_extensions==4.15.0 From 2c8e75241c9a62a45312d3140c93bb3f758a0559 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Thu, 9 Apr 2026 13:53:55 -0400 Subject: [PATCH 11/13] Add prerequisite tables to tests Also includes a small change in which the list of table names in test_create_tables is converted to a set for more efficient asserts. --- tests/test_models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_models.py b/tests/test_models.py index d3a4b68..abae33f 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -13,6 +13,8 @@ Course_Relationship, Course_Restriction, Faculty, + Prerequisite_Course, + Prerequisite_Nesting, Restriction, Subject, ) @@ -50,7 +52,7 @@ def test_create_tables(engine): errors. Ensures the tables actually exist in the database catalog. """ inspector = inspect(engine) - existing_tables = inspector.get_table_names() + existing_tables = set(inspector.get_table_names()) assert Subject.__tablename__ in existing_tables assert Attribute.__tablename__ in existing_tables @@ -62,6 +64,8 @@ def test_create_tables(engine): assert Course_Restriction.__tablename__ in existing_tables assert Course_Offering.__tablename__ in existing_tables assert Course_Faculty.__tablename__ in existing_tables + assert Prerequisite_Nesting.__tablename__ in existing_tables + assert Prerequisite_Course.__tablename__ in existing_tables def test_insert_and_query(engine): From a9a1f194957872d2815f05d8586294e6f6222aed Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Thu, 9 Apr 2026 13:58:56 -0400 Subject: [PATCH 12/13] Fix type mismatch in prerequisite course table --- carpi_data_model/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/carpi_data_model/models.py b/carpi_data_model/models.py index 073ebf6..58d22aa 100644 --- a/carpi_data_model/models.py +++ b/carpi_data_model/models.py @@ -241,7 +241,7 @@ class Prerequisite_Course(Base): og_code_num: Mapped[str] = mapped_column(VARCHAR(4), primary_key=True) parent_id: Mapped[int] = mapped_column(SMALLINT, primary_key=True) new_subj_code: Mapped[str] = mapped_column(VARCHAR(4), primary_key=True) - new_code_num: Mapped[int] = mapped_column(VARCHAR(4), primary_key=True) + new_code_num: Mapped[str] = mapped_column(VARCHAR(4), primary_key=True) __table_args__ = ( ForeignKeyConstraint( From eeafc48a8c9ad686f9087a0ec69bef01565fa487 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+ramonechen@users.noreply.github.com> Date: Thu, 9 Apr 2026 14:00:50 -0400 Subject: [PATCH 13/13] Add optional None annotations to nullable fields --- carpi_data_model/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/carpi_data_model/models.py b/carpi_data_model/models.py index 58d22aa..1411171 100644 --- a/carpi_data_model/models.py +++ b/carpi_data_model/models.py @@ -212,11 +212,11 @@ class Prerequisite_Nesting(Base): og_subj_code: Mapped[str] = mapped_column(VARCHAR(4), primary_key=True) og_code_num: Mapped[str] = mapped_column(VARCHAR(4), primary_key=True) id: Mapped[int] = mapped_column(SMALLINT, primary_key=True) - relationship: Mapped[PrerequisiteNestingTypeEnum] = mapped_column( + relationship: Mapped[PrerequisiteNestingTypeEnum | None] = mapped_column( PREREQUISITE_NESTING_TYPE_ENUM, nullable=True, ) - parent_id: Mapped[int] = mapped_column(SMALLINT, nullable=True) + parent_id: Mapped[int | None] = mapped_column(SMALLINT, nullable=True) __table_args__ = ( ForeignKeyConstraint(