mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-07 00:16:57 +08:00
Merge pull request #4820 from DDS-Derek/dev
This commit is contained in:
@@ -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 ###
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user