Model that maps to the projects table
| 609 | |
| 610 | |
| 611 | class ProjectModel(BaseProjectModel, BaseModel): |
| 612 | """Model that maps to the projects table""" |
| 613 | |
| 614 | __tablename__ = "projects" |
| 615 | __table_args__ = {"schema": "public"} |
| 616 | |
| 617 | is_sparse = False |
| 618 | id = model.Column(model.UUID, primary_key=True, default=uuid.uuid4) |
| 619 | org_id = model.Column(model.UUID, model.ForeignKey("public.orgs.id"), nullable=False) |
| 620 | api_key = model.Column(model.UUID, unique=True, default=uuid.uuid4) |
| 621 | name = model.Column(model.String, nullable=False) |
| 622 | environment = model.Column(model.Enum(Environment), default=Environment.development, nullable=False) |
| 623 | |
| 624 | org = orm.relationship("OrgModel", back_populates="projects") |
| 625 | |
| 626 | @property |
| 627 | @require_loaded('org') |
| 628 | def is_freeplan(self) -> bool: |
| 629 | """Check if the organization is on a pro plan.""" |
| 630 | return self.org.is_freeplan |
| 631 | |
| 632 | def get_project(self, orm: orm.Session) -> Optional["ProjectModel"]: |
| 633 | """For ProjectModel, return self since it's already the full model.""" |
| 634 | return self |
| 635 | |
| 636 | @classmethod |
| 637 | def get_by_id(cls, orm: orm.Session, project_id: str | UUID) -> Optional['ProjectModel']: |
| 638 | """Get a project by ID with org and necessary relationships preloaded.""" |
| 639 | # This loads org.users, org.invites, and org.projects relationships which are |
| 640 | # needed when returning a `ProjectResponse` in these view functions: |
| 641 | # - get_project |
| 642 | # - create_project |
| 643 | # - update_project |
| 644 | # - regenerate_api_key |
| 645 | # TODO: Consider optimizing with count queries instead of loading full relationships |
| 646 | # when we only need counts for org.current_member_count and org.current_project_count. |
| 647 | return ( |
| 648 | orm.query(cls) |
| 649 | .filter(cls.id == normalize_uuid(project_id)) |
| 650 | .options( |
| 651 | joinedload(cls.org).joinedload(OrgModel.users), |
| 652 | joinedload(cls.org).joinedload(OrgModel.invites), |
| 653 | joinedload(cls.org).joinedload(OrgModel.projects), |
| 654 | ) |
| 655 | .first() |
| 656 | ) |
| 657 | |
| 658 | @classmethod |
| 659 | def get_by_api_key(cls, orm: orm.Session, api_key: str | UUID) -> Optional['ProjectModel']: |
| 660 | """Get a project by API key with org and necessary relationships preloaded.""" |
| 661 | return ( |
| 662 | orm.query(cls) |
| 663 | .filter(cls.api_key == normalize_uuid(api_key)) |
| 664 | .options( |
| 665 | joinedload(cls.org).joinedload(OrgModel.users), |
| 666 | joinedload(cls.org).joinedload(OrgModel.invites), |
| 667 | joinedload(cls.org).joinedload(OrgModel.projects), |
| 668 | ) |
no outgoing calls
searching dependent graphs…