diff --git a/backend/trip/alembic/versions/11c969913a7e_update_indexes.py b/backend/trip/alembic/versions/11c969913a7e_update_indexes.py new file mode 100644 index 0000000..815fc60 --- /dev/null +++ b/backend/trip/alembic/versions/11c969913a7e_update_indexes.py @@ -0,0 +1,95 @@ +"""Update indexes + +Revision ID: 11c969913a7e +Revises: 4f837664b686 +Create Date: 2025-10-11 15:40:44.325096 + +""" + +import sqlalchemy as sa +import sqlmodel.sql.sqltypes +from alembic import op + +# revision identifiers, used by Alembic. +revision = "11c969913a7e" +down_revision = "4f837664b686" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("category", schema=None) as batch_op: + batch_op.create_index(batch_op.f("ix_category_user"), ["user"], unique=False) + + with op.batch_alter_table("image", schema=None) as batch_op: + batch_op.create_index(batch_op.f("ix_image_user"), ["user"], unique=False) + + with op.batch_alter_table("place", schema=None) as batch_op: + batch_op.create_index("idx_place_user_category", ["user", "category_id"], unique=False) + batch_op.create_index(batch_op.f("ix_place_category_id"), ["category_id"], unique=False) + batch_op.create_index(batch_op.f("ix_place_user"), ["user"], unique=False) + + with op.batch_alter_table("trip", schema=None) as batch_op: + batch_op.create_index(batch_op.f("ix_trip_user"), ["user"], unique=False) + + with op.batch_alter_table("tripchecklistitem", schema=None) as batch_op: + batch_op.create_index(batch_op.f("ix_tripchecklistitem_trip_id"), ["trip_id"], unique=False) + + with op.batch_alter_table("tripday", schema=None) as batch_op: + batch_op.create_index(batch_op.f("ix_tripday_trip_id"), ["trip_id"], unique=False) + + with op.batch_alter_table("tripitem", schema=None) as batch_op: + batch_op.create_index(batch_op.f("ix_tripitem_day_id"), ["day_id"], unique=False) + + with op.batch_alter_table("tripmember", schema=None) as batch_op: + batch_op.create_index( + "idx_tripmember_trip_user_joined", ["trip_id", "user", "joined_at"], unique=False + ) + batch_op.create_index(batch_op.f("ix_tripmember_trip_id"), ["trip_id"], unique=False) + + with op.batch_alter_table("trippackinglistitem", schema=None) as batch_op: + batch_op.create_index(batch_op.f("ix_trippackinglistitem_trip_id"), ["trip_id"], unique=False) + + with op.batch_alter_table("tripplacelink", schema=None) as batch_op: + batch_op.create_index(batch_op.f("ix_tripplacelink_place_id"), ["place_id"], unique=False) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("tripplacelink", schema=None) as batch_op: + batch_op.drop_index(batch_op.f("ix_tripplacelink_place_id")) + + with op.batch_alter_table("trippackinglistitem", schema=None) as batch_op: + batch_op.drop_index(batch_op.f("ix_trippackinglistitem_trip_id")) + + with op.batch_alter_table("tripmember", schema=None) as batch_op: + batch_op.drop_index(batch_op.f("ix_tripmember_trip_id")) + batch_op.drop_index("idx_tripmember_trip_user_joined") + + with op.batch_alter_table("tripitem", schema=None) as batch_op: + batch_op.drop_index(batch_op.f("ix_tripitem_day_id")) + + with op.batch_alter_table("tripday", schema=None) as batch_op: + batch_op.drop_index(batch_op.f("ix_tripday_trip_id")) + + with op.batch_alter_table("tripchecklistitem", schema=None) as batch_op: + batch_op.drop_index(batch_op.f("ix_tripchecklistitem_trip_id")) + + with op.batch_alter_table("trip", schema=None) as batch_op: + batch_op.drop_index(batch_op.f("ix_trip_user")) + + with op.batch_alter_table("place", schema=None) as batch_op: + batch_op.drop_index(batch_op.f("ix_place_user")) + batch_op.drop_index(batch_op.f("ix_place_category_id")) + batch_op.drop_index("idx_place_user_category") + + with op.batch_alter_table("image", schema=None) as batch_op: + batch_op.drop_index(batch_op.f("ix_image_user")) + + with op.batch_alter_table("category", schema=None) as batch_op: + batch_op.drop_index(batch_op.f("ix_category_user")) + + # ### end Alembic commands ### diff --git a/backend/trip/models/models.py b/backend/trip/models/models.py index f5f7f51..a7a093d 100644 --- a/backend/trip/models/models.py +++ b/backend/trip/models/models.py @@ -4,7 +4,7 @@ from enum import Enum from typing import Annotated from pydantic import BaseModel, StringConstraints, field_validator -from sqlalchemy import MetaData +from sqlalchemy import Index, MetaData from sqlmodel import Field, Relationship, SQLModel from ..config import settings @@ -70,7 +70,7 @@ class ImageBase(SQLModel): class Image(ImageBase, table=True): id: int | None = Field(default=None, primary_key=True) - user: str = Field(foreign_key="user.username", ondelete="CASCADE") + user: str = Field(foreign_key="user.username", ondelete="CASCADE", index=True) categories: list["Category"] = Relationship(back_populates="image") places: list["Place"] = Relationship(back_populates="image") @@ -130,7 +130,7 @@ class Category(CategoryBase, table=True): image_id: int | None = Field(default=None, foreign_key="image.id", ondelete="CASCADE") image: Image | None = Relationship(back_populates="categories") places: list["Place"] = Relationship(back_populates="category") - user: str = Field(foreign_key="user.username", ondelete="CASCADE") + user: str = Field(foreign_key="user.username", ondelete="CASCADE", index=True) class CategoryCreate(CategoryBase): @@ -164,7 +164,7 @@ class CategoryRead(CategoryBase): class TripPlaceLink(SQLModel, table=True): trip_id: int = Field(foreign_key="trip.id", primary_key=True) - place_id: int = Field(foreign_key="place.id", primary_key=True) + place_id: int = Field(foreign_key="place.id", primary_key=True, index=True) class PlaceBase(SQLModel): @@ -184,18 +184,20 @@ class PlaceBase(SQLModel): class Place(PlaceBase, table=True): id: int | None = Field(default=None, primary_key=True) cdate: date = Field(default_factory=lambda: datetime.now(UTC)) - user: str = Field(foreign_key="user.username", ondelete="CASCADE") + user: str = Field(foreign_key="user.username", ondelete="CASCADE", index=True) image_id: int | None = Field(default=None, foreign_key="image.id", ondelete="CASCADE") image: Image | None = Relationship(back_populates="places") - category_id: int = Field(foreign_key="category.id") + category_id: int = Field(foreign_key="category.id", index=True) category: Category | None = Relationship(back_populates="places") trip_items: list["TripItem"] = Relationship(back_populates="place") trips: list["Trip"] = Relationship(back_populates="places", link_model=TripPlaceLink) + __table_args__ = (Index("idx_place_user_category", "user", "category_id"),) + class PlaceCreate(PlaceBase): image: str | None = None @@ -259,7 +261,7 @@ class Trip(TripBase, table=True): id: int | None = Field(default=None, primary_key=True) image_id: int | None = Field(default=None, foreign_key="image.id", ondelete="CASCADE") image: Image | None = Relationship(back_populates="trips") - user: str = Field(foreign_key="user.username", ondelete="CASCADE") + user: str = Field(foreign_key="user.username", ondelete="CASCADE", index=True) places: list["Place"] = Relationship( back_populates="trips", sa_relationship_kwargs={"order_by": "Place.name"}, link_model=TripPlaceLink @@ -328,7 +330,7 @@ class TripRead(TripBase): shared=bool(obj.shares), currency=obj.currency if obj.currency else settings.DEFAULT_CURRENCY, notes=obj.notes, - archival_review=obj.archival_review + archival_review=obj.archival_review, ) @@ -339,9 +341,11 @@ class TripMember(SQLModel, table=True): invited_at: datetime = Field(default_factory=lambda: datetime.now(UTC)) joined_at: datetime | None = None - trip_id: int = Field(foreign_key="trip.id", ondelete="CASCADE") + trip_id: int = Field(foreign_key="trip.id", ondelete="CASCADE", index=True) trip: Trip | None = Relationship(back_populates="memberships") + __table_args__ = (Index("idx_tripmember_trip_user_joined", "trip_id", "user", "joined_at"),) + class TripMemberCreate(BaseModel): user: str @@ -371,7 +375,7 @@ class TripDayBase(SQLModel): class TripDay(TripDayBase, table=True): id: int | None = Field(default=None, primary_key=True) - trip_id: int = Field(foreign_key="trip.id", ondelete="CASCADE") + trip_id: int = Field(foreign_key="trip.id", ondelete="CASCADE", index=True) trip: Trip | None = Relationship(back_populates="days") items: list["TripItem"] = Relationship(back_populates="day", cascade_delete=True) @@ -419,7 +423,7 @@ class TripItem(TripItemBase, table=True): image_id: int | None = Field(default=None, foreign_key="image.id", ondelete="CASCADE") image: Image | None = Relationship(back_populates="tripitems") - day_id: int = Field(foreign_key="tripday.id", ondelete="CASCADE") + day_id: int = Field(foreign_key="tripday.id", ondelete="CASCADE", index=True) day: TripDay | None = Relationship(back_populates="items") paid_by: int | None = Field(default=None, foreign_key="user.username", ondelete="SET NULL") @@ -489,7 +493,7 @@ class TripPackingListItemBase(SQLModel): class TripPackingListItem(TripPackingListItemBase, table=True): id: int | None = Field(default=None, primary_key=True) - trip_id: int = Field(foreign_key="trip.id", ondelete="CASCADE") + trip_id: int = Field(foreign_key="trip.id", ondelete="CASCADE", index=True) trip: Trip | None = Relationship(back_populates="packing_items") @@ -522,7 +526,7 @@ class TripChecklistItemBase(SQLModel): class TripChecklistItem(TripChecklistItemBase, table=True): id: int | None = Field(default=None, primary_key=True) - trip_id: int = Field(foreign_key="trip.id", ondelete="CASCADE") + trip_id: int = Field(foreign_key="trip.id", ondelete="CASCADE", index=True) trip: Trip | None = Relationship(back_populates="checklist_items")