82 lines
2.8 KiB
Python
82 lines
2.8 KiB
Python
from datetime import datetime
|
|
from typing import TYPE_CHECKING, List, Optional
|
|
|
|
from sqlalchemy import Boolean, DateTime, ForeignKey, Index, Integer, String, func
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.database.session import Base
|
|
|
|
if TYPE_CHECKING:
|
|
from app.user.models import User
|
|
from app.video.models import Video
|
|
|
|
|
|
class Comment(Base):
|
|
"""
|
|
영상 댓글 테이블
|
|
|
|
2-depth 구조 (최상위 댓글 + 대댓글 1단계).
|
|
parent_id가 NULL이면 최상위 댓글, 값이 있으면 대댓글.
|
|
작성자(user_uuid)는 DB에 저장하지만 API 응답에는 미노출 (익명 정책).
|
|
"""
|
|
|
|
__tablename__ = "comment"
|
|
__table_args__ = (
|
|
Index("idx_comment_video_id", "video_id"),
|
|
Index("idx_comment_user_uuid", "user_uuid"),
|
|
Index("idx_comment_parent_id", "parent_id"),
|
|
Index("idx_comment_is_deleted", "is_deleted"),
|
|
{
|
|
"mysql_engine": "InnoDB",
|
|
"mysql_charset": "utf8mb4",
|
|
"mysql_collate": "utf8mb4_unicode_ci",
|
|
},
|
|
)
|
|
|
|
id: Mapped[int] = mapped_column(
|
|
Integer, primary_key=True, autoincrement=True, comment="고유 식별자"
|
|
)
|
|
video_id: Mapped[int] = mapped_column(
|
|
Integer,
|
|
ForeignKey("video.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
comment="연결된 Video의 id",
|
|
)
|
|
user_uuid: Mapped[str] = mapped_column(
|
|
ForeignKey("user.user_uuid", ondelete="CASCADE"),
|
|
nullable=False,
|
|
comment="작성자 UUID (응답 미노출, 권한 검증용)",
|
|
)
|
|
parent_id: Mapped[Optional[int]] = mapped_column(
|
|
Integer,
|
|
ForeignKey("comment.id", ondelete="CASCADE"),
|
|
nullable=True,
|
|
comment="NULL=최상위 댓글, 값=대댓글의 부모 id",
|
|
)
|
|
nickname: Mapped[Optional[str]] = mapped_column(
|
|
String(50), nullable=True, comment="댓글 작성자 닉네임 (null이면 익명)"
|
|
)
|
|
content: Mapped[str] = mapped_column(
|
|
String(100), nullable=False, comment="댓글 본문 (한글 기준 100자 이내)"
|
|
)
|
|
is_deleted: Mapped[bool] = mapped_column(
|
|
Boolean, nullable=False, default=False, comment="소프트 삭제 여부"
|
|
)
|
|
created_at: Mapped[datetime] = mapped_column(
|
|
DateTime,
|
|
nullable=False,
|
|
server_default=func.now(),
|
|
comment="작성 일시",
|
|
)
|
|
|
|
video: Mapped["Video"] = relationship("Video", back_populates="comments")
|
|
user: Mapped["User"] = relationship("User", back_populates="comments")
|
|
parent: Mapped[Optional["Comment"]] = relationship(
|
|
"Comment", remote_side=[id], back_populates="replies"
|
|
)
|
|
replies: Mapped[List["Comment"]] = relationship(
|
|
"Comment",
|
|
back_populates="parent",
|
|
cascade="all, delete-orphan",
|
|
)
|