Files
playwrite/db/materials_to_be_deleted_dao.py
Misaka aaa46ef282 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>
2026-02-09 22:39:14 +08:00

482 lines
15 KiB
Python

"""
Data Access Object for MaterialsTypeToBeDeleted table.
This module provides CRUD operations for the MaterialsTypeToBeDeleted table,
which tracks materials that need to be deleted by their managers.
"""
from typing import List, Dict, Any, Tuple, Optional
from db.base_dao import BaseDAO
from db.connection import get_connection
from config.schema import DatabaseType
class MaterialsTypeToBeDeletedDAO(BaseDAO):
"""Data Access Object for MaterialsTypeToBeDeleted table CRUD operations"""
# ==================== CREATE ====================
def insert_material(
self, material_name: str, manager_name: str
) -> bool:
"""
Insert a single material record.
Args:
material_name: Material name
manager_name: Manager name
Returns:
True if successful, False otherwise
"""
table_name = self._convert_sql('[dbo].[MaterialsTypeToBeDeleted]')
placeholder = self._get_placeholder()
# 根据数据库类型选择列名格式
if self._db_type == DatabaseType.MYSQL:
sql = f"""
INSERT INTO {table_name} (MaterialName, ManagerName)
VALUES ({placeholder}, {placeholder})
"""
else:
sql = f"""
INSERT INTO {table_name} ([MaterialName], [ManagerName])
VALUES ({placeholder}, {placeholder})
"""
try:
with get_connection() as db:
db.execute_update(sql, (material_name, manager_name))
return True
except Exception as e:
print(f"Error inserting material: {e}")
return False
def insert_batch(self, materials: List[Tuple[str, str]]) -> int:
"""
Insert multiple material records in batch.
Args:
materials: List of tuples (material_name, manager_name)
Returns:
Number of records inserted
"""
if not materials:
return 0
table_name = self._convert_sql('[dbo].[MaterialsTypeToBeDeleted]')
placeholder = self._get_placeholder()
# 根据数据库类型选择列名格式
if self._db_type == DatabaseType.MYSQL:
sql = f"""
INSERT INTO {table_name} (MaterialName, ManagerName)
VALUES ({placeholder}, {placeholder})
"""
else:
sql = f"""
INSERT INTO {table_name} ([MaterialName], [ManagerName])
VALUES ({placeholder}, {placeholder})
"""
inserted_count = 0
try:
with get_connection() as db:
for material_name, manager_name in materials:
db.execute_update(sql, (material_name, manager_name))
inserted_count += 1
return inserted_count
except Exception as e:
print(f"Error inserting batch materials: {e}")
return inserted_count
# ==================== READ ====================
def get_all_materials(self) -> List[Dict[str, Any]]:
"""
Get all material records.
Returns:
List of all materials with MaterialName and ManagerName
"""
table_name = self._convert_sql('[dbo].[MaterialsTypeToBeDeleted]')
# 根据数据库类型选择列名格式
if self._db_type == DatabaseType.MYSQL:
sql = f"""
SELECT MaterialName, ManagerName
FROM {table_name}
WHERE MaterialName IS NOT NULL
ORDER BY ManagerName, MaterialName
"""
else:
sql = f"""
SELECT [MaterialName], [ManagerName]
FROM {table_name}
WHERE [MaterialName] IS NOT NULL
ORDER BY [ManagerName], [MaterialName]
"""
with get_connection() as db:
return db.execute_query(sql)
def get_materials_by_manager(self, manager_name: str) -> List[Dict[str, Any]]:
"""
Get all materials for a specific manager.
Args:
manager_name: Manager name
Returns:
List of materials for the specified manager
"""
table_name = self._convert_sql('[dbo].[MaterialsTypeToBeDeleted]')
placeholder = self._get_placeholder()
# 根据数据库类型选择列名格式
if self._db_type == DatabaseType.MYSQL:
sql = f"""
SELECT MaterialName, ManagerName
FROM {table_name}
WHERE ManagerName = {placeholder} AND MaterialName IS NOT NULL
ORDER BY MaterialName
"""
else:
sql = f"""
SELECT [MaterialName], [ManagerName]
FROM {table_name}
WHERE [ManagerName] = {placeholder} AND [MaterialName] IS NOT NULL
ORDER BY [MaterialName]
"""
with get_connection() as db:
return db.execute_query(sql, (manager_name,))
def get_managers(self) -> List[str]:
"""
Get list of unique manager names.
Returns:
List of unique manager names
"""
table_name = self._convert_sql('[dbo].[MaterialsTypeToBeDeleted]')
# 根据数据库类型选择列名格式
if self._db_type == DatabaseType.MYSQL:
sql = f"""
SELECT DISTINCT ManagerName
FROM {table_name}
WHERE ManagerName IS NOT NULL
ORDER BY ManagerName
"""
else:
sql = f"""
SELECT DISTINCT [ManagerName]
FROM {table_name}
WHERE [ManagerName] IS NOT NULL
ORDER BY [ManagerName]
"""
with get_connection() as db:
results = db.execute_query(sql)
return [r['ManagerName'] for r in results if r.get('ManagerName')]
def get_material_names_by_manager(self, manager_name: str) -> List[str]:
"""
Get material names for a specific manager.
Args:
manager_name: Manager name
Returns:
List of material names for the specified manager
"""
results = self.get_materials_by_manager(manager_name)
return [r['MaterialName'] for r in results if r.get('MaterialName')]
# ==================== UPDATE ====================
def update_manager(
self,
material_name: str,
old_manager: str,
new_manager: str
) -> bool:
"""
Update manager for a specific material.
Args:
material_name: Material name
old_manager: Current manager name
new_manager: New manager name
Returns:
True if successful, False otherwise
"""
table_name = self._convert_sql('[dbo].[MaterialsTypeToBeDeleted]')
placeholder = self._get_placeholder()
# 根据数据库类型选择列名格式
if self._db_type == DatabaseType.MYSQL:
sql = f"""
UPDATE {table_name}
SET ManagerName = {placeholder}
WHERE MaterialName = {placeholder} AND ManagerName = {placeholder}
"""
else:
sql = f"""
UPDATE {table_name}
SET [ManagerName] = {placeholder}
WHERE [MaterialName] = {placeholder} AND [ManagerName] = {placeholder}
"""
try:
with get_connection() as db:
affected = db.execute_update(sql, (new_manager, material_name, old_manager))
return affected > 0
except Exception as e:
print(f"Error updating manager: {e}")
return False
# ==================== DELETE ====================
def delete_material(
self,
material_name: str,
manager_name: str
) -> bool:
"""
Delete a specific material record.
Args:
material_name: Material name
manager_name: Manager name
Returns:
True if successful, False otherwise
"""
table_name = self._convert_sql('[dbo].[MaterialsTypeToBeDeleted]')
placeholder = self._get_placeholder()
# 根据数据库类型选择列名格式
if self._db_type == DatabaseType.MYSQL:
sql = f"""
DELETE FROM {table_name}
WHERE MaterialName = {placeholder} AND ManagerName = {placeholder}
"""
else:
sql = f"""
DELETE FROM {table_name}
WHERE [MaterialName] = {placeholder} AND [ManagerName] = {placeholder}
"""
try:
with get_connection() as db:
affected = db.execute_update(sql, (material_name, manager_name))
return affected > 0
except Exception as e:
print(f"Error deleting material: {e}")
return False
def delete_by_manager(self, manager_name: str) -> int:
"""
Delete all materials for a specific manager.
Args:
manager_name: Manager name
Returns:
Number of records deleted
"""
table_name = self._convert_sql('[dbo].[MaterialsTypeToBeDeleted]')
placeholder = self._get_placeholder()
# 根据数据库类型选择列名格式
if self._db_type == DatabaseType.MYSQL:
sql = f"""
DELETE FROM {table_name}
WHERE ManagerName = {placeholder}
"""
else:
sql = f"""
DELETE FROM {table_name}
WHERE [ManagerName] = {placeholder}
"""
try:
with get_connection() as db:
return db.execute_update(sql, (manager_name,))
except Exception as e:
print(f"Error deleting by manager: {e}")
return 0
def delete_all_materials(self) -> int:
"""
Delete all material records.
Returns:
Number of records deleted
"""
table_name = self._convert_sql('[dbo].[MaterialsTypeToBeDeleted]')
sql = f"DELETE FROM {table_name}"
try:
with get_connection() as db:
return db.execute_update(sql)
except Exception as e:
print(f"Error deleting all materials: {e}")
return 0
# ==================== UTILITIES ====================
def material_exists(self, material_name: str) -> bool:
"""
Check if a material exists in the table.
Args:
material_name: Material name
Returns:
True if material exists, False otherwise
"""
table_name = self._convert_sql('[dbo].[MaterialsTypeToBeDeleted]')
placeholder = self._get_placeholder()
# 根据数据库类型选择列名格式
if self._db_type == DatabaseType.MYSQL:
sql = f"""
SELECT COUNT(*) as count
FROM {table_name}
WHERE MaterialName = {placeholder}
"""
else:
sql = f"""
SELECT COUNT(*) as count
FROM {table_name}
WHERE [MaterialName] = {placeholder}
"""
with get_connection() as db:
result = db.execute_query(sql, (material_name,))
return result[0]['count'] > 0 if result else False
def count_by_manager(self, manager_name: str) -> int:
"""
Count materials for a specific manager.
Args:
manager_name: Manager name
Returns:
Number of materials for the manager
"""
table_name = self._convert_sql('[dbo].[MaterialsTypeToBeDeleted]')
placeholder = self._get_placeholder()
# 根据数据库类型选择列名格式
if self._db_type == DatabaseType.MYSQL:
sql = f"""
SELECT COUNT(*) as count
FROM {table_name}
WHERE ManagerName = {placeholder}
"""
else:
sql = f"""
SELECT COUNT(*) as count
FROM {table_name}
WHERE [ManagerName] = {placeholder}
"""
with get_connection() as db:
result = db.execute_query(sql, (manager_name,))
return result[0]['count'] if result else 0
def get_statistics(self) -> Dict[str, Any]:
"""
Get comprehensive statistics about the data.
Returns:
Dictionary with statistics including total materials,
unique managers, and materials per manager
"""
table_name = self._convert_sql('[dbo].[MaterialsTypeToBeDeleted]')
# 根据数据库类型选择列名格式
if self._db_type == DatabaseType.MYSQL:
sql = f"""
SELECT
COUNT(*) as total_materials,
COUNT(DISTINCT ManagerName) as unique_managers
FROM {table_name}
WHERE MaterialName IS NOT NULL
"""
manager_sql = f"""
SELECT ManagerName, COUNT(*) as count
FROM {table_name}
WHERE ManagerName IS NOT NULL
GROUP BY ManagerName
ORDER BY count DESC
"""
else:
sql = f"""
SELECT
COUNT(*) as total_materials,
COUNT(DISTINCT ManagerName) as unique_managers
FROM {table_name}
WHERE [MaterialName] IS NOT NULL
"""
manager_sql = f"""
SELECT [ManagerName], COUNT(*) as count
FROM {table_name}
WHERE [ManagerName] IS NOT NULL
GROUP BY [ManagerName]
ORDER BY count DESC
"""
with get_connection() as db:
result = db.execute_query(sql)
stats = result[0] if result else {}
# Get materials per manager
manager_results = db.execute_query(manager_sql)
stats['materials_per_manager'] = [
{r['ManagerName']: r['count']} for r in manager_results
]
return stats
def search_materials(self, keyword: str) -> List[Dict[str, Any]]:
"""
Search materials by keyword (partial match).
Args:
keyword: Keyword to search for
Returns:
List of matching materials
"""
table_name = self._convert_sql('[dbo].[MaterialsTypeToBeDeleted]')
placeholder = self._get_placeholder()
# 根据数据库类型选择列名格式
if self._db_type == DatabaseType.MYSQL:
sql = f"""
SELECT MaterialName, ManagerName
FROM {table_name}
WHERE MaterialName LIKE {placeholder}
ORDER BY ManagerName, MaterialName
"""
else:
sql = f"""
SELECT [MaterialName], [ManagerName]
FROM {table_name}
WHERE [MaterialName] LIKE {placeholder}
ORDER BY [ManagerName], [MaterialName]
"""
with get_connection() as db:
return db.execute_query(sql, (f'%{keyword}%',))