-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Issue #3874] Create Rough Tables for Opportunity Applicate package #3906
base: main
Are you sure you want to change the base?
Conversation
… 3875/opp-package-app-tables
@@ -451,3 +457,80 @@ class OpportunityChangeAudit(ApiSchemaTable, TimestampMixin): | |||
BigInteger, ForeignKey(Opportunity.opportunity_id), primary_key=True, index=True | |||
) | |||
opportunity: Mapped[Opportunity] = relationship(Opportunity) | |||
|
|||
|
|||
class OpportunityCompetition(ApiSchemaTable, TimestampMixin): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we put these in a competition_models.py
file - just want to avoid the opportunity file getting really long, and there are going to be a lot of additional tables we need for this. We can also name the tables without prefixing with Opportunity
- they're all sorta a part of it, but separate enough
opportunity_competition: Mapped[list["OpportunityCompetition"]] = relationship( | ||
back_populates="opportunity", uselist=True, cascade="all, delete-orphan" | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI - if you move these models to another file, you might hit an issue with this having a circular import. You can work around that by adding the import to the if TYPE_CHECKING
line towards the top of this file: https://github.com/HHS/simpler-grants-gov/blob/main/api/src/db/models/opportunity_models.py#L26
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
__tablename__ = "opportunity_competition_assistance_listing" | ||
|
||
competition_id: Mapped[uuid.UUID] = mapped_column( | ||
UUID, ForeignKey(OpportunityCompetition.competition_id), index=True, primary_key=True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to index if it's the primary key - I might have something like that on some of our many-to-many tables, but that was a holdover from me testing some performance ideas a while back (I don't think they ever worked?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, makes sense. Removed
api/tests/src/db/models/factories.py
Outdated
opportunity = factory.SubFactory(OpportunityFactory) | ||
opportunity_id = factory.LazyAttribute(lambda o: o.opportunity.opportunity_id) | ||
|
||
competition_id = Generators.UuidObj |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we put the primary key at the top of the factories? I generally just keep everything in the same order as the class itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to top
api/tests/src/db/models/factories.py
Outdated
legacy_competition_id = sometimes_none(factory.Faker("random_int", min=1, max=15)) | ||
public_competition_id = sometimes_none(factory.Faker("random_int", min=1, max=15)) | ||
legacy_package_id = sometimes_none(factory.Faker("random_int", min=1, max=15)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For these, my recommendation:
- don't set legacy_competition_id -> it's a pointer back to the old system, only our transform logic will ever care about it / want it set.
- public_competition_id -> It's actually a string with some variance in how it can be set, I'd just put something like
ABC<number>
to make it look sorta like the old system (keep the sometimes_none) - legacy_package_id - This looks to be formatted as
PKG<number>
, probably just do that as well? (keep the sometimes_none).
api/tests/src/db/models/factories.py
Outdated
) | ||
|
||
grace_period = factory.Faker("random_int", min=1, max=10) | ||
contact_info = sometimes_none(factory.Faker("sentence")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I setup a contact info faker provider previously, could use agency_contact_description
for this to get it to roughly look like contact info
api/tests/src/db/models/factories.py
Outdated
form_id = Generators.UuidObj | ||
form_name = factory.Faker("sentence") | ||
form_version = factory.Faker("sentence") | ||
is_active = False | ||
description = factory.Faker("sentence") | ||
agency_code_id = factory.Faker("sentence") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some suggestions:
form_name
->bs
might be a good one: https://faker.readthedocs.io/en/master/providers/faker.providers.company.html#faker.providers.company.Provider.bsform_version
-> I'd probably say we should make this formatted like1.<random int>
- could randomize both, don't think it matters muchis_active
-> default to true, if it's inactive, we'll probably disallow the form for use in certain waysagency_code_id
-> Just reuse theagency_code
faker provider we made
form_version: Mapped[str] | ||
is_active: Mapped[bool] | ||
description: Mapped[str] | ||
agency_code_id: Mapped[str] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On second thought, let's just name this agency_code
like we have on the opportunity
form_name: Mapped[str] | ||
form_version: Mapped[str] | ||
is_active: Mapped[bool] | ||
description: Mapped[str] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yknow what, on second thought, I don't even know what this description refers to, let's drop this column. It's not on the form UI, so let's hold off on it for now
…simpler-grants-gov into 3875/opp-package-app-tables
…simpler-grants-gov into 3875/opp-package-app-tables
… 3875/opp-package-app-tables
…simpler-grants-gov into 3875/opp-package-app-tables
sa.Column("form_id", sa.UUID(), nullable=False), | ||
sa.Column("form_name", sa.Text(), nullable=False), | ||
sa.Column("form_version", sa.Text(), nullable=False), | ||
sa.Column("is_active", sa.Boolean(), nullable=False), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should think through the lifecycle a bit more than just currently active or inactive. Do we need to have a "available after"/"available until" kind of dates when a form is "depreciated" or "retired?" For example what if SF-424 v4 is live now and v5 gets approved and added to the system. Do all applications switch immediately? Do new application packages only show v5 when selecting what forms to add? Is there a period where both remain pick-able when setting up an application package? Even if we just have active, I think it'd be good to have this be a date/time and have it be called like inactive_at and that date then controls if it's shown and also provides more of a history of when it became inactivated, can be set for a future date, etc.
If we want to move this forward in the short term, maybe just make this a timestamp instead of boolean and re-name it accordingly and then we can always add an "active_at" column in the future if we need more specifics of a lifecycle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mdragon These were initially considered basic columns, with the plan to add more as needed. I believe it's a good idea to include both inactive_at
and active_at
columns, as it's generally better for each column to serve a single purpose rather than combining logic. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that makes sense for now and then yes, we absolutely shouldn't try to make perfect tables out of the gate and anticipate revisions and improvements as we work with the tables and learn more about the functionality. 👍🏻
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added inactive_at
-nullable and active_at
-non-nullable datetime
columns and updated factory
Summary
Fixes #{3874}
Time to review: 15 mins
Rough Tables Created
opportunity_application_form
opportunity_competition_form
opportunity_competition
opportunity_competition_assistance_listing
opportunity_competition_instruction
Factories created