feat: migrate configuration to .env environment variables
This commit implements a complete migration from JSON-based configuration to .env environment variables, providing better security and flexibility. Key Changes: - Add python-dotenv dependency for environment variable support - Create config/env_loader.py with type conversion utilities - Add from_env() class methods to all config dataclasses - Update ConfigLoader to prioritize environment variables - Add save_to_env() method for .env file management - Implement database connection factory pattern - Add base DAO and connection classes for better abstraction - Support both SQL Server and MySQL with unified interface - Create migration script (scripts/migrate_to_env.py) - Update GUI to read/write .env files - Add comprehensive migration documentation New Files: - config/env_loader.py - Environment variable loader - db/base_connection.py - Base database connection interface - db/base_dao.py - Base DAO with common utilities - db/connection_factory.py - Factory for creating connections - db/mysql_connection.py - MySQL-specific connection - db/sqlserver_connection.py - SQL Server-specific connection - db/table_name_converter.py - SQL dialect converter - scripts/migrate_to_env.py - Configuration migration tool - docs/ENV_MIGRATION.md - Complete migration guide - .env.example - Environment variable template Testing: - Verified MySQL connection (8.0.44) - Tested all DAO operations - Confirmed 150 tables accessible - Validated configuration loading Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
140
db/table_name_converter.py
Normal file
140
db/table_name_converter.py
Normal file
@@ -0,0 +1,140 @@
|
||||
"""
|
||||
表名转换工具
|
||||
|
||||
处理 SQL Server 和 MySQL 之间的表名格式转换
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import List
|
||||
|
||||
|
||||
class TableNameConverter:
|
||||
"""表名转换工具类"""
|
||||
|
||||
# 匹配 SQL Server 表名格式:[schema].[tablename] 或 [schema].[table name]
|
||||
SQLSERVER_PATTERN = re.compile(r'\[([^\]]+)\]\.\[([^\]]+)\]')
|
||||
|
||||
@staticmethod
|
||||
def to_mysql(table_name: str) -> str:
|
||||
"""
|
||||
将 SQL Server 表名格式转换为 MySQL 格式
|
||||
|
||||
SQL Server: [schema].[tablename] → MySQL: schema_tablename
|
||||
SQL Server: tablename → MySQL: dbo_tablename (默认 dbo)
|
||||
|
||||
Args:
|
||||
table_name: SQL Server 格式的表名
|
||||
|
||||
Returns:
|
||||
MySQL 格式的表名
|
||||
|
||||
Examples:
|
||||
>>> TableNameConverter.to_mysql('[dbo].[BIPUsers]')
|
||||
'dbo_BIPUsers'
|
||||
>>> TableNameConverter.to_mysql('DiscreteMaterialPlanData')
|
||||
'dbo_DiscreteMaterialPlanData'
|
||||
>>> TableNameConverter.to_mysql('[productionContractData].[26年压力表合同数据]')
|
||||
'productionContractData_26年压力表合同数据'
|
||||
"""
|
||||
# 尝试匹配 [schema].[tablename] 格式
|
||||
match = TableNameConverter.SQLSERVER_PATTERN.match(table_name.strip())
|
||||
if match:
|
||||
schema = match.group(1)
|
||||
table = match.group(2)
|
||||
return f"{schema}_{table}"
|
||||
|
||||
# 如果没有匹配到,使用默认 schema dbo
|
||||
return f"dbo_{table_name}"
|
||||
|
||||
@staticmethod
|
||||
def to_sqlserver(table_name: str) -> str:
|
||||
"""
|
||||
将 MySQL 表名格式转换为 SQL Server 格式
|
||||
|
||||
MySQL: schema_tablename → SQL Server: [schema].[tablename]
|
||||
|
||||
Args:
|
||||
table_name: MySQL 格式的表名
|
||||
|
||||
Returns:
|
||||
SQL Server 格式的表名
|
||||
|
||||
Examples:
|
||||
>>> TableNameConverter.to_sqlserver('dbo_BIPUsers')
|
||||
'[dbo].[BIPUsers]'
|
||||
>>> TableNameConverter.to_sqlserver('productionContractData_26年压力表合同数据')
|
||||
'[productionContractData].[26年压力表合同数据]'
|
||||
"""
|
||||
# 分割第一个下划线
|
||||
parts = table_name.split('_', 1)
|
||||
if len(parts) == 2:
|
||||
schema = parts[0]
|
||||
table = parts[1]
|
||||
return f"[{schema}].[{table}]"
|
||||
|
||||
# 如果没有下划线,使用默认 schema dbo
|
||||
return f"[dbo].[{table_name}]"
|
||||
|
||||
@staticmethod
|
||||
def convert_sql(sql: str, db_type: str) -> str:
|
||||
"""
|
||||
批量转换 SQL 语句中的表名
|
||||
|
||||
Args:
|
||||
sql: SQL 语句
|
||||
db_type: 目标数据库类型 ('sqlserver' 或 'mysql')
|
||||
|
||||
Returns:
|
||||
转换后的 SQL 语句
|
||||
|
||||
Examples:
|
||||
>>> sql = "SELECT * FROM [dbo].[BIPUsers] WHERE ID = ?"
|
||||
>>> TableNameConverter.convert_sql(sql, 'mysql')
|
||||
'SELECT * FROM dbo_BIPUsers WHERE ID = ?'
|
||||
"""
|
||||
if db_type == 'mysql':
|
||||
# SQL Server → MySQL
|
||||
def replace_to_mysql(match):
|
||||
schema = match.group(1)
|
||||
table = match.group(2)
|
||||
return f"{schema}_{table}"
|
||||
result = TableNameConverter.SQLSERVER_PATTERN.sub(replace_to_mysql, sql)
|
||||
return result
|
||||
elif db_type == 'sqlserver':
|
||||
# MySQL → SQL Server
|
||||
# 首先查找可能的 MySQL 格式表名(schema_table 格式)
|
||||
# 这是一个简化版本,可能无法处理所有边缘情况
|
||||
result = sql
|
||||
# 查找单词字符_单词字符 的模式(可能是表名)
|
||||
mysql_pattern = re.compile(r'\b([a-zA-Z_][a-zA-Z0-9_]*)_([a-zA-Z0-9_\u4e00-\u9fff]+)\b')
|
||||
matches = mysql_pattern.findall(result)
|
||||
for schema, table in set(matches):
|
||||
mysql_name = f"{schema}_{table}"
|
||||
sqlserver_name = f"[{schema}].[{table}]"
|
||||
result = result.replace(mysql_name, sqlserver_name)
|
||||
return result
|
||||
return sql
|
||||
|
||||
@staticmethod
|
||||
def extract_table_names(sql: str) -> List[str]:
|
||||
"""
|
||||
从 SQL 语句中提取所有表名
|
||||
|
||||
Args:
|
||||
sql: SQL 语句
|
||||
|
||||
Returns:
|
||||
表名列表
|
||||
"""
|
||||
tables = []
|
||||
# 查找 SQL Server 格式
|
||||
sqlserver_matches = TableNameConverter.SQLSERVER_PATTERN.findall(sql)
|
||||
for schema, table in sqlserver_matches:
|
||||
tables.append(f"{schema}_{table}")
|
||||
|
||||
# 查找可能的 MySQL 格式
|
||||
mysql_pattern = re.compile(r'\b[a-zA-Z_][a-zA-Z0-9_]*_[a-zA-Z0-9_]+\b')
|
||||
mysql_matches = mysql_pattern.findall(sql)
|
||||
tables.extend(mysql_matches)
|
||||
|
||||
return list(set(tables))
|
||||
Reference in New Issue
Block a user