File size: 3,189 Bytes
b07a1e9
 
 
 
 
 
 
 
 
 
 
 
 
 
4004da2
 
b07a1e9
 
 
4004da2
 
 
 
 
 
b07a1e9
 
 
4004da2
 
 
 
 
b07a1e9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
"""

Database models for Neon Postgres

"""
from sqlalchemy import Column, String, Text, DateTime, ForeignKey, UniqueConstraint, Index
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.sql import func
import uuid
from database.db import Base

class User(Base):
    __tablename__ = "users"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    email = Column(String(255), unique=True, nullable=False, index=True)
    password_hash = Column(String(255), nullable=True)  # Nullable for OAuth users
    full_name = Column(String(255), nullable=True)
    software_background = Column(Text, nullable=True)
    hardware_background = Column(Text, nullable=True)
    experience_level = Column(String(50), nullable=True, default="Intermediate")

    # OAuth fields
    oauth_provider = Column(String(50), nullable=True)  # 'google', 'facebook', or None
    oauth_id = Column(String(255), nullable=True)  # Provider's user ID
    profile_picture = Column(String(500), nullable=True)  # Profile picture URL from OAuth

    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(DateTime(timezone=True), onupdate=func.now())

    # Index for OAuth lookup
    __table_args__ = (
        Index('idx_user_oauth', 'oauth_provider', 'oauth_id'),
    )

class Personalization(Base):
    __tablename__ = "personalizations"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    user_id = Column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
    chapter_id = Column(String(255), nullable=False, index=True)
    personalized_content = Column(Text, nullable=False)
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(DateTime(timezone=True), onupdate=func.now())

    # Composite unique constraint: one personalization per user per chapter
    __table_args__ = (
        UniqueConstraint('user_id', 'chapter_id', name='uq_user_chapter'),
    )

class Translation(Base):
    __tablename__ = "translations"

    id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    chapter_id = Column(String(255), nullable=False, index=True)
    content_hash = Column(String(64), nullable=False, index=True)
    source_language = Column(String(10), nullable=False, default="english")
    target_language = Column(String(10), nullable=False, index=True)
    original_content = Column(Text, nullable=False)
    translated_content = Column(Text, nullable=False)
    user_id = Column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(DateTime(timezone=True), onupdate=func.now())

    # Composite unique constraint: one translation per (chapter_id, content_hash, target_language)
    __table_args__ = (
        UniqueConstraint('chapter_id', 'content_hash', 'target_language', name='uq_chapter_hash_language'),
        Index('idx_translations_lookup', 'chapter_id', 'content_hash', 'target_language'),
    )