fix(db): 補全 metadata model import 與 realtime sales ORM

ADR-017 Phase 3f-0
This commit is contained in:
OoO
2026-04-29 21:00:46 +08:00
parent 8be332728e
commit f4149d4c05
12 changed files with 314 additions and 27 deletions

View File

@@ -1,5 +1,6 @@
import os
import re
import threading
from sqlalchemy import create_engine, desc, select, text, literal
from sqlalchemy.orm import sessionmaker
from datetime import datetime
@@ -7,12 +8,22 @@ from .models import Base, Category, Product, PriceRecord, MonthlySummaryAnalysis
from .user_models import User, LoginHistory # noqa: F401 - 必須在 trend_models 之前導入,解決 ForeignKey 依賴問題
from .edm_models import PromoProduct # V-Fix: 確保 EDM 模型被註冊,以便自動建表
from .trend_models import TrendRecord, TrendKeyword, TrendAnalysis, WebSearchCache, TelegramUser # noqa: F401 - 趨勢資料表
from .ai_models import AgentContext, ActionPlan, ActionOutcome, AgentStrategyWeights # noqa: F401 - AI agent 模型
from .autoheal_models import Incident, Playbook, HealLog # noqa: F401 - ADR-013 AIOps 自動修復
from .import_models import ImportJob # noqa: F401 - 確保 import_jobs 表被 Base.metadata 管理
from .permission_models import Permission, UserPermission # noqa: F401 - 確保權限表被 Base.metadata 管理
from .ai_models import AIGenerationHistory, AIPromptTemplate, AIUsageTracking, AIInsight # noqa: F401 - AI history/template
from .autoheal_models import ( # noqa: F401 - ADR-013 AIOps 自動修復表
AgentContext,
ActionPlan,
ActionOutcome,
AgentStrategyWeights,
Incident,
Playbook,
HealLog,
)
from .import_models import ImportJob, ImportConfig # noqa: F401 - 確保 import_jobs/import_config 被 Base.metadata 管理
from .notification_models import NotificationTemplate # noqa: F401 - 確保 notification_templates 表被 Base.metadata 管理
from .ppt_reports import PPTReport # noqa: F401 - 確保 ppt_reports 表被 Base.metadata 管理
from .vendor_models import VendorStockout # noqa: F401 - 確保 vendor_stockout 表被 Base.metadata 管理
from .vendor_models import VendorStockout, VendorList, VendorEmail, EmailSendLog # noqa: F401 - 確保 vendor 表被 Base.metadata 管理
from .realtime_sales_models import RealtimeSalesMonthly # noqa: F401 - 確保 realtime_sales_monthly 被 Base.metadata 管理
# 🚩 導入優化後的日誌管理模組
from utils.logger_manager import SystemLogger
@@ -20,6 +31,33 @@ from utils.logger_manager import SystemLogger
# 初始化資料庫模組專用 Logger
sys_log = SystemLogger("Database").get_logger()
_metadata_init_lock = threading.Lock()
_metadata_initialized = False
_POSTGRES_METADATA_LOCK_ID = 170017
def ensure_metadata_initialized(engine, use_postgres_lock=False):
"""冪等初始化 SQLAlchemy metadata避免一般流程重複碰 DDL。"""
global _metadata_initialized
if _metadata_initialized:
return
with _metadata_init_lock:
if _metadata_initialized:
return
if use_postgres_lock:
with engine.begin() as conn:
conn.execute(text("SELECT pg_advisory_lock(:lock_id)"), {"lock_id": _POSTGRES_METADATA_LOCK_ID})
try:
Base.metadata.create_all(conn)
finally:
conn.execute(text("SELECT pg_advisory_unlock(:lock_id)"), {"lock_id": _POSTGRES_METADATA_LOCK_ID})
else:
Base.metadata.create_all(engine)
_metadata_initialized = True
def sanitize_timestamp(timestamp_str):
"""
驗證並清理時間戳字串,防止 SQL Injection
@@ -63,6 +101,7 @@ class DatabaseManager:
'options': '-c statement_timeout=60000' # SQL 超時 60 秒
}
)
ensure_metadata_initialized(self.engine, use_postgres_lock=True)
self.Session = sessionmaker(bind=self.engine)
sys_log.info(f"[Database] ✅ 使用 PostgreSQL 資料庫 (連線池已優化)")
# ADR-013: 確保 AIOps 自動修復表存在並植入種子 PlayBook
@@ -422,4 +461,4 @@ def get_session():
finally:
session.close()
"""
return get_db_manager().get_session()
return get_db_manager().get_session()