218 lines
13 KiB
Python
218 lines
13 KiB
Python
"""initial migration
|
||
|
||
Revision ID: 001
|
||
Revises:
|
||
Create Date: 2024-01-01 00:00:00.000000
|
||
|
||
"""
|
||
from alembic import op
|
||
import sqlalchemy as sa
|
||
from sqlalchemy.dialects import mysql
|
||
|
||
# revision identifiers, used by Alembic.
|
||
revision = '001'
|
||
down_revision = None
|
||
branch_labels = None
|
||
depends_on = None
|
||
|
||
|
||
def upgrade() -> None:
|
||
# 创建用户表
|
||
op.create_table(
|
||
'users',
|
||
sa.Column('id', mysql.CHAR(length=36), nullable=False, comment='用户ID'),
|
||
sa.Column('username', sa.String(length=50), nullable=False, comment='用户名'),
|
||
sa.Column('email', sa.String(length=100), nullable=False, comment='邮箱'),
|
||
sa.Column('password_hash', sa.String(length=255), nullable=False, comment='密码哈希'),
|
||
sa.Column('role', sa.String(length=20), server_default='user', nullable=True, comment='角色: admin/user'),
|
||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True, comment='创建时间'),
|
||
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'), nullable=True, comment='更新时间'),
|
||
sa.PrimaryKeyConstraint('id'),
|
||
sa.UniqueConstraint('email'),
|
||
sa.UniqueConstraint('username'),
|
||
mysql_charset='utf8mb4',
|
||
mysql_collate='utf8mb4_unicode_ci'
|
||
)
|
||
|
||
# 创建工作流表
|
||
op.create_table(
|
||
'workflows',
|
||
sa.Column('id', mysql.CHAR(length=36), nullable=False, comment='工作流ID'),
|
||
sa.Column('name', sa.String(length=100), nullable=False, comment='工作流名称'),
|
||
sa.Column('description', sa.Text(), nullable=True, comment='描述'),
|
||
sa.Column('nodes', sa.JSON(), nullable=False, comment='节点配置'),
|
||
sa.Column('edges', sa.JSON(), nullable=False, comment='边配置'),
|
||
sa.Column('version', sa.Integer(), server_default='1', nullable=True, comment='版本号'),
|
||
sa.Column('status', sa.String(length=20), server_default='draft', nullable=True, comment='状态: draft/published/running/stopped'),
|
||
sa.Column('user_id', mysql.CHAR(length=36), nullable=True, comment='创建者ID'),
|
||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True, comment='创建时间'),
|
||
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'), nullable=True, comment='更新时间'),
|
||
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
|
||
sa.PrimaryKeyConstraint('id'),
|
||
mysql_charset='utf8mb4',
|
||
mysql_collate='utf8mb4_unicode_ci'
|
||
)
|
||
op.create_index('ix_workflows_user_id', 'workflows', ['user_id'], unique=False)
|
||
|
||
# 创建工作流版本表
|
||
op.create_table(
|
||
'workflow_versions',
|
||
sa.Column('id', mysql.CHAR(length=36), nullable=False, comment='版本ID'),
|
||
sa.Column('workflow_id', mysql.CHAR(length=36), nullable=False, comment='工作流ID'),
|
||
sa.Column('version', sa.Integer(), nullable=False, comment='版本号'),
|
||
sa.Column('name', sa.String(length=100), nullable=False, comment='工作流名称'),
|
||
sa.Column('description', sa.Text(), nullable=True, comment='描述'),
|
||
sa.Column('nodes', sa.JSON(), nullable=False, comment='节点配置'),
|
||
sa.Column('edges', sa.JSON(), nullable=False, comment='边配置'),
|
||
sa.Column('status', sa.String(length=20), server_default='draft', nullable=True, comment='状态: draft/published/running/stopped'),
|
||
sa.Column('created_by', mysql.CHAR(length=36), nullable=True, comment='创建者ID'),
|
||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True, comment='创建时间'),
|
||
sa.Column('comment', sa.Text(), nullable=True, comment='版本备注'),
|
||
sa.ForeignKeyConstraint(['created_by'], ['users.id'], ),
|
||
sa.ForeignKeyConstraint(['workflow_id'], ['workflows.id'], ondelete='CASCADE'),
|
||
sa.PrimaryKeyConstraint('id'),
|
||
mysql_charset='utf8mb4',
|
||
mysql_collate='utf8mb4_unicode_ci'
|
||
)
|
||
op.create_index('ix_workflow_versions_workflow_id', 'workflow_versions', ['workflow_id'], unique=False)
|
||
|
||
# 创建智能体表
|
||
op.create_table(
|
||
'agents',
|
||
sa.Column('id', mysql.CHAR(length=36), nullable=False, comment='智能体ID'),
|
||
sa.Column('name', sa.String(length=100), nullable=False, comment='智能体名称'),
|
||
sa.Column('description', sa.Text(), nullable=True, comment='描述'),
|
||
sa.Column('workflow_config', sa.JSON(), nullable=False, comment='工作流配置'),
|
||
sa.Column('version', sa.Integer(), server_default='1', nullable=True, comment='版本号'),
|
||
sa.Column('status', sa.String(length=20), server_default='draft', nullable=True, comment='状态: draft/published/running/stopped'),
|
||
sa.Column('user_id', mysql.CHAR(length=36), nullable=True, comment='创建者ID'),
|
||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True, comment='创建时间'),
|
||
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'), nullable=True, comment='更新时间'),
|
||
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
|
||
sa.PrimaryKeyConstraint('id'),
|
||
mysql_charset='utf8mb4',
|
||
mysql_collate='utf8mb4_unicode_ci'
|
||
)
|
||
op.create_index('ix_agents_user_id', 'agents', ['user_id'], unique=False)
|
||
|
||
# 创建执行记录表
|
||
op.create_table(
|
||
'executions',
|
||
sa.Column('id', mysql.CHAR(length=36), nullable=False, comment='执行ID'),
|
||
sa.Column('workflow_id', mysql.CHAR(length=36), nullable=True, comment='工作流ID'),
|
||
sa.Column('agent_id', mysql.CHAR(length=36), nullable=True, comment='智能体ID'),
|
||
sa.Column('input_data', sa.JSON(), nullable=True, comment='输入数据'),
|
||
sa.Column('output_data', sa.JSON(), nullable=True, comment='输出数据'),
|
||
sa.Column('status', sa.String(length=20), server_default='pending', nullable=True, comment='状态: pending/running/completed/failed'),
|
||
sa.Column('task_id', sa.String(length=255), nullable=True, comment='Celery任务ID'),
|
||
sa.Column('error_message', sa.Text(), nullable=True, comment='错误信息'),
|
||
sa.Column('execution_time', sa.Integer(), nullable=True, comment='执行时间(毫秒)'),
|
||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True, comment='创建时间'),
|
||
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'), nullable=True, comment='更新时间'),
|
||
sa.ForeignKeyConstraint(['agent_id'], ['agents.id'], ),
|
||
sa.ForeignKeyConstraint(['workflow_id'], ['workflows.id'], ),
|
||
sa.PrimaryKeyConstraint('id'),
|
||
mysql_charset='utf8mb4',
|
||
mysql_collate='utf8mb4_unicode_ci'
|
||
)
|
||
op.create_index('ix_executions_workflow_id', 'executions', ['workflow_id'], unique=False)
|
||
op.create_index('ix_executions_agent_id', 'executions', ['agent_id'], unique=False)
|
||
op.create_index('ix_executions_status', 'executions', ['status'], unique=False)
|
||
|
||
# 创建执行日志表
|
||
op.create_table(
|
||
'execution_logs',
|
||
sa.Column('id', mysql.CHAR(length=36), nullable=False, comment='日志ID'),
|
||
sa.Column('execution_id', mysql.CHAR(length=36), nullable=False, comment='执行ID'),
|
||
sa.Column('node_id', sa.String(length=100), nullable=True, comment='节点ID'),
|
||
sa.Column('node_type', sa.String(length=50), nullable=True, comment='节点类型'),
|
||
sa.Column('level', sa.String(length=20), nullable=False, comment='日志级别: info/warn/error/debug'),
|
||
sa.Column('message', sa.Text(), nullable=False, comment='日志消息'),
|
||
sa.Column('timestamp', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True, comment='时间戳'),
|
||
sa.Column('duration_ms', sa.Integer(), nullable=True, comment='执行时长(毫秒)'),
|
||
sa.Column('input_data', sa.JSON(), nullable=True, comment='输入数据'),
|
||
sa.Column('output_data', sa.JSON(), nullable=True, comment='输出数据'),
|
||
sa.Column('error_message', sa.Text(), nullable=True, comment='错误信息'),
|
||
sa.Column('additional_data', sa.JSON(), nullable=True, comment='附加数据'),
|
||
sa.ForeignKeyConstraint(['execution_id'], ['executions.id'], ondelete='CASCADE'),
|
||
sa.PrimaryKeyConstraint('id'),
|
||
mysql_charset='utf8mb4',
|
||
mysql_collate='utf8mb4_unicode_ci'
|
||
)
|
||
op.create_index('ix_execution_logs_execution_id', 'execution_logs', ['execution_id'], unique=False)
|
||
op.create_index('ix_execution_logs_node_id', 'execution_logs', ['node_id'], unique=False)
|
||
op.create_index('ix_execution_logs_level', 'execution_logs', ['level'], unique=False)
|
||
|
||
# 创建模型配置表
|
||
op.create_table(
|
||
'model_configs',
|
||
sa.Column('id', mysql.CHAR(length=36), nullable=False, comment='配置ID'),
|
||
sa.Column('name', sa.String(length=100), nullable=False, comment='配置名称'),
|
||
sa.Column('provider', sa.String(length=50), nullable=False, comment='提供商: openai/claude/local'),
|
||
sa.Column('model_name', sa.String(length=100), nullable=False, comment='模型名称'),
|
||
sa.Column('api_key', sa.String(length=500), nullable=False, comment='API密钥(加密存储)'),
|
||
sa.Column('base_url', sa.String(length=255), nullable=True, comment='API地址'),
|
||
sa.Column('user_id', mysql.CHAR(length=36), nullable=True, comment='所属用户ID'),
|
||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True, comment='创建时间'),
|
||
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'), nullable=True, comment='更新时间'),
|
||
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
|
||
sa.PrimaryKeyConstraint('id'),
|
||
mysql_charset='utf8mb4',
|
||
mysql_collate='utf8mb4_unicode_ci'
|
||
)
|
||
op.create_index('ix_model_configs_user_id', 'model_configs', ['user_id'], unique=False)
|
||
|
||
# 创建数据源表
|
||
op.create_table(
|
||
'data_sources',
|
||
sa.Column('id', mysql.CHAR(length=36), nullable=False, comment='数据源ID'),
|
||
sa.Column('name', sa.String(length=100), nullable=False, comment='数据源名称'),
|
||
sa.Column('type', sa.String(length=50), nullable=False, comment='数据源类型: mysql/postgresql/mongodb/redis/csv/json/api/s3'),
|
||
sa.Column('description', sa.Text(), nullable=True, comment='描述'),
|
||
sa.Column('config', sa.JSON(), nullable=False, comment='连接配置(加密存储敏感信息)'),
|
||
sa.Column('status', sa.String(length=20), server_default='active', nullable=True, comment='状态: active/inactive/error'),
|
||
sa.Column('user_id', mysql.CHAR(length=36), nullable=False, comment='创建者ID'),
|
||
sa.Column('last_connected_at', sa.DateTime(), nullable=True, comment='最后连接时间'),
|
||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=True, comment='创建时间'),
|
||
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'), nullable=True, comment='更新时间'),
|
||
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
|
||
sa.PrimaryKeyConstraint('id'),
|
||
mysql_charset='utf8mb4',
|
||
mysql_collate='utf8mb4_unicode_ci'
|
||
)
|
||
op.create_index('ix_data_sources_user_id', 'data_sources', ['user_id'], unique=False)
|
||
op.create_index('ix_data_sources_type', 'data_sources', ['type'], unique=False)
|
||
op.create_index('ix_data_sources_status', 'data_sources', ['status'], unique=False)
|
||
|
||
|
||
def downgrade() -> None:
|
||
# 删除所有表(按依赖关系逆序)
|
||
op.drop_index('ix_data_sources_status', table_name='data_sources')
|
||
op.drop_index('ix_data_sources_type', table_name='data_sources')
|
||
op.drop_index('ix_data_sources_user_id', table_name='data_sources')
|
||
op.drop_table('data_sources')
|
||
|
||
op.drop_index('ix_model_configs_user_id', table_name='model_configs')
|
||
op.drop_table('model_configs')
|
||
|
||
op.drop_index('ix_execution_logs_level', table_name='execution_logs')
|
||
op.drop_index('ix_execution_logs_node_id', table_name='execution_logs')
|
||
op.drop_index('ix_execution_logs_execution_id', table_name='execution_logs')
|
||
op.drop_table('execution_logs')
|
||
|
||
op.drop_index('ix_executions_status', table_name='executions')
|
||
op.drop_index('ix_executions_agent_id', table_name='executions')
|
||
op.drop_index('ix_executions_workflow_id', table_name='executions')
|
||
op.drop_table('executions')
|
||
|
||
op.drop_index('ix_agents_user_id', table_name='agents')
|
||
op.drop_table('agents')
|
||
|
||
op.drop_index('ix_workflow_versions_workflow_id', table_name='workflow_versions')
|
||
op.drop_table('workflow_versions')
|
||
|
||
op.drop_index('ix_workflows_user_id', table_name='workflows')
|
||
op.drop_table('workflows')
|
||
|
||
op.drop_table('users')
|