From c5b703b75ac9eda7f6389a823c6cce27b0c91685 Mon Sep 17 00:00:00 2001 From: patrick Date: Mon, 10 Aug 2026 23:58:09 -0400 Subject: [PATCH] refactor: use unique constraints instead of composite keys on link tables --- backend/src/chitai/database/models/author.py | 9 ++++----- backend/src/chitai/database/models/book.py | 10 ++++------ backend/src/chitai/database/models/book_list.py | 10 +++++----- backend/src/chitai/database/models/tag.py | 11 ++++------- 4 files changed, 17 insertions(+), 23 deletions(-) diff --git a/backend/src/chitai/database/models/author.py b/backend/src/chitai/database/models/author.py index 4540327..b47fe4a 100644 --- a/backend/src/chitai/database/models/author.py +++ b/backend/src/chitai/database/models/author.py @@ -1,7 +1,7 @@ from typing import TYPE_CHECKING, Optional from collections.abc import Hashable -from sqlalchemy import ColumnElement, ForeignKey +from sqlalchemy import ColumnElement, ForeignKey, UniqueConstraint from sqlalchemy.orm import Mapped from sqlalchemy.orm import mapped_column from sqlalchemy.orm import relationship @@ -35,11 +35,10 @@ class Author(BigIntAuditBase, UniqueMixin): class BookAuthorLink(BigIntBase): __tablename__ = "book_author_links" + __table_args__ = (UniqueConstraint("book_id", "author_id"),) - book_id: Mapped[int] = mapped_column( - ForeignKey("books.id", ondelete="cascade"), primary_key=True - ) - author_id: Mapped[int] = mapped_column(ForeignKey("authors.id"), primary_key=True) + book_id: Mapped[int] = mapped_column(ForeignKey("books.id", ondelete="cascade")) + author_id: Mapped[int] = mapped_column(ForeignKey("authors.id")) position: Mapped[int] diff --git a/backend/src/chitai/database/models/book.py b/backend/src/chitai/database/models/book.py index 3e69cb0..e647e70 100644 --- a/backend/src/chitai/database/models/book.py +++ b/backend/src/chitai/database/models/book.py @@ -1,8 +1,7 @@ from datetime import date from typing import TYPE_CHECKING, Any, Optional -from sqlalchemy import Index -from sqlalchemy import ForeignKey +from sqlalchemy import Index, ForeignKey, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column, relationship from sqlalchemy.orm import mapped_column from sqlalchemy.orm import relationship @@ -127,11 +126,10 @@ class Book(BigIntAuditBase): class Identifier(BigIntBase): __tablename__ = "identifiers" + __table_args__ = (UniqueConstraint("name", "book_id"),) - name: Mapped[str] = mapped_column(primary_key=True) - book_id: Mapped[int] = mapped_column( - ForeignKey("books.id", ondelete="cascade"), primary_key=True - ) + name: Mapped[str] + book_id: Mapped[int] = mapped_column(ForeignKey("books.id", ondelete="cascade")) value: Mapped[str] def __repr__(self): diff --git a/backend/src/chitai/database/models/book_list.py b/backend/src/chitai/database/models/book_list.py index 05edfea..d2d62cd 100644 --- a/backend/src/chitai/database/models/book_list.py +++ b/backend/src/chitai/database/models/book_list.py @@ -1,5 +1,5 @@ from typing import Optional -from sqlalchemy import ForeignKey +from sqlalchemy import ForeignKey, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column, relationship from sqlalchemy.ext.associationproxy import association_proxy, AssociationProxy from sqlalchemy.ext.orderinglist import ordering_list @@ -38,10 +38,10 @@ class BookList(BigIntAuditBase): class BookListLink(BigIntBase): __tablename__ = "book_list_links" - book_id: Mapped[int] = mapped_column( - ForeignKey("books.id", ondelete="cascade"), primary_key=True - ) - list_id: Mapped[int] = mapped_column(ForeignKey("book_lists.id"), primary_key=True) + __table_args__ = (UniqueConstraint("book_id", "list_id"),) + + book_id: Mapped[int] = mapped_column(ForeignKey("books.id", ondelete="cascade")) + list_id: Mapped[int] = mapped_column(ForeignKey("book_lists.id")) position: Mapped[int] book: Mapped[Book] = relationship(back_populates="list_links") diff --git a/backend/src/chitai/database/models/tag.py b/backend/src/chitai/database/models/tag.py index c449803..fca2bdc 100644 --- a/backend/src/chitai/database/models/tag.py +++ b/backend/src/chitai/database/models/tag.py @@ -1,7 +1,7 @@ from collections.abc import Hashable from typing import TYPE_CHECKING -from sqlalchemy import ColumnElement, ForeignKey +from sqlalchemy import ColumnElement, ForeignKey, UniqueConstraint from sqlalchemy.orm import Mapped from sqlalchemy.orm import mapped_column from sqlalchemy.orm import relationship @@ -35,15 +35,12 @@ class Tag(BigIntBase, UniqueMixin): class BookTagLink(BigIntBase): __tablename__ = "book_tag_link" + __table_args__ = (UniqueConstraint("book_id", "tag_id"),) - book_id: Mapped[int] = mapped_column( - ForeignKey("books.id", ondelete="cascade"), primary_key=True - ) - - tag_id: Mapped[int] = mapped_column(ForeignKey("tags.id"), primary_key=True) + book_id: Mapped[int] = mapped_column(ForeignKey("books.id", ondelete="cascade")) + tag_id: Mapped[int] = mapped_column(ForeignKey("tags.id")) position: Mapped[int] book: Mapped["Book"] = relationship(back_populates="tag_links") - tag: Mapped[Tag] = relationship()