Skip to content

Commit

Permalink
[Issue #2491] Modify the Agency table schema to include a link to a t…
Browse files Browse the repository at this point in the history
…op-level agency (#2517)

Summary
Fixes #2491

Time to review: 15 mins

Changes proposed
New schema fields
DB Migration
In the opportunity table, add a new property called
top_level_agency_name that pulls from agency record relationship it
already has to get the top-level agency name. Something like:

Context for reviewers
We want to add a foreign key in the agency table to the (same) agency
table called top_level_agency_id as well as a corresponding
relationship.

This field will be populated by a separate process and used in setting
up the agency name in the API

Additional information

After seed is complete:
https://github.com/user-attachments/assets/a861d717-06ba-4731-a88f-679945ba0ae7
  • Loading branch information
mikehgrantsgov authored Oct 18, 2024
1 parent 1fa4cef commit 26eeecf
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Add top level agency field
Revision ID: 39f7f941fc6c
Revises: 558ad9563e9a
Create Date: 2024-10-17 20:08:55.193636
"""

import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "39f7f941fc6c"
down_revision = "558ad9563e9a"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column(
"agency", sa.Column("top_level_agency_id", sa.BigInteger(), nullable=True), schema="api"
)
op.create_foreign_key(
op.f("agency_top_level_agency_id_agency_fkey"),
"agency",
"agency",
["top_level_agency_id"],
["agency_id"],
source_schema="api",
referent_schema="api",
)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(
op.f("agency_top_level_agency_id_agency_fkey"), "agency", schema="api", type_="foreignkey"
)
op.drop_column("agency", "top_level_agency_id", schema="api")
# ### end Alembic commands ###
10 changes: 10 additions & 0 deletions api/src/db/models/agency_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ class Agency(ApiSchemaTable, TimestampMixin):
creator=lambda obj: LinkAgencyDownloadFileType(agency_download_file_type=obj),
)

top_level_agency_id: Mapped[int | None] = mapped_column(
BigInteger,
ForeignKey(agency_id),
nullable=True,
)
top_level_agency: Mapped["Agency"] = relationship(
lambda: Agency,
remote_side=[agency_id],
)


class LinkAgencyDownloadFileType(ApiSchemaTable, TimestampMixin):
__tablename__ = "link_agency_download_file_type"
Expand Down
7 changes: 7 additions & 0 deletions api/src/db/models/opportunity_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ class Opportunity(ApiSchemaTable, TimestampMixin):
Agency, primaryjoin="Opportunity.agency == foreign(Agency.agency_code)", uselist=False
)

@property
def top_level_agency_name(self) -> str | None:
if self.agency_record is not None and self.agency_record.top_level_agency is not None:
return self.agency_record.top_level_agency.agency_name

return None

@property
def agency_name(self) -> str | None:
# Fetch the agency name from the agency table record (if one was found)
Expand Down
5 changes: 5 additions & 0 deletions api/tests/lib/seed_local_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,20 +120,25 @@ def _build_opportunities(db_session: db.Session, iterations: int, include_histor
# we can consider shoving this into a CSV that we load instead.
AGENCIES_TO_CREATE = [
{
"agency_id": 1,
"agency_code": "USAID",
"agency_name": "Agency for International Development",
},
{
"agency_id": 2,
"agency_code": "ARPAH",
"agency_name": "Advanced Research Projects Agency for Health",
},
{
"agency_id": 3,
"agency_code": "DOC",
"agency_name": "Agency for International Development",
},
{
"agency_id": 4,
"agency_code": "DOC-EDA",
"agency_name": "Agency for International Development",
"top_level_agency_id": 3, # DOC
},
]

Expand Down
3 changes: 1 addition & 2 deletions api/tests/src/db/models/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,6 @@ class OpportunityAttachmentFactory(BaseFactory):
class Meta:
model = opportunity_models.OpportunityAttachment

attachment_id = factory.Sequence(lambda n: n)

file_location = factory.Faker("url")
mime_type = factory.Faker("mime_type")
file_name = factory.Faker("file_name")
Expand Down Expand Up @@ -721,6 +719,7 @@ class Meta:
is_image_workspace_enabled = factory.Faker("boolean")
is_validation_workspace_enabled = factory.Faker("boolean")

top_level_agency_id = None
agency_download_file_types = factory.Faker(
"random_elements",
length=random.randint(1, 2),
Expand Down
Binary file modified documentation/api/database/erds/api-schema.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 26eeecf

Please sign in to comment.