2.0.0 Alpha: Data Refinery
This commit is contained in:
@@ -1,19 +1,10 @@
|
||||
from web.database import query_db
|
||||
from web.services.web_service import WebService
|
||||
import json
|
||||
from web.services.team_context_service import TeamContextService
|
||||
|
||||
class OpponentService:
|
||||
@staticmethod
|
||||
def _get_active_roster_ids():
|
||||
lineups = WebService.get_lineups()
|
||||
active_roster_ids = []
|
||||
if lineups:
|
||||
try:
|
||||
raw_ids = json.loads(lineups[0]['player_ids_json'])
|
||||
active_roster_ids = [str(uid) for uid in raw_ids]
|
||||
except:
|
||||
pass
|
||||
return active_roster_ids
|
||||
return TeamContextService.get_active_roster_ids()
|
||||
|
||||
@staticmethod
|
||||
def get_opponent_list(page=1, per_page=20, sort_by='matches', search=None):
|
||||
@@ -21,30 +12,21 @@ class OpponentService:
|
||||
if not roster_ids:
|
||||
return [], 0
|
||||
|
||||
# Placeholders
|
||||
roster_ph = ','.join('?' for _ in roster_ids)
|
||||
|
||||
# 1. Identify Matches involving our roster (at least 1 member? usually 2 for 'team' match)
|
||||
# Let's say at least 1 for broader coverage as requested ("1 match sample")
|
||||
# But "Our Team" usually implies the entity. Let's stick to matches where we can identify "Us".
|
||||
# If we use >=1, we catch solo Q matches of roster members. The user said "Non-team members or 1 match sample",
|
||||
# but implied "facing different our team lineups".
|
||||
# Let's use the standard "candidate matches" logic (>=2 roster members) to represent "The Team".
|
||||
# OR, if user wants "Opponent Analysis" for even 1 match, maybe they mean ANY match in DB?
|
||||
# "Left Top add Opponent Analysis... (non-team member or 1 sample)"
|
||||
# This implies we analyze PLAYERS who are NOT us.
|
||||
# Let's stick to matches where >= 1 roster member played, to define "Us" vs "Them".
|
||||
|
||||
# Actually, let's look at ALL matches in DB, and any player NOT in active roster is an "Opponent".
|
||||
# This covers "1 sample".
|
||||
|
||||
# Query:
|
||||
# Select all players who are NOT in active roster.
|
||||
# Group by steam_id.
|
||||
# Aggregate stats.
|
||||
|
||||
where_clauses = [f"CAST(mp.steam_id_64 AS TEXT) NOT IN ({roster_ph})"]
|
||||
args = list(roster_ids)
|
||||
|
||||
where_clauses = [
|
||||
f"CAST(mp.steam_id_64 AS TEXT) NOT IN ({roster_ph})",
|
||||
f"""
|
||||
EXISTS (
|
||||
SELECT 1
|
||||
FROM fact_match_players roster_mp
|
||||
WHERE roster_mp.match_id = mp.match_id
|
||||
AND CAST(roster_mp.steam_id_64 AS TEXT) IN ({roster_ph})
|
||||
AND roster_mp.team_id != mp.team_id
|
||||
)
|
||||
""",
|
||||
]
|
||||
args = list(roster_ids) + list(roster_ids)
|
||||
|
||||
if search:
|
||||
where_clauses.append("(LOWER(p.username) LIKE LOWER(?) OR mp.steam_id_64 LIKE ?)")
|
||||
@@ -61,16 +43,6 @@ class OpponentService:
|
||||
elif sort_by == 'win_rate':
|
||||
sort_sql = "win_rate DESC"
|
||||
|
||||
# Main Aggregation Query
|
||||
# We need to join fact_matches to get match info (win/loss, elo) if needed,
|
||||
# but fact_match_players has is_win (boolean) usually? No, it has team_id.
|
||||
# We need to determine if THEY won.
|
||||
# fact_match_players doesn't store is_win directly in schema (I should check schema, but stats_service calculates it).
|
||||
# Wait, stats_service.get_player_trend uses `mp.is_win`?
|
||||
# Let's check schema. `fact_match_players` usually has `match_id`, `team_id`.
|
||||
# `fact_matches` has `winner_team`.
|
||||
# So we join.
|
||||
|
||||
offset = (page - 1) * per_page
|
||||
|
||||
sql = f"""
|
||||
@@ -151,10 +123,17 @@ class OpponentService:
|
||||
LEFT JOIN fact_match_teams fmt_gid ON mp.match_id = fmt_gid.match_id AND fmt_gid.group_id = mp.team_id
|
||||
LEFT JOIN fact_match_teams fmt_tid ON mp.match_id = fmt_tid.match_id AND fmt_tid.group_tid = mp.match_team_id
|
||||
WHERE CAST(mp.steam_id_64 AS TEXT) NOT IN ({roster_ph})
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM fact_match_players roster_mp
|
||||
WHERE roster_mp.match_id = mp.match_id
|
||||
AND CAST(roster_mp.steam_id_64 AS TEXT) IN ({roster_ph})
|
||||
AND roster_mp.team_id != mp.team_id
|
||||
)
|
||||
GROUP BY mp.steam_id_64
|
||||
"""
|
||||
|
||||
rows = query_db('l2', sql, roster_ids)
|
||||
rows = query_db('l2', sql, roster_ids + roster_ids)
|
||||
|
||||
# Initialize Buckets
|
||||
elo_buckets = {'<1000': 0, '1000-1200': 0, '1200-1400': 0, '1400-1600': 0, '1600-1800': 0, '1800-2000': 0, '>2000': 0}
|
||||
@@ -216,13 +195,12 @@ class OpponentService:
|
||||
player = dict(info)
|
||||
player['avatar_url'] = StatsService.resolve_avatar_url(steam_id, player.get('avatar_url'))
|
||||
|
||||
# 2. Match History vs Us (All matches this player played)
|
||||
# We define "Us" as matches where this player is an opponent.
|
||||
# But actually, we just show ALL their matches in our DB, assuming our DB only contains matches relevant to us?
|
||||
# Usually yes, but if we have a huge DB, we might want to filter by "Contains Roster Member".
|
||||
# For now, show all matches in DB for this player.
|
||||
|
||||
sql_history = """
|
||||
roster_ids = OpponentService._get_active_roster_ids()
|
||||
if not roster_ids:
|
||||
return None
|
||||
roster_ph = ','.join('?' for _ in roster_ids)
|
||||
|
||||
sql_history = f"""
|
||||
SELECT
|
||||
m.match_id, m.start_time, m.map_name, m.score_team1, m.score_team2, m.winner_team,
|
||||
mp.team_id, mp.match_team_id, mp.rating, mp.kd_ratio, mp.adr, mp.kills, mp.deaths,
|
||||
@@ -236,9 +214,16 @@ class OpponentService:
|
||||
LEFT JOIN fact_match_teams fmt_gid ON mp.match_id = fmt_gid.match_id AND fmt_gid.group_id = mp.team_id
|
||||
LEFT JOIN fact_match_teams fmt_tid ON mp.match_id = fmt_tid.match_id AND fmt_tid.group_tid = mp.match_team_id
|
||||
WHERE mp.steam_id_64 = ?
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM fact_match_players roster_mp
|
||||
WHERE roster_mp.match_id = mp.match_id
|
||||
AND CAST(roster_mp.steam_id_64 AS TEXT) IN ({roster_ph})
|
||||
AND roster_mp.team_id != mp.team_id
|
||||
)
|
||||
ORDER BY m.start_time DESC
|
||||
"""
|
||||
history = query_db('l2', sql_history, [steam_id])
|
||||
history = query_db('l2', sql_history, [steam_id] + roster_ids)
|
||||
|
||||
# 3. Aggregation by ELO
|
||||
elo_buckets = {
|
||||
@@ -389,11 +374,18 @@ class OpponentService:
|
||||
LEFT JOIN fact_match_teams fmt_gid ON mp.match_id = fmt_gid.match_id AND fmt_gid.group_id = mp.team_id
|
||||
LEFT JOIN fact_match_teams fmt_tid ON mp.match_id = fmt_tid.match_id AND fmt_tid.group_tid = mp.match_team_id
|
||||
WHERE CAST(mp.steam_id_64 AS TEXT) NOT IN ({roster_ph})
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM fact_match_players roster_mp
|
||||
WHERE roster_mp.match_id = mp.match_id
|
||||
AND CAST(roster_mp.steam_id_64 AS TEXT) IN ({roster_ph})
|
||||
AND roster_mp.team_id != mp.team_id
|
||||
)
|
||||
AND m.map_name IS NOT NULL AND m.map_name <> ''
|
||||
GROUP BY m.map_name
|
||||
ORDER BY matches DESC
|
||||
"""
|
||||
rows = query_db('l2', sql, roster_ids)
|
||||
rows = query_db('l2', sql, roster_ids + roster_ids)
|
||||
results = []
|
||||
for r in rows:
|
||||
d = dict(r)
|
||||
|
||||
Reference in New Issue
Block a user