Files
life-echo/api/app/features/memoir/models.py

132 lines
4.3 KiB
Python

from sqlalchemy import (
JSON,
Boolean,
Column,
DateTime,
ForeignKey,
Integer,
String,
Text,
)
from sqlalchemy.orm import relationship
from app.core.db import Base, utc_now
class Chapter(Base):
__tablename__ = "chapters"
id = Column(String, primary_key=True)
user_id = Column(String, ForeignKey("users.id"), nullable=False)
title = Column(String, nullable=False)
order_index = Column(Integer, nullable=False)
status = Column(String, default="draft")
cover_image = Column(JSON, nullable=True)
updated_at = Column(DateTime(timezone=True), default=utc_now, onupdate=utc_now)
category = Column(String, nullable=True)
is_new = Column(Boolean, default=True)
is_active = Column(Boolean, default=True)
source_segments = Column(JSON, nullable=True)
user = relationship("User", back_populates="chapters")
sections = relationship(
"ChapterSection",
back_populates="chapter",
order_by="ChapterSection.order_index",
cascade="all, delete-orphan",
)
images = relationship(
"MemoirImage",
back_populates="chapter",
foreign_keys="MemoirImage.chapter_id",
cascade="all, delete-orphan",
)
class ChapterSection(Base):
__tablename__ = "chapter_sections"
id = Column(String, primary_key=True)
chapter_id = Column(
String, ForeignKey("chapters.id", ondelete="CASCADE"), nullable=False
)
order_index = Column(Integer, nullable=False)
content = Column(Text, nullable=False)
image_id = Column(
String, ForeignKey("memoir_images.id", ondelete="SET NULL"), nullable=True
)
updated_at = Column(DateTime(timezone=True), default=utc_now, onupdate=utc_now)
chapter = relationship("Chapter", back_populates="sections")
image_record = relationship(
"MemoirImage",
back_populates="section",
uselist=False,
foreign_keys="ChapterSection.image_id",
cascade="all, delete-orphan",
single_parent=True,
)
class MemoirImage(Base):
__tablename__ = "memoir_images"
id = Column(String, primary_key=True)
chapter_id = Column(
String, ForeignKey("chapters.id", ondelete="CASCADE"), nullable=False
)
section_id = Column(
String, ForeignKey("chapter_sections.id", ondelete="CASCADE"), nullable=True
)
order_index = Column(Integer, nullable=False, default=0)
placeholder = Column(Text, nullable=True)
description = Column(Text, nullable=True)
status = Column(String, nullable=False, default="pending")
prompt = Column(Text, nullable=True)
url = Column(Text, nullable=True)
storage_key = Column(Text, nullable=True)
provider = Column(String, nullable=True)
style = Column(String, nullable=True)
size = Column(String, nullable=True)
error = Column(Text, nullable=True)
retryable = Column(Boolean, nullable=True)
created_at = Column(DateTime(timezone=True), nullable=True)
updated_at = Column(DateTime(timezone=True), default=utc_now, onupdate=utc_now)
chapter = relationship("Chapter", back_populates="images")
section = relationship(
"ChapterSection",
back_populates="image_record",
foreign_keys="ChapterSection.image_id",
)
class Book(Base):
__tablename__ = "books"
id = Column(String, primary_key=True)
user_id = Column(String, ForeignKey("users.id"), nullable=False)
title = Column(String, nullable=False)
total_pages = Column(Integer, default=0)
total_words = Column(Integer, default=0)
cover_image_url = Column(String, nullable=True)
updated_at = Column(DateTime(timezone=True), default=utc_now, onupdate=utc_now)
has_update = Column(Boolean, default=False)
last_update_chapter_id = Column(String, nullable=True)
user = relationship("User", back_populates="books")
class MemoirState(Base):
__tablename__ = "memoir_states"
id = Column(String, primary_key=True)
user_id = Column(String, ForeignKey("users.id"), unique=True, nullable=False)
stage_order = Column(JSON, default=list)
current_stage = Column(String, default="childhood")
covered_stages = Column(JSON, default=list)
slots = Column(JSON, nullable=False)
updated_at = Column(DateTime(timezone=True), default=utc_now, onupdate=utc_now)
user = relationship("User", back_populates="memoir_state")