Merge pull request #4820 from DDS-Derek/dev

This commit is contained in:
jxxghp
2025-08-23 18:46:52 +08:00
committed by GitHub
11 changed files with 154 additions and 66 deletions
+5 -1
View File
@@ -21,7 +21,11 @@ depends_on = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
# 站点数据统计增加站点名称 # 站点数据统计增加站点名称
with contextlib.suppress(Exception): conn = op.get_bind()
inspector = sa.inspect(conn)
columns = inspector.get_columns('siteuserdata')
# 检查 'name' 字段是否已存在
if not any(c['name'] == 'name' for c in columns):
op.add_column('siteuserdata', sa.Column('name', sa.String(), nullable=True)) op.add_column('siteuserdata', sa.Column('name', sa.String(), nullable=True))
# ### end Alembic commands ### # ### end Alembic commands ###
+7 -8
View File
@@ -18,19 +18,18 @@ depends_on = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### conn = op.get_bind()
with contextlib.suppress(Exception): inspector = sa.inspect(conn)
# 添加触发类型字段 columns = inspector.get_columns('workflow')
if not any(c['name'] == 'trigger_type' for c in columns):
op.add_column('workflow', sa.Column('trigger_type', sa.String(), nullable=True, default='timer')) op.add_column('workflow', sa.Column('trigger_type', sa.String(), nullable=True, default='timer'))
with contextlib.suppress(Exception): if not any(c['name'] == 'event_type' for c in columns):
# 添加事件类型字段
op.add_column('workflow', sa.Column('event_type', sa.String(), nullable=True)) op.add_column('workflow', sa.Column('event_type', sa.String(), nullable=True))
with contextlib.suppress(Exception): if not any(c['name'] == 'event_conditions' for c in columns):
# 添加事件条件字段
op.add_column('workflow', sa.Column('event_conditions', sa.JSON(), nullable=True, default={})) op.add_column('workflow', sa.Column('event_conditions', sa.JSON(), nullable=True, default={}))
# ### end Alembic commands ###
def downgrade() -> None: def downgrade() -> None:
+18 -3
View File
@@ -19,13 +19,28 @@ depends_on = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### conn = op.get_bind()
with contextlib.suppress(Exception): inspector = sa.inspect(conn)
# 检查并添加 downloadhistory.episode_group
dh_columns = inspector.get_columns('downloadhistory')
if not any(c['name'] == 'episode_group' for c in dh_columns):
op.add_column('downloadhistory', sa.Column('episode_group', sa.String, nullable=True)) op.add_column('downloadhistory', sa.Column('episode_group', sa.String, nullable=True))
# 检查并添加 subscribe.episode_group
s_columns = inspector.get_columns('subscribe')
if not any(c['name'] == 'episode_group' for c in s_columns):
op.add_column('subscribe', sa.Column('episode_group', sa.String, nullable=True)) op.add_column('subscribe', sa.Column('episode_group', sa.String, nullable=True))
# 检查并添加 subscribehistory.episode_group
sh_columns = inspector.get_columns('subscribehistory')
if not any(c['name'] == 'episode_group' for c in sh_columns):
op.add_column('subscribehistory', sa.Column('episode_group', sa.String, nullable=True)) op.add_column('subscribehistory', sa.Column('episode_group', sa.String, nullable=True))
# 检查并添加 transferhistory.episode_group
th_columns = inspector.get_columns('transferhistory')
if not any(c['name'] == 'episode_group' for c in th_columns):
op.add_column('transferhistory', sa.Column('episode_group', sa.String, nullable=True)) op.add_column('transferhistory', sa.Column('episode_group', sa.String, nullable=True))
# ### end Alembic commands ###
def downgrade() -> None: def downgrade() -> None:
+4 -4
View File
@@ -18,11 +18,11 @@ depends_on = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### conn = op.get_bind()
# 整理历史记录 增加下载器字段 inspector = sa.inspect(conn)
with contextlib.suppress(Exception): columns = inspector.get_columns('transferhistory')
if not any(c['name'] == 'downloader' for c in columns):
op.add_column('transferhistory', sa.Column('downloader', sa.String(), nullable=True)) op.add_column('transferhistory', sa.Column('downloader', sa.String(), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None: def downgrade() -> None:
+10 -9
View File
@@ -8,6 +8,7 @@ Create Date: 2025-08-19 12:27:08.451371
import sqlalchemy as sa import sqlalchemy as sa
from alembic import op from alembic import op
from app.log import logger
from app.core.config import settings from app.core.config import settings
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -41,7 +42,7 @@ def fix_postgresql_sequences():
""")) """))
tables = [row[0] for row in result.fetchall()] tables = [row[0] for row in result.fetchall()]
print(f"发现 {len(tables)} 个表需要检查序列") logger.info(f"发现 {len(tables)} 个表需要检查序列")
for table_name in tables: for table_name in tables:
fix_table_sequence(connection, table_name) fix_table_sequence(connection, table_name)
@@ -54,7 +55,7 @@ def fix_table_sequence(connection, table_name):
try: try:
# 跳过alembic_version表,它没有id列 # 跳过alembic_version表,它没有id列
if table_name == 'alembic_version': if table_name == 'alembic_version':
print(f"跳过表 {table_name},这是Alembic版本表") logger.debug(f"跳过表 {table_name},这是Alembic版本表")
return return
# 检查表是否有id列 # 检查表是否有id列
@@ -67,22 +68,22 @@ def fix_table_sequence(connection, table_name):
id_column = result.fetchone() id_column = result.fetchone()
if not id_column: if not id_column:
print(f"{table_name} 没有id列,跳过") logger.debug(f"{table_name} 没有id列,跳过")
return return
is_identity, column_default = id_column is_identity, column_default = id_column
# 检查是否已经是Identity类型 # 检查是否已经是Identity类型
if is_identity == 'YES' or (column_default and 'GENERATED BY DEFAULT AS IDENTITY' in column_default): if is_identity == 'YES' or (column_default and 'GENERATED BY DEFAULT AS IDENTITY' in column_default):
print(f"{table_name} 的id列已经是Identity类型,跳过") logger.debug(f"{table_name} 的id列已经是Identity类型,跳过")
return return
# 检查是否有序列 # 检查是否有序列
print(f"{table_name} 存在序列,需要修复") logger.info(f"{table_name} 存在序列,需要修复")
convert_to_identity(connection, table_name) convert_to_identity(connection, table_name)
except Exception as e: except Exception as e:
print(f"修复表 {table_name} 序列时出错: {e}") logger.error(f"修复表 {table_name} 序列时出错: {e}")
# 回滚当前事务,避免影响后续操作 # 回滚当前事务,避免影响后续操作
connection.rollback() connection.rollback()
@@ -106,12 +107,12 @@ def convert_to_identity(connection, table_name):
ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY (START WITH {next_value}) ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY (START WITH {next_value})
""")) """))
print(f"{table_name} 序列已转换为Identity,起始值为 {next_value}") logger.info(f"{table_name} 序列已转换为Identity,起始值为 {next_value}")
except Exception as e: except Exception as e:
print(f"转换表 {table_name} 序列时出错: {e}")
# 如果是已经存在的Identity错误,则忽略 # 如果是已经存在的Identity错误,则忽略
if "already an identity column" in str(e): if "already an identity column" in str(e):
print(f"{table_name} 的id列已经是Identity类型,忽略此错误") logger.warn(f"{table_name} 的id列已经是Identity类型,忽略此错误: {e}")
return return
logger.error(f"转换表 {table_name} 序列时出错: {e}")
raise raise
+4 -3
View File
@@ -19,10 +19,11 @@ depends_on = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### conn = op.get_bind()
with contextlib.suppress(Exception): inspector = sa.inspect(conn)
columns = inspector.get_columns('workflow')
if not any(c['name'] == 'flows' for c in columns):
op.add_column('workflow', sa.Column('flows', sa.JSON(), nullable=True)) op.add_column('workflow', sa.Column('flows', sa.JSON(), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None: def downgrade() -> None:
+4 -4
View File
@@ -18,11 +18,11 @@ depends_on = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### conn = op.get_bind()
# 下载历史记录 增加下载器字段 inspector = sa.inspect(conn)
with contextlib.suppress(Exception): columns = inspector.get_columns('downloadhistory')
if not any(c['name'] == 'downloader' for c in columns):
op.add_column('downloadhistory', sa.Column('downloader', sa.String(), nullable=True)) op.add_column('downloadhistory', sa.Column('downloader', sa.String(), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None: def downgrade() -> None:
+14 -4
View File
@@ -18,13 +18,23 @@ depends_on = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### conn = op.get_bind()
# 订阅增加mediaid inspector = sa.inspect(conn)
with contextlib.suppress(Exception):
# 检查并添加 subscribe.mediaid
s_columns = inspector.get_columns('subscribe')
if not any(c['name'] == 'mediaid' for c in s_columns):
op.add_column('subscribe', sa.Column('mediaid', sa.String(), nullable=True)) op.add_column('subscribe', sa.Column('mediaid', sa.String(), nullable=True))
# 检查并创建索引
s_indexes = inspector.get_indexes('subscribe')
if not any(i['name'] == 'ix_subscribe_mediaid' for i in s_indexes):
op.create_index('ix_subscribe_mediaid', 'subscribe', ['mediaid'], unique=False) op.create_index('ix_subscribe_mediaid', 'subscribe', ['mediaid'], unique=False)
# 检查并添加 subscribehistory.mediaid
sh_columns = inspector.get_columns('subscribehistory')
if not any(c['name'] == 'mediaid' for c in sh_columns):
op.add_column('subscribehistory', sa.Column('mediaid', sa.String(), nullable=True)) op.add_column('subscribehistory', sa.Column('mediaid', sa.String(), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None: def downgrade() -> None:
+47 -16
View File
@@ -10,6 +10,7 @@ import contextlib
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from app.log import logger
from app.db import SessionFactory from app.db import SessionFactory
from app.db.models import UserConfig from app.db.models import UserConfig
@@ -21,28 +22,58 @@ depends_on = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### conn = op.get_bind()
# 支持订阅自定义媒体类别和过滤规则组、自定义识别词 inspector = sa.inspect(conn)
with contextlib.suppress(Exception):
# 检查并添加 downloadhistory.media_category
dh_columns = inspector.get_columns('downloadhistory')
if not any(c['name'] == 'media_category' for c in dh_columns):
op.add_column('downloadhistory', sa.Column('media_category', sa.String(), nullable=True)) op.add_column('downloadhistory', sa.Column('media_category', sa.String(), nullable=True))
# 检查并添加 subscribe 表的列
sub_columns = inspector.get_columns('subscribe')
if not any(c['name'] == 'custom_words' for c in sub_columns):
op.add_column('subscribe', sa.Column('custom_words', sa.String(), nullable=True)) op.add_column('subscribe', sa.Column('custom_words', sa.String(), nullable=True))
if not any(c['name'] == 'media_category' for c in sub_columns):
op.add_column('subscribe', sa.Column('media_category', sa.String(), nullable=True)) op.add_column('subscribe', sa.Column('media_category', sa.String(), nullable=True))
if not any(c['name'] == 'filter_groups' for c in sub_columns):
op.add_column('subscribe', sa.Column('filter_groups', sa.JSON(), nullable=True)) op.add_column('subscribe', sa.Column('filter_groups', sa.JSON(), nullable=True))
# 将String转换为JSON类型
with contextlib.suppress(Exception): # 定义需要检查和转换的表和列
op.alter_column('subscribe', 'note', existing_type=sa.String(), type_=sa.JSON()) columns_to_alter = {
op.alter_column('downloadhistory', 'note', existing_type=sa.String(), type_=sa.JSON()) 'subscribe': 'note',
op.alter_column('mediaserveritem', 'note', existing_type=sa.String(), type_=sa.JSON()) 'downloadhistory': 'note',
op.alter_column('message', 'note', existing_type=sa.String(), type_=sa.JSON()) 'mediaserveritem': 'note',
op.alter_column('plugindata', 'value', existing_type=sa.String(), type_=sa.JSON()) 'message': 'note',
op.alter_column('site', 'note', existing_type=sa.String(), type_=sa.JSON()) 'plugindata': 'value',
op.alter_column('sitestatistic', 'note', existing_type=sa.String(), type_=sa.JSON()) 'site': 'note',
op.alter_column('systemconfig', 'value', existing_type=sa.String(), type_=sa.JSON()) 'sitestatistic': 'note',
op.alter_column('userconfig', 'value', existing_type=sa.String(), type_=sa.JSON()) 'systemconfig': 'value',
# 清空用户配置表中不兼容的数据 'userconfig': 'value'
}
for table, column_name in columns_to_alter.items():
try:
cols = inspector.get_columns(table)
# 找到对应的列信息
target_col = next((c for c in cols if c['name'] == column_name), None)
# 如果列存在且类型不是JSON,则进行修改
if target_col and not isinstance(target_col['type'], sa.JSON):
# PostgreSQL需要指定USING子句来处理类型转换
if conn.dialect.name == 'postgresql':
op.alter_column(table, column_name,
existing_type=sa.String(),
type_=sa.JSON(),
postgresql_using=f'"{column_name}"::json')
else:
op.alter_column(table, column_name,
existing_type=sa.String(),
type_=sa.JSON())
except Exception as e:
logger.error(f"Could not alter column {column_name} in table {table}: {e}")
with SessionFactory() as db: with SessionFactory() as db:
UserConfig.truncate(db) UserConfig.truncate(db)
# ### end Alembic commands ###
def downgrade() -> None: def downgrade() -> None:
+10 -5
View File
@@ -18,14 +18,19 @@ depends_on = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### conn = op.get_bind()
# 站点管理、订阅增加下载器选项 inspector = sa.inspect(conn)
with contextlib.suppress(Exception):
# 检查并添加 site.downloader
site_columns = inspector.get_columns('site')
if not any(c['name'] == 'downloader' for c in site_columns):
op.add_column('site', sa.Column('downloader', sa.String(), nullable=True)) op.add_column('site', sa.Column('downloader', sa.String(), nullable=True))
# 检查并添加 subscribe.downloader
subscribe_columns = inspector.get_columns('subscribe')
if not any(c['name'] == 'downloader' for c in subscribe_columns):
op.add_column('subscribe', sa.Column('downloader', sa.String(), nullable=True)) op.add_column('subscribe', sa.Column('downloader', sa.String(), nullable=True))
# ### end Alembic commands ###
def downgrade() -> None: def downgrade() -> None:
pass pass
+31 -9
View File
@@ -10,6 +10,8 @@ import contextlib
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from app.log import logger
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'ecf3c693fdf3' revision = 'ecf3c693fdf3'
@@ -19,15 +21,35 @@ depends_on = None
def upgrade() -> None: def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ### conn = op.get_bind()
# 将String转换为JSON类型 inspector = sa.inspect(conn)
with contextlib.suppress(Exception): table_name = 'subscribehistory'
op.alter_column('subscribehistory', 'sites', existing_type=sa.String(), type_=sa.JSON()) columns = inspector.get_columns(table_name)
with contextlib.suppress(Exception):
op.add_column('subscribehistory', sa.Column('custom_words', sa.String(), nullable=True)) try:
op.add_column('subscribehistory', sa.Column('media_category', sa.String(), nullable=True)) sites_col = next((c for c in columns if c['name'] == 'sites'), None)
op.add_column('subscribehistory', sa.Column('filter_groups', sa.JSON(), nullable=True)) # 如果 'sites' 列存在且类型不是 JSON,则进行修改
# ### end Alembic commands ### if sites_col and not isinstance(sites_col['type'], sa.JSON):
if conn.dialect.name == 'postgresql':
op.alter_column(table_name, 'sites',
existing_type=sa.String(),
type_=sa.JSON(),
postgresql_using='sites::json')
else:
op.alter_column(table_name, 'sites',
existing_type=sa.String(),
type_=sa.JSON())
except Exception as e:
logger.error(f"Could not alter column 'sites' in table {table_name}: {e}")
if not any(c['name'] == 'custom_words' for c in columns):
op.add_column(table_name, sa.Column('custom_words', sa.String(), nullable=True))
if not any(c['name'] == 'media_category' for c in columns):
op.add_column(table_name, sa.Column('media_category', sa.String(), nullable=True))
if not any(c['name'] == 'filter_groups' for c in columns):
op.add_column(table_name, sa.Column('filter_groups', sa.JSON(), nullable=True))
def downgrade() -> None: def downgrade() -> None: