TravelMap / app /models.py
Jack
Initial commit
5ff3858
from __future__ import annotations
from datetime import date, datetime
from typing import Any
from sqlalchemy import (
JSON,
Boolean,
Date,
DateTime,
Float,
ForeignKey,
Integer,
String,
Text,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.database import Base
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
name: Mapped[str] = mapped_column(String(120), nullable=False)
email: Mapped[str] = mapped_column(String(255), unique=True, index=True, nullable=False)
password: Mapped[str] = mapped_column(String(120), nullable=False)
is_host: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
hometown: Mapped[str] = mapped_column(String(120), default="", nullable=False)
bio: Mapped[str] = mapped_column(Text, default="", nullable=False)
avatar_url: Mapped[str] = mapped_column(String(500), default="", nullable=False)
listings: Mapped[list["Listing"]] = relationship(back_populates="host")
bookings: Mapped[list["Booking"]] = relationship(back_populates="guest")
wishlist_items: Mapped[list["WishlistItem"]] = relationship(back_populates="user")
reviews: Mapped[list["Review"]] = relationship(back_populates="user")
sent_messages: Mapped[list["Message"]] = relationship(back_populates="sender")
class Listing(Base):
__tablename__ = "listings"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
slug: Mapped[str] = mapped_column(String(150), unique=True, index=True, nullable=False)
host_id: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False)
title: Mapped[str] = mapped_column(String(200), nullable=False)
city: Mapped[str] = mapped_column(String(120), index=True, nullable=False)
country: Mapped[str] = mapped_column(String(120), nullable=False)
neighborhood: Mapped[str] = mapped_column(String(120), nullable=False)
price_per_night: Mapped[float] = mapped_column(Float, nullable=False)
cleaning_fee: Mapped[float] = mapped_column(Float, default=0, nullable=False)
service_fee: Mapped[float] = mapped_column(Float, default=0, nullable=False)
bedrooms: Mapped[int] = mapped_column(Integer, default=1, nullable=False)
beds: Mapped[int] = mapped_column(Integer, default=1, nullable=False)
baths: Mapped[float] = mapped_column(Float, default=1, nullable=False)
max_guests: Mapped[int] = mapped_column(Integer, default=2, nullable=False)
rating: Mapped[float] = mapped_column(Float, default=5.0, nullable=False)
review_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
description: Mapped[str] = mapped_column(Text, default="", nullable=False)
amenities: Mapped[list[str]] = mapped_column(JSON, default=list, nullable=False)
house_rules: Mapped[list[str]] = mapped_column(JSON, default=list, nullable=False)
blocked_ranges: Mapped[list[dict[str, str]]] = mapped_column(JSON, default=list, nullable=False)
host: Mapped[User] = relationship(back_populates="listings")
images: Mapped[list["ListingImage"]] = relationship(
back_populates="listing",
cascade="all, delete-orphan",
order_by="ListingImage.display_order",
)
reviews: Mapped[list["Review"]] = relationship(
back_populates="listing",
cascade="all, delete-orphan",
order_by="desc(Review.created_at)",
)
bookings: Mapped[list["Booking"]] = relationship(back_populates="listing")
availability_entries: Mapped[list["Availability"]] = relationship(
back_populates="listing",
cascade="all, delete-orphan",
)
wishlist_items: Mapped[list["WishlistItem"]] = relationship(back_populates="listing")
threads: Mapped[list["MessageThread"]] = relationship(back_populates="listing")
@property
def primary_image(self) -> str:
if self.images:
return self.images[0].url
return "https://images.unsplash.com/photo-1505693416388-ac5ce068fe85?auto=format&fit=crop&w=1200&q=80"
class ListingImage(Base):
__tablename__ = "listing_images"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
listing_id: Mapped[int] = mapped_column(ForeignKey("listings.id"), nullable=False)
url: Mapped[str] = mapped_column(String(500), nullable=False)
alt_text: Mapped[str] = mapped_column(String(255), default="", nullable=False)
display_order: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
listing: Mapped[Listing] = relationship(back_populates="images")
class Availability(Base):
__tablename__ = "availability"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
listing_id: Mapped[int] = mapped_column(ForeignKey("listings.id"), index=True, nullable=False)
date: Mapped[date] = mapped_column(Date, index=True, nullable=False)
is_available: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
listing: Mapped[Listing] = relationship(back_populates="availability_entries")
class Review(Base):
__tablename__ = "reviews"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
listing_id: Mapped[int] = mapped_column(ForeignKey("listings.id"), nullable=False)
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False)
rating: Mapped[float] = mapped_column(Float, nullable=False)
comment: Mapped[str] = mapped_column(Text, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
listing: Mapped[Listing] = relationship(back_populates="reviews")
user: Mapped[User] = relationship(back_populates="reviews")
class Booking(Base):
__tablename__ = "bookings"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
confirmation_code: Mapped[str] = mapped_column(String(50), unique=True, nullable=False)
listing_id: Mapped[int] = mapped_column(ForeignKey("listings.id"), nullable=False)
guest_id: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False)
check_in: Mapped[date] = mapped_column(Date, nullable=False)
check_out: Mapped[date] = mapped_column(Date, nullable=False)
guests: Mapped[int] = mapped_column(Integer, nullable=False)
total_price: Mapped[float] = mapped_column(Float, nullable=False)
status: Mapped[str] = mapped_column(String(40), default="confirmed", nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
listing: Mapped[Listing] = relationship(back_populates="bookings")
guest: Mapped[User] = relationship(back_populates="bookings")
@property
def nights(self) -> int:
return (self.check_out - self.check_in).days
class WishlistItem(Base):
__tablename__ = "wishlist_items"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False)
listing_id: Mapped[int] = mapped_column(ForeignKey("listings.id"), nullable=False)
notes: Mapped[str] = mapped_column(Text, default="", nullable=False)
user: Mapped[User] = relationship(back_populates="wishlist_items")
listing: Mapped[Listing] = relationship(back_populates="wishlist_items")
class MessageThread(Base):
__tablename__ = "message_threads"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
listing_id: Mapped[int] = mapped_column(ForeignKey("listings.id"), nullable=False)
guest_id: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False)
host_id: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False)
subject: Mapped[str] = mapped_column(String(200), nullable=False)
last_message_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
listing: Mapped[Listing] = relationship(back_populates="threads")
guest: Mapped[User] = relationship(foreign_keys=[guest_id])
host: Mapped[User] = relationship(foreign_keys=[host_id])
messages: Mapped[list["Message"]] = relationship(
back_populates="thread",
cascade="all, delete-orphan",
order_by="Message.created_at",
)
class Message(Base):
__tablename__ = "messages"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
thread_id: Mapped[int] = mapped_column(ForeignKey("message_threads.id"), nullable=False)
sender_id: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False)
body: Mapped[str] = mapped_column(Text, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
thread: Mapped[MessageThread] = relationship(back_populates="messages")
sender: Mapped[User] = relationship(back_populates="sent_messages")
class TaskDefinition(Base):
__tablename__ = "task_definitions"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
slug: Mapped[str] = mapped_column(String(120), unique=True, nullable=False)
title: Mapped[str] = mapped_column(String(200), nullable=False)
category: Mapped[str] = mapped_column(String(120), nullable=False)
difficulty: Mapped[str] = mapped_column(String(50), nullable=False)
start_path: Mapped[str] = mapped_column(String(255), default="/", nullable=False)
persona_user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), nullable=False)
intent: Mapped[str] = mapped_column(Text, nullable=False)
success_criteria: Mapped[str] = mapped_column(Text, nullable=False)
validator_key: Mapped[str] = mapped_column(String(80), nullable=False)
validation_target: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict, nullable=False)
persona: Mapped[User] = relationship()