Skip to content

Commit a29b018

Browse files
committed
feat: Implement MySQL-optimized BIGINT conversion for ID columns in migration
1 parent e556179 commit a29b018

File tree

1 file changed

+60
-1
lines changed

1 file changed

+60
-1
lines changed

app/db/migrations/versions/4f15c0789493_use_bigint_for_id_column.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def _upgrade_mysql() -> None:
7272
op.drop_constraint(fk['name'], table_name, type_='foreignkey')
7373

7474
# Step 2: Alter columns to BIGINT
75-
_alter_columns_to_bigint()
75+
_alter_columns_to_bigint_mysql()
7676

7777
# Step 3: Recreate FKs
7878
for table_name, fks in fk_info.items():
@@ -90,6 +90,65 @@ def _upgrade_postgresql() -> None:
9090
_alter_columns_to_bigint()
9191

9292

93+
def _is_bigint_type(sqlalchemy_type) -> bool:
94+
"""Check if a reflected SQLAlchemy type is BIGINT."""
95+
return "BIGINT" in str(sqlalchemy_type).upper()
96+
97+
98+
def _alter_columns_to_bigint_mysql():
99+
"""MySQL-optimized BIGINT conversion.
100+
101+
Combine changes per table to reduce table rebuilds and skip columns
102+
that are already BIGINT (resume-friendly after interrupted runs).
103+
"""
104+
bind = op.get_bind()
105+
inspector = inspect(bind)
106+
107+
# Avoid waiting for a very long default metadata-lock timeout.
108+
op.execute(sa.text("SET SESSION lock_wait_timeout = 120"))
109+
110+
table_specs = [
111+
('admins', [('id', False, True)]),
112+
('core_configs', [('id', False, True)]),
113+
('groups', [('id', False, True)]),
114+
('hosts', [('id', False, True)]),
115+
('inbounds', [('id', False, True)]),
116+
('user_templates', [('id', False, True)]),
117+
('settings', [('id', False, True)]),
118+
('system', [('id', False, True)]),
119+
('nodes', [('id', False, True), ('core_config_id', True, False)]),
120+
('users', [('id', False, True), ('admin_id', True, False)]),
121+
('admin_usage_logs', [('id', False, True), ('admin_id', False, False)]),
122+
('node_stats', [('id', False, True), ('node_id', False, False)]),
123+
('node_usages', [('id', False, True), ('node_id', True, False)]),
124+
('node_user_usages', [('id', False, True), ('user_id', False, False), ('node_id', True, False)]),
125+
('node_usage_reset_logs', [('id', False, True), ('node_id', False, False)]),
126+
('notification_reminders', [('id', False, True), ('user_id', False, False)]),
127+
('user_usage_logs', [('id', False, True), ('user_id', True, False)]),
128+
('user_subscription_updates', [('id', False, True), ('user_id', False, False)]),
129+
('next_plans', [('id', False, True), ('user_id', False, False), ('user_template_id', True, False)]),
130+
('inbounds_groups_association', [('inbound_id', False, False), ('group_id', False, False)]),
131+
('users_groups_association', [('user_id', False, False), ('groups_id', False, False)]),
132+
('template_group_association', [('user_template_id', True, False), ('group_id', True, False)]),
133+
]
134+
135+
for table_name, columns in table_specs:
136+
reflected_columns = {column['name']: column for column in inspector.get_columns(table_name)}
137+
alter_clauses = []
138+
for column_name, nullable, autoincrement in columns:
139+
reflected = reflected_columns.get(column_name)
140+
if reflected and _is_bigint_type(reflected['type']):
141+
continue
142+
143+
clause = f"MODIFY COLUMN `{column_name}` BIGINT {'NULL' if nullable else 'NOT NULL'}"
144+
if autoincrement:
145+
clause += " AUTO_INCREMENT"
146+
alter_clauses.append(clause)
147+
148+
if alter_clauses:
149+
op.execute(sa.text(f"ALTER TABLE `{table_name}` {', '.join(alter_clauses)}"))
150+
151+
93152
def _alter_columns_to_bigint():
94153
"""Alter all ID columns from INTEGER to BIGINT"""
95154
# Parent tables - all primary keys are NOT NULL with autoincrement

0 commit comments

Comments
 (0)