from typing import List, Optional

from functools import wraps
from uuid import UUID

from sqlalchemy.sql.schema import UniqueConstraint
from sqlmodel import Field, Relationship, SQLModel


# monkeypath from https://github.com/tiangolo/sqlmodel/issues/9
# without this all database fields are indexed be default
def set_default_index(func):
    """Decorator to set default index for SQLModel
    Can be removed when https://github.com/tiangolo/sqlmodel/pull/11 is merged
    """

    @wraps(func)
    def inner(*args, index=False, **kwargs):
        return func(*args, index=index, **kwargs)

    return inner


# monkey patch field with default index=False
# this works as long as we always call Field()
Field = set_default_index(Field)


class TopicModelBase(SQLModel):
    model_id: UUID = Field()
    version: int = Field(default=1)


class TopicModel(TopicModelBase, table=True):
    __tablename__ = "topic_model"
    __table_args__ = (UniqueConstraint("model_id", "version", name="_model_id_version_uc"),)

    id: Optional[int] = Field(primary_key=True, nullable=False)  # NOQA: A003
    topics: List["Topic"] = Relationship(
        back_populates="topic_model", sa_relationship_kwargs={"cascade": "all,delete"}
    )


class WordBase(SQLModel):
    name: str = Field()
    score: float = Field()


class Word(WordBase, table=True):
    id: Optional[int] = Field(primary_key=True, nullable=False)  # NOQA: A003
    topic_id: int = Field(foreign_key="topic.id")
    topic: "Topic" = Relationship(
        back_populates="top_words", sa_relationship_kwargs={"cascade": "all,delete"}
    )


class TopicBase(SQLModel):
    name: str = Field()
    count: int = Field()
    topic_index: int = Field()


class TopicWithWords(TopicBase):
    top_words: List["WordBase"] = Field(default=[])


class Topic(TopicBase, table=True):
    id: Optional[int] = Field(primary_key=True, nullable=False)  # NOQA: A003
    topic_model_id: int = Field(foreign_key="topic_model.id")
    top_words: List[Word] = Relationship(
        back_populates="topic", sa_relationship_kwargs={"cascade": "all,delete"}
    )
    topic_model: TopicModel = Relationship(
        back_populates="topics", sa_relationship_kwargs={"cascade": "all,delete"}
    )

sqlmodel.Relationship sqlalchemy.sql.schema.UniqueConstraint functools.wraps sqlmodel.Field
[((485, 496), 'functools.wraps', 'wraps', (['func'], {}), '(func)\n', (490, 496), False, 'from functools import wraps\n'), ((793, 800), 'sqlmodel.Field', 'Field', ([], {}), '()\n', (798, 800), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((820, 836), 'sqlmodel.Field', 'Field', ([], {'default': '(1)'}), '(default=1)\n', (825, 836), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((1037, 1076), 'sqlmodel.Field', 'Field', ([], {'primary_key': '(True)', 'nullable': '(False)'}), '(primary_key=True, nullable=False)\n', (1042, 1076), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((1119, 1216), 'sqlmodel.Relationship', 'Relationship', ([], {'back_populates': '"""topic_model"""', 'sa_relationship_kwargs': "{'cascade': 'all,delete'}"}), "(back_populates='topic_model', sa_relationship_kwargs={\n    'cascade': 'all,delete'})\n", (1131, 1216), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((1270, 1277), 'sqlmodel.Field', 'Field', ([], {}), '()\n', (1275, 1277), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((1297, 1304), 'sqlmodel.Field', 'Field', ([], {}), '()\n', (1302, 1304), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((1365, 1404), 'sqlmodel.Field', 'Field', ([], {'primary_key': '(True)', 'nullable': '(False)'}), '(primary_key=True, nullable=False)\n', (1370, 1404), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((1439, 1468), 'sqlmodel.Field', 'Field', ([], {'foreign_key': '"""topic.id"""'}), "(foreign_key='topic.id')\n", (1444, 1468), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((1490, 1584), 'sqlmodel.Relationship', 'Relationship', ([], {'back_populates': '"""top_words"""', 'sa_relationship_kwargs': "{'cascade': 'all,delete'}"}), "(back_populates='top_words', sa_relationship_kwargs={'cascade':\n    'all,delete'})\n", (1502, 1584), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((1640, 1647), 'sqlmodel.Field', 'Field', ([], {}), '()\n', (1645, 1647), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((1665, 1672), 'sqlmodel.Field', 'Field', ([], {}), '()\n', (1670, 1672), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((1696, 1703), 'sqlmodel.Field', 'Field', ([], {}), '()\n', (1701, 1703), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((1773, 1790), 'sqlmodel.Field', 'Field', ([], {'default': '[]'}), '(default=[])\n', (1778, 1790), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((1853, 1892), 'sqlmodel.Field', 'Field', ([], {'primary_key': '(True)', 'nullable': '(False)'}), '(primary_key=True, nullable=False)\n', (1858, 1892), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((1933, 1968), 'sqlmodel.Field', 'Field', ([], {'foreign_key': '"""topic_model.id"""'}), "(foreign_key='topic_model.id')\n", (1938, 1968), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((1997, 2087), 'sqlmodel.Relationship', 'Relationship', ([], {'back_populates': '"""topic"""', 'sa_relationship_kwargs': "{'cascade': 'all,delete'}"}), "(back_populates='topic', sa_relationship_kwargs={'cascade':\n    'all,delete'})\n", (2009, 2087), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((2128, 2219), 'sqlmodel.Relationship', 'Relationship', ([], {'back_populates': '"""topics"""', 'sa_relationship_kwargs': "{'cascade': 'all,delete'}"}), "(back_populates='topics', sa_relationship_kwargs={'cascade':\n    'all,delete'})\n", (2140, 2219), False, 'from sqlmodel import Field, Relationship, SQLModel\n'), ((941, 1009), 'sqlalchemy.sql.schema.UniqueConstraint', 'UniqueConstraint', (['"""model_id"""', '"""version"""'], {'name': '"""_model_id_version_uc"""'}), "('model_id', 'version', name='_model_id_version_uc')\n", (957, 1009), False, 'from sqlalchemy.sql.schema import UniqueConstraint\n')]