Skip to content

Commit

Permalink
[Issue #3291] Create database tables for saved opportunities (#3325)
Browse files Browse the repository at this point in the history
## Summary
Fixes #3291

### Time to review: 5 mins

## Changes proposed
Add a `user_saved_opportunity` table with columns as described in the
ticket.

## Context for reviewers
Needed for follow-on work with saved opportunity API tickets.
  • Loading branch information
mikehgrantsgov authored Dec 20, 2024
1 parent 9ce8c00 commit 2188831
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""Create user saved opportunity table
Revision ID: 232a9223ed9b
Revises: 6a23520d2c3c
Create Date: 2024-12-19 22:41:02.487364
"""

import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "232a9223ed9b"
down_revision = "f8058a6c0a66"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"user_saved_opportunity",
sa.Column("user_id", sa.UUID(), nullable=False),
sa.Column("opportunity_id", sa.BigInteger(), nullable=False),
sa.Column(
"created_at",
sa.TIMESTAMP(timezone=True),
server_default=sa.text("now()"),
nullable=False,
),
sa.Column(
"updated_at",
sa.TIMESTAMP(timezone=True),
server_default=sa.text("now()"),
nullable=False,
),
sa.ForeignKeyConstraint(
["user_id"], ["api.user.user_id"], name=op.f("user_saved_opportunity_user_id_user_fkey")
),
sa.ForeignKeyConstraint(
["opportunity_id"],
["api.opportunity.opportunity_id"],
name=op.f("user_saved_opportunity_opportunity_id_opportunity_fkey"),
),
sa.PrimaryKeyConstraint(
"user_id", "opportunity_id", name=op.f("user_saved_opportunity_pkey")
),
schema="api",
)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table("user_saved_opportunity", schema="api")
# ### end Alembic commands ###
11 changes: 11 additions & 0 deletions api/src/db/models/opportunity_models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import date
from typing import TYPE_CHECKING

from sqlalchemy import BigInteger, ForeignKey, UniqueConstraint
from sqlalchemy.ext.associationproxy import AssociationProxy, association_proxy
Expand All @@ -24,6 +25,9 @@
LkOpportunityStatus,
)

if TYPE_CHECKING:
from src.db.models.user_models import UserSavedOpportunity


class Opportunity(ApiSchemaTable, TimestampMixin):
__tablename__ = "opportunity"
Expand Down Expand Up @@ -77,6 +81,13 @@ def agency(self) -> str | None:
back_populates="opportunity", uselist=True, cascade="all, delete-orphan"
)

saved_opportunities_by_users: Mapped[list["UserSavedOpportunity"]] = relationship(
"UserSavedOpportunity",
back_populates="opportunity",
uselist=True,
cascade="all, delete-orphan",
)

agency_record: Mapped[Agency | None] = relationship(
Agency,
primaryjoin="Opportunity.agency_code == foreign(Agency.agency_code)",
Expand Down
24 changes: 23 additions & 1 deletion api/src/db/models/user_models.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
import uuid
from datetime import datetime

from sqlalchemy import ForeignKey
from sqlalchemy import BigInteger, ForeignKey
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship

from src.adapters.db.type_decorators.postgres_type_decorators import LookupColumn
from src.constants.lookup_constants import ExternalUserType
from src.db.models.base import ApiSchemaTable, TimestampMixin
from src.db.models.lookup_models import LkExternalUserType
from src.db.models.opportunity_models import Opportunity


class User(ApiSchemaTable, TimestampMixin):
__tablename__ = "user"

user_id: Mapped[uuid.UUID] = mapped_column(UUID, primary_key=True, default=uuid.uuid4)

saved_opportunities: Mapped[list["UserSavedOpportunity"]] = relationship(
"UserSavedOpportunity",
back_populates="user",
uselist=True,
cascade="all, delete-orphan",
)


class LinkExternalUser(ApiSchemaTable, TimestampMixin):
__tablename__ = "link_external_user"
Expand Down Expand Up @@ -60,3 +68,17 @@ class LoginGovState(ApiSchemaTable, TimestampMixin):

# https://openid.net/specs/openid-connect-core-1_0.html#NonceNotes
nonce: Mapped[uuid.UUID]


class UserSavedOpportunity(ApiSchemaTable, TimestampMixin):
__tablename__ = "user_saved_opportunity"

user_id: Mapped[uuid.UUID] = mapped_column(ForeignKey(User.user_id), primary_key=True)
opportunity_id: Mapped[int] = mapped_column(
BigInteger, ForeignKey(Opportunity.opportunity_id), primary_key=True
)

user: Mapped[User] = relationship(User, back_populates="saved_opportunities")
opportunity: Mapped[Opportunity] = relationship(
"Opportunity", back_populates="saved_opportunities_by_users"
)
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 2188831

Please sign in to comment.