alphax/app/db/push_queries.py
2026-05-20 00:57:46 +08:00

80 lines
2.6 KiB
Python

"""Push de-duplication and push-facing recommendation reads."""
from datetime import datetime, timedelta
from app.db.recommendation_state import classify_recommendation_result, derive_execution_fields
from app.db.schema import get_conn
PUSH_COOLDOWN_HOURS = 12
def should_push(symbol: str, push_type: str, action_status: str = "") -> bool:
"""Return whether a symbol/type can be pushed under the status-aware cooldown."""
conn = get_conn()
cutoff = (datetime.now() - timedelta(hours=PUSH_COOLDOWN_HOURS)).isoformat()
try:
if action_status:
row = conn.execute(
"SELECT action_status FROM push_log WHERE symbol=%s AND push_type=%s AND pushed_at > %s ORDER BY id DESC LIMIT 1",
(symbol, push_type, cutoff),
).fetchone()
if row is None:
return True
return row[0] != action_status
row = conn.execute(
"SELECT id FROM push_log WHERE symbol=%s AND push_type=%s AND pushed_at > %s ORDER BY id DESC LIMIT 1",
(symbol, push_type, cutoff),
).fetchone()
return row is None
finally:
conn.close()
def log_push(symbol: str, push_type: str, action_status: str = "", rec_id: int = 0):
"""Record one push event and keep the recommendation source traceable."""
conn = get_conn()
try:
conn.execute(
"INSERT INTO push_log (symbol, push_type, action_status, rec_id, pushed_at) VALUES (%s,%s,%s,%s,%s)",
(symbol, push_type, action_status, int(rec_id or 0), datetime.now().isoformat()),
)
conn.commit()
finally:
conn.close()
def get_recommendation_for_push(rec_id: int):
"""Read one recommendation with the same derived display state used by the web/API layer."""
try:
rec_id = int(rec_id or 0)
except Exception:
rec_id = 0
if rec_id <= 0:
return None
conn = get_conn()
try:
row = conn.execute(
"""
SELECT r.*,
lpc.price AS latest_cache_price,
lpc.updated_at AS latest_cache_updated_at
FROM recommendation r
LEFT JOIN latest_price_cache lpc ON lpc.symbol = r.symbol
WHERE r.id=%s
""",
(rec_id,),
).fetchone()
finally:
conn.close()
if not row:
return None
item = dict(row)
rec_result, rec_result_label = classify_recommendation_result(item)
item["recommendation_result"] = rec_result
item["recommendation_result_label"] = rec_result_label
return derive_execution_fields(item)