129 lines
5.5 KiB
Python
129 lines
5.5 KiB
Python
|
|
"""
|
||
|
|
Match Processor - Handles fact_matches and fact_match_teams
|
||
|
|
|
||
|
|
Responsibilities:
|
||
|
|
- Extract match basic information from JSON
|
||
|
|
- Process team data (group1/group2)
|
||
|
|
- Store raw JSON fields (treat_info, response metadata)
|
||
|
|
- Set data_source_type marker
|
||
|
|
"""
|
||
|
|
|
||
|
|
import sqlite3
|
||
|
|
import json
|
||
|
|
import logging
|
||
|
|
from typing import Any, Dict
|
||
|
|
|
||
|
|
logger = logging.getLogger(__name__)
|
||
|
|
|
||
|
|
|
||
|
|
def safe_int(val):
|
||
|
|
"""Safely convert value to integer"""
|
||
|
|
try:
|
||
|
|
return int(float(val)) if val is not None else 0
|
||
|
|
except:
|
||
|
|
return 0
|
||
|
|
|
||
|
|
|
||
|
|
def safe_float(val):
|
||
|
|
"""Safely convert value to float"""
|
||
|
|
try:
|
||
|
|
return float(val) if val is not None else 0.0
|
||
|
|
except:
|
||
|
|
return 0.0
|
||
|
|
|
||
|
|
|
||
|
|
def safe_text(val):
|
||
|
|
"""Safely convert value to text"""
|
||
|
|
return "" if val is None else str(val)
|
||
|
|
|
||
|
|
|
||
|
|
class MatchProcessor:
|
||
|
|
@staticmethod
|
||
|
|
def process(match_data, conn: sqlite3.Connection) -> bool:
|
||
|
|
"""
|
||
|
|
Process match basic info and team data
|
||
|
|
|
||
|
|
Args:
|
||
|
|
match_data: MatchData object containing parsed JSON
|
||
|
|
conn: L2 database connection
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
bool: True if successful
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
cursor = conn.cursor()
|
||
|
|
|
||
|
|
# Build column list and values dynamically to avoid count mismatches
|
||
|
|
columns = [
|
||
|
|
'match_id', 'match_code', 'map_name', 'start_time', 'end_time', 'duration',
|
||
|
|
'winner_team', 'score_team1', 'score_team2', 'server_ip', 'server_port', 'location',
|
||
|
|
'has_side_data_and_rating2', 'match_main_id', 'demo_url', 'game_mode', 'game_name',
|
||
|
|
'map_desc', 'location_full', 'match_mode', 'match_status', 'match_flag', 'status', 'waiver',
|
||
|
|
'year', 'season', 'round_total', 'cs_type', 'priority_show_type', 'pug10m_show_type',
|
||
|
|
'credit_match_status', 'knife_winner', 'knife_winner_role', 'most_1v2_uid',
|
||
|
|
'most_assist_uid', 'most_awp_uid', 'most_end_uid', 'most_first_kill_uid',
|
||
|
|
'most_headshot_uid', 'most_jump_uid', 'mvp_uid', 'response_code', 'response_message',
|
||
|
|
'response_status', 'response_timestamp', 'response_trace_id', 'response_success',
|
||
|
|
'response_errcode', 'treat_info_raw', 'round_list_raw', 'leetify_data_raw',
|
||
|
|
'data_source_type'
|
||
|
|
]
|
||
|
|
|
||
|
|
values = [
|
||
|
|
match_data.match_id, match_data.match_code, match_data.map_name, match_data.start_time,
|
||
|
|
match_data.end_time, match_data.duration, match_data.winner_team, match_data.score_team1,
|
||
|
|
match_data.score_team2, match_data.server_ip, match_data.server_port, match_data.location,
|
||
|
|
match_data.has_side_data_and_rating2, match_data.match_main_id, match_data.demo_url,
|
||
|
|
match_data.game_mode, match_data.game_name, match_data.map_desc, match_data.location_full,
|
||
|
|
match_data.match_mode, match_data.match_status, match_data.match_flag, match_data.status,
|
||
|
|
match_data.waiver, match_data.year, match_data.season, match_data.round_total,
|
||
|
|
match_data.cs_type, match_data.priority_show_type, match_data.pug10m_show_type,
|
||
|
|
match_data.credit_match_status, match_data.knife_winner, match_data.knife_winner_role,
|
||
|
|
match_data.most_1v2_uid, match_data.most_assist_uid, match_data.most_awp_uid,
|
||
|
|
match_data.most_end_uid, match_data.most_first_kill_uid, match_data.most_headshot_uid,
|
||
|
|
match_data.most_jump_uid, match_data.mvp_uid, match_data.response_code,
|
||
|
|
match_data.response_message, match_data.response_status, match_data.response_timestamp,
|
||
|
|
match_data.response_trace_id, match_data.response_success, match_data.response_errcode,
|
||
|
|
match_data.treat_info_raw, match_data.round_list_raw, match_data.leetify_data_raw,
|
||
|
|
match_data.data_source_type
|
||
|
|
]
|
||
|
|
|
||
|
|
# Build SQL dynamically
|
||
|
|
placeholders = ','.join(['?' for _ in columns])
|
||
|
|
columns_sql = ','.join(columns)
|
||
|
|
sql = f"INSERT OR REPLACE INTO fact_matches ({columns_sql}) VALUES ({placeholders})"
|
||
|
|
|
||
|
|
cursor.execute(sql, values)
|
||
|
|
|
||
|
|
# Process team data
|
||
|
|
for team in match_data.teams:
|
||
|
|
team_row = (
|
||
|
|
match_data.match_id,
|
||
|
|
team.group_id,
|
||
|
|
team.group_all_score,
|
||
|
|
team.group_change_elo,
|
||
|
|
team.group_fh_role,
|
||
|
|
team.group_fh_score,
|
||
|
|
team.group_origin_elo,
|
||
|
|
team.group_sh_role,
|
||
|
|
team.group_sh_score,
|
||
|
|
team.group_tid,
|
||
|
|
team.group_uids
|
||
|
|
)
|
||
|
|
|
||
|
|
cursor.execute('''
|
||
|
|
INSERT OR REPLACE INTO fact_match_teams (
|
||
|
|
match_id, group_id, group_all_score, group_change_elo,
|
||
|
|
group_fh_role, group_fh_score, group_origin_elo,
|
||
|
|
group_sh_role, group_sh_score, group_tid, group_uids
|
||
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||
|
|
''', team_row)
|
||
|
|
|
||
|
|
logger.debug(f"Processed match {match_data.match_id}")
|
||
|
|
return True
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
logger.error(f"Error processing match {match_data.match_id}: {e}")
|
||
|
|
import traceback
|
||
|
|
traceback.print_exc()
|
||
|
|
return False
|