"""Initial schema with users, conversations, messages, and guilds. Revision ID: 0001 Revises: Create Date: 2025-01-12 """ from typing import Sequence, Union import sqlalchemy as sa from sqlalchemy.dialects import postgresql from alembic import op # revision identifiers, used by Alembic. revision: str = "0001" down_revision: Union[str, None] = None branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # Users table op.create_table( "users", sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False), sa.Column("discord_id", sa.BigInteger(), nullable=False), sa.Column("discord_username", sa.String(255), nullable=False), sa.Column("discord_display_name", sa.String(255), nullable=True), sa.Column("custom_name", sa.String(255), nullable=True), sa.Column("first_seen_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("last_seen_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("is_active", sa.Boolean(), nullable=False, server_default="true"), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.PrimaryKeyConstraint("id", name=op.f("pk_users")), sa.UniqueConstraint("discord_id", name=op.f("uq_users_discord_id")), ) op.create_index(op.f("ix_users_discord_id"), "users", ["discord_id"]) op.create_index(op.f("ix_users_last_seen_at"), "users", ["last_seen_at"]) # User preferences table op.create_table( "user_preferences", sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False), sa.Column("user_id", sa.BigInteger(), nullable=False), sa.Column("preference_key", sa.String(100), nullable=False), sa.Column("preference_value", sa.Text(), nullable=True), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.ForeignKeyConstraint( ["user_id"], ["users.id"], name=op.f("fk_user_preferences_user_id_users"), ondelete="CASCADE", ), sa.PrimaryKeyConstraint("id", name=op.f("pk_user_preferences")), sa.UniqueConstraint("user_id", "preference_key", name="uq_user_preferences_user_key"), ) op.create_index(op.f("ix_user_preferences_user_id"), "user_preferences", ["user_id"]) # User facts table op.create_table( "user_facts", sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False), sa.Column("user_id", sa.BigInteger(), nullable=False), sa.Column("fact_type", sa.String(50), nullable=False), sa.Column("fact_content", sa.Text(), nullable=False), sa.Column("confidence", sa.Float(), server_default="1.0"), sa.Column("source", sa.String(50), server_default="conversation"), sa.Column("is_active", sa.Boolean(), nullable=False, server_default="true"), sa.Column("learned_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("last_referenced_at", sa.DateTime(timezone=True), nullable=True), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.ForeignKeyConstraint( ["user_id"], ["users.id"], name=op.f("fk_user_facts_user_id_users"), ondelete="CASCADE", ), sa.PrimaryKeyConstraint("id", name=op.f("pk_user_facts")), ) op.create_index(op.f("ix_user_facts_user_id"), "user_facts", ["user_id"]) op.create_index(op.f("ix_user_facts_fact_type"), "user_facts", ["fact_type"]) op.create_index(op.f("ix_user_facts_is_active"), "user_facts", ["is_active"]) # Guilds table op.create_table( "guilds", sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False), sa.Column("discord_id", sa.BigInteger(), nullable=False), sa.Column("name", sa.String(255), nullable=False), sa.Column("joined_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("is_active", sa.Boolean(), nullable=False, server_default="true"), sa.Column("settings", postgresql.JSONB(), server_default="{}"), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.PrimaryKeyConstraint("id", name=op.f("pk_guilds")), sa.UniqueConstraint("discord_id", name=op.f("uq_guilds_discord_id")), ) op.create_index(op.f("ix_guilds_discord_id"), "guilds", ["discord_id"]) # Guild members table op.create_table( "guild_members", sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False), sa.Column("guild_id", sa.BigInteger(), nullable=False), sa.Column("user_id", sa.BigInteger(), nullable=False), sa.Column("guild_nickname", sa.String(255), nullable=True), sa.Column("roles", postgresql.ARRAY(sa.Text()), nullable=True), sa.Column("joined_guild_at", sa.DateTime(timezone=True), nullable=True), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.ForeignKeyConstraint( ["guild_id"], ["guilds.id"], name=op.f("fk_guild_members_guild_id_guilds"), ondelete="CASCADE", ), sa.ForeignKeyConstraint( ["user_id"], ["users.id"], name=op.f("fk_guild_members_user_id_users"), ondelete="CASCADE", ), sa.PrimaryKeyConstraint("id", name=op.f("pk_guild_members")), sa.UniqueConstraint("guild_id", "user_id", name="uq_guild_members_guild_user"), ) op.create_index(op.f("ix_guild_members_guild_id"), "guild_members", ["guild_id"]) op.create_index(op.f("ix_guild_members_user_id"), "guild_members", ["user_id"]) # Conversations table op.create_table( "conversations", sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False), sa.Column("user_id", sa.BigInteger(), nullable=False), sa.Column("guild_id", sa.BigInteger(), nullable=True), sa.Column("channel_id", sa.BigInteger(), nullable=True), sa.Column("started_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("last_message_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("message_count", sa.Integer(), server_default="0"), sa.Column("is_active", sa.Boolean(), nullable=False, server_default="true"), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.ForeignKeyConstraint( ["user_id"], ["users.id"], name=op.f("fk_conversations_user_id_users"), ondelete="CASCADE", ), sa.PrimaryKeyConstraint("id", name=op.f("pk_conversations")), ) op.create_index(op.f("ix_conversations_user_id"), "conversations", ["user_id"]) op.create_index(op.f("ix_conversations_channel_id"), "conversations", ["channel_id"]) op.create_index(op.f("ix_conversations_last_message_at"), "conversations", ["last_message_at"]) op.create_index(op.f("ix_conversations_is_active"), "conversations", ["is_active"]) # Messages table op.create_table( "messages", sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False), sa.Column("conversation_id", sa.BigInteger(), nullable=False), sa.Column("user_id", sa.BigInteger(), nullable=False), sa.Column("discord_message_id", sa.BigInteger(), nullable=True), sa.Column("role", sa.String(20), nullable=False), sa.Column("content", sa.Text(), nullable=False), sa.Column("has_images", sa.Boolean(), nullable=False, server_default="false"), sa.Column("image_urls", postgresql.ARRAY(sa.Text()), nullable=True), sa.Column("token_count", sa.Integer(), nullable=True), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.ForeignKeyConstraint( ["conversation_id"], ["conversations.id"], name=op.f("fk_messages_conversation_id_conversations"), ondelete="CASCADE", ), sa.ForeignKeyConstraint( ["user_id"], ["users.id"], name=op.f("fk_messages_user_id_users"), ondelete="CASCADE", ), sa.PrimaryKeyConstraint("id", name=op.f("pk_messages")), ) op.create_index(op.f("ix_messages_conversation_id"), "messages", ["conversation_id"]) op.create_index(op.f("ix_messages_user_id"), "messages", ["user_id"]) op.create_index(op.f("ix_messages_created_at"), "messages", ["created_at"]) def downgrade() -> None: op.drop_table("messages") op.drop_table("conversations") op.drop_table("guild_members") op.drop_table("guilds") op.drop_table("user_facts") op.drop_table("user_preferences") op.drop_table("users")