数据库迁移 - 添加缺失的列 用于在不删除数据的情况下更新表结构
(self)
| 267 | logger.warning(f"迁移 bind_card_tasks 历史保留结构时出错: {e}") |
| 268 | |
| 269 | def migrate_tables(self): |
| 270 | """ |
| 271 | 数据库迁移 - 添加缺失的列 |
| 272 | 用于在不删除数据的情况下更新表结构 |
| 273 | """ |
| 274 | if not self.database_url.startswith("sqlite"): |
| 275 | logger.info("非 SQLite 数据库,跳过自动迁移") |
| 276 | return |
| 277 | |
| 278 | # 需要检查和添加的新列 |
| 279 | migrations = [ |
| 280 | # (表名, 列名, 列类型) |
| 281 | ("accounts", "cpa_uploaded", "BOOLEAN DEFAULT 0"), |
| 282 | ("accounts", "cpa_uploaded_at", "DATETIME"), |
| 283 | ("accounts", "source", "VARCHAR(20) DEFAULT 'register'"), |
| 284 | ("accounts", "priority", "INTEGER DEFAULT 50"), |
| 285 | ("accounts", "last_used_at", "DATETIME"), |
| 286 | ("accounts", "subscription_type", "VARCHAR(20)"), |
| 287 | ("accounts", "subscription_at", "DATETIME"), |
| 288 | ("accounts", "cookies", "TEXT"), |
| 289 | ("cpa_services", "proxy_url", "VARCHAR(1000)"), |
| 290 | ("sub2api_services", "target_type", "VARCHAR(50) DEFAULT 'sub2api'"), |
| 291 | ("codex2api_services", "admin_key", "TEXT"), |
| 292 | ("proxies", "is_default", "BOOLEAN DEFAULT 0"), |
| 293 | ("bind_card_tasks", "checkout_session_id", "VARCHAR(120)"), |
| 294 | ("bind_card_tasks", "publishable_key", "VARCHAR(255)"), |
| 295 | ("bind_card_tasks", "client_secret", "TEXT"), |
| 296 | ("bind_card_tasks", "bind_mode", "VARCHAR(30) DEFAULT 'semi_auto'"), |
| 297 | ("bind_card_tasks", "account_email", "VARCHAR(255)"), |
| 298 | ] |
| 299 | |
| 300 | # 确保新表存在(create_tables 已处理,此处兜底) |
| 301 | Base.metadata.create_all(bind=self.engine) |
| 302 | |
| 303 | with self.engine.connect() as conn: |
| 304 | # 数据迁移:将旧的 custom_domain 记录统一为 moe_mail |
| 305 | try: |
| 306 | conn.execute(text("UPDATE email_services SET service_type='moe_mail' WHERE service_type='custom_domain'")) |
| 307 | conn.execute(text("UPDATE accounts SET email_service='moe_mail' WHERE email_service='custom_domain'")) |
| 308 | conn.commit() |
| 309 | except Exception as e: |
| 310 | logger.warning(f"迁移 custom_domain -> moe_mail 时出错: {e}") |
| 311 | |
| 312 | for table_name, column_name, column_type in migrations: |
| 313 | try: |
| 314 | # 检查列是否存在 |
| 315 | result = conn.execute(text( |
| 316 | f"SELECT * FROM pragma_table_info('{table_name}') WHERE name='{column_name}'" |
| 317 | )) |
| 318 | if result.fetchone() is None: |
| 319 | # 列不存在,添加它 |
| 320 | logger.info(f"添加列 {table_name}.{column_name}") |
| 321 | conn.execute(text( |
| 322 | f"ALTER TABLE {table_name} ADD COLUMN {column_name} {column_type}" |
| 323 | )) |
| 324 | conn.commit() |
| 325 | logger.info(f"成功添加列 {table_name}.{column_name}") |
| 326 | except Exception as e: |