|
2 | 2 | import os |
3 | 3 | from datetime import datetime |
4 | 4 |
|
5 | | -import psycopg2 |
6 | 5 | import requests |
7 | 6 | from jinja2 import Template |
| 7 | +from sqlalchemy import create_engine, text |
| 8 | +from sqlalchemy.exc import SQLAlchemyError |
8 | 9 |
|
9 | 10 | TOKEN = os.environ.get("DISCORD_DUMMY_TOKEN") |
10 | 11 |
|
@@ -80,102 +81,108 @@ def get_name_from_id(user_id: str) -> str: |
80 | 81 | def fetch_leaderboard_data(): |
81 | 82 | print("Fetching data from database...") |
82 | 83 | try: |
83 | | - with psycopg2.connect(DATABASE_URL) as conn: |
84 | | - with conn.cursor() as cur: |
85 | | - cur.execute( |
86 | | - """ |
87 | | - SELECT id, name, deadline |
88 | | - FROM leaderboard.leaderboard |
89 | | - """ |
| 84 | + engine = create_engine(DATABASE_URL) |
| 85 | + with engine.connect() as connection: |
| 86 | + # Get all leaderboards |
| 87 | + leaderboards_query = text(""" |
| 88 | + SELECT id, name, deadline |
| 89 | + FROM leaderboard.leaderboard |
| 90 | + """) |
| 91 | + |
| 92 | + leaderboards_result = connection.execute(leaderboards_query) |
| 93 | + leaderboards = leaderboards_result.fetchall() |
| 94 | + |
| 95 | + # Get active leaderboards with their GPU types and submission counts |
| 96 | + submissions_query = text(""" |
| 97 | + WITH unique_best_submissions AS ( |
| 98 | + SELECT DISTINCT ON (s.user_id) |
| 99 | + s.file_name, |
| 100 | + s.user_id, |
| 101 | + s.submission_time, |
| 102 | + r.score, |
| 103 | + r.runner |
| 104 | + FROM leaderboard.runs r |
| 105 | + JOIN leaderboard.submission s ON r.submission_id = s.id |
| 106 | + JOIN leaderboard.leaderboard l ON s.leaderboard_id = l.id |
| 107 | + WHERE l.name = :leaderboard_name AND r.runner = :gpu_type AND NOT r.secret |
| 108 | + AND r.score IS NOT NULL AND r.passed |
| 109 | + ORDER BY s.user_id, r.score ASC |
90 | 110 | ) |
91 | | - |
92 | | - leaderboards = cur.fetchall() |
93 | | - |
94 | | - # Get active leaderboards with their GPU types and submission counts |
95 | | - query = """ |
96 | | - WITH unique_best_submissions AS ( |
97 | | - SELECT DISTINCT ON (s.user_id) |
98 | | - s.file_name, |
99 | | - s.user_id, |
100 | | - s.submission_time, |
101 | | - r.score, |
102 | | - r.runner |
103 | | - FROM leaderboard.runs r |
104 | | - JOIN leaderboard.submission s ON r.submission_id = s.id |
105 | | - JOIN leaderboard.leaderboard l ON s.leaderboard_id = l.id |
106 | | - WHERE l.name = %s AND r.runner = %s AND NOT r.secret |
107 | | - AND r.score IS NOT NULL AND r.passed |
108 | | - ORDER BY s.user_id, r.score ASC |
| 111 | + SELECT |
| 112 | + file_name, |
| 113 | + user_id, |
| 114 | + submission_time, |
| 115 | + score, |
| 116 | + runner, |
| 117 | + ROW_NUMBER() OVER (ORDER BY score ASC) as rank |
| 118 | + FROM unique_best_submissions |
| 119 | + ORDER BY score ASC; |
| 120 | + """) |
| 121 | + |
| 122 | + gpu_type_data = {} |
| 123 | + for _lb_id, name, deadline in leaderboards: |
| 124 | + # Get GPU types for this leaderboard |
| 125 | + gpu_types_query = text(""" |
| 126 | + SELECT gpu_type |
| 127 | + FROM leaderboard.gpu_type |
| 128 | + WHERE leaderboard_id = :leaderboard_id |
| 129 | + """) |
| 130 | + |
| 131 | + gpu_types_result = connection.execute(gpu_types_query, {'leaderboard_id': _lb_id}) |
| 132 | + gpu_types = [row[0] for row in gpu_types_result.fetchall()] |
| 133 | + |
| 134 | + for gpu_type in gpu_types: |
| 135 | + submissions_result = connection.execute( |
| 136 | + submissions_query, |
| 137 | + {'leaderboard_name': name, 'gpu_type': gpu_type} |
109 | 138 | ) |
110 | | - SELECT |
111 | | - file_name, |
112 | | - user_id, |
113 | | - submission_time, |
114 | | - score, |
115 | | - runner, |
116 | | - ROW_NUMBER() OVER (ORDER BY score ASC) as rank |
117 | | - FROM unique_best_submissions |
118 | | - ORDER BY score ASC; |
119 | | - """ |
120 | | - |
121 | | - gpu_type_data = {} |
122 | | - for ( |
123 | | - _lb_id, |
124 | | - name, |
125 | | - deadline, |
126 | | - ) in leaderboards: |
127 | | - cur.execute( |
128 | | - "SELECT * from leaderboard.gpu_type where leaderboard_id = %s", [_lb_id] |
| 139 | + submissions = submissions_result.fetchall() |
| 140 | + |
| 141 | + print( |
| 142 | + f"Found {len(submissions)} active submissions in {name} for {gpu_type}" |
129 | 143 | ) |
130 | | - gpu_types = [x[1] for x in cur.fetchall()] |
131 | | - |
132 | | - for gpu_type in gpu_types: |
133 | | - args = (name, gpu_type) |
134 | | - cur.execute(query, args) |
135 | | - submissions = cur.fetchall() |
136 | | - |
137 | | - print( |
138 | | - f"Found {len(submissions)} active submissions in {name} for {gpu_type}" |
139 | | - ) |
140 | | - |
141 | | - if len(submissions) > 0: |
142 | | - if gpu_type not in gpu_type_data: |
143 | | - gpu_type_data[gpu_type] = {} |
144 | | - |
145 | | - gpu_submissions = [] |
146 | | - for lb in submissions: |
147 | | - user_id = lb[1] |
148 | | - time = lb[3] |
149 | | - rank = lb[5] |
150 | | - global_name = get_name_from_id(user_id) |
151 | | - gpu_submissions.append( |
152 | | - { |
153 | | - "user": f"{global_name}", |
154 | | - "time": f"{time:.9f}", |
155 | | - "rank": rank, |
156 | | - } |
157 | | - ) |
158 | | - |
159 | | - # Sort submissions by time |
160 | | - gpu_submissions.sort(key=lambda x: float(x["time"])) |
161 | | - |
162 | | - gpu_type_data[gpu_type][name] = { |
163 | | - "name": name, |
164 | | - "deadline": deadline.strftime("%Y-%m-%d %H:%M"), |
165 | | - "submissions": gpu_submissions, |
166 | | - } |
167 | | - |
168 | | - # Convert to final format |
169 | | - formatted_data = { |
170 | | - "gpu_types": [ |
171 | | - {"name": gpu_type, "problems": list(problems.values())} |
172 | | - for gpu_type, problems in gpu_type_data.items() |
173 | | - ], |
174 | | - "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S UTC"), |
175 | | - } |
176 | | - |
177 | | - print("Data fetched successfully") |
178 | | - return formatted_data |
| 144 | + |
| 145 | + if len(submissions) > 0: |
| 146 | + if gpu_type not in gpu_type_data: |
| 147 | + gpu_type_data[gpu_type] = {} |
| 148 | + |
| 149 | + gpu_submissions = [] |
| 150 | + for lb in submissions: |
| 151 | + user_id = lb[1] |
| 152 | + time = lb[3] |
| 153 | + rank = lb[5] |
| 154 | + global_name = get_name_from_id(user_id) |
| 155 | + gpu_submissions.append( |
| 156 | + { |
| 157 | + "user": f"{global_name}", |
| 158 | + "time": f"{time:.9f}", |
| 159 | + "rank": rank, |
| 160 | + } |
| 161 | + ) |
| 162 | + |
| 163 | + # Sort submissions by time |
| 164 | + gpu_submissions.sort(key=lambda x: float(x["time"])) |
| 165 | + |
| 166 | + gpu_type_data[gpu_type][name] = { |
| 167 | + "name": name, |
| 168 | + "deadline": deadline.strftime("%Y-%m-%d %H:%M"), |
| 169 | + "submissions": gpu_submissions, |
| 170 | + } |
| 171 | + |
| 172 | + # Convert to final format |
| 173 | + formatted_data = { |
| 174 | + "gpu_types": [ |
| 175 | + {"name": gpu_type, "problems": list(problems.values())} |
| 176 | + for gpu_type, problems in gpu_type_data.items() |
| 177 | + ], |
| 178 | + "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S UTC"), |
| 179 | + } |
| 180 | + |
| 181 | + print("Data fetched successfully") |
| 182 | + return formatted_data |
| 183 | + except SQLAlchemyError as e: |
| 184 | + print(f"Database error: {str(e)}") |
| 185 | + raise |
179 | 186 | except Exception as e: |
180 | 187 | print(f"Error fetching data: {str(e)}") |
181 | 188 | raise |
|
0 commit comments