Coverage for app / backend / src / couchers / models / public_trips.py: 100%
25 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-26 17:16 +0000
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-26 17:16 +0000
1import enum
2from datetime import date, datetime
3from typing import TYPE_CHECKING
5from sqlalchemy import BigInteger, Boolean, CheckConstraint, Date, DateTime, Enum, ForeignKey, Index, String, func
6from sqlalchemy.orm import Mapped, mapped_column, relationship
7from sqlalchemy.sql import expression
9from couchers.models.base import Base
11if TYPE_CHECKING:
12 from couchers.models import Node, User
13 from couchers.models.host_requests import HostRequest
16class PublicTripStatus(enum.Enum):
17 searching_for_host = enum.auto()
18 closed = enum.auto()
21class PublicTrip(Base, kw_only=True):
22 """
23 A public trip posted by a traveler looking for a host in a community.
24 """
26 __tablename__ = "public_trips"
28 id: Mapped[int] = mapped_column(BigInteger, primary_key=True, init=False)
30 # The traveler posting the trip
31 user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), index=True)
33 # The community/location (city-level node)
34 node_id: Mapped[int] = mapped_column(ForeignKey("nodes.id"), index=True)
36 # Trip dates
37 from_date: Mapped[date] = mapped_column(Date)
38 to_date: Mapped[date] = mapped_column(Date)
40 # User's message about their trip
41 description: Mapped[str] = mapped_column(String)
43 # Current status
44 status: Mapped[PublicTripStatus] = mapped_column(
45 Enum(PublicTripStatus), default=PublicTripStatus.searching_for_host
46 )
48 # If true, only users with the same gender as the poster can see this trip
49 same_gender_only: Mapped[bool] = mapped_column(Boolean, default=False, server_default=expression.false())
51 # Timestamps
52 created: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), init=False)
54 # Relationships
55 user: Mapped[User] = relationship(init=False, back_populates="public_trips")
56 node: Mapped[Node] = relationship(init=False, back_populates="public_trips")
57 host_requests: Mapped[list[HostRequest]] = relationship(init=False, back_populates="public_trip")
59 __table_args__ = (
60 # Ensure from_date is not after to_date
61 CheckConstraint("from_date <= to_date", name="valid_date_range"),
62 # Index for querying active trips in a community
63 # Using partial index since we mostly query for active trips
64 Index(
65 "ix_public_trips_node_from_date_active",
66 node_id,
67 from_date,
68 postgresql_where=status == PublicTripStatus.searching_for_host,
69 ),
70 )