@@ -12,35 +12,30 @@ def list_difficulties_and_topics() -> Dict[str, List[str]]:
12
12
- difficulties (list[str]): List of all available difficulty levels
13
13
- topics (list[str]): List of all available topics
14
14
"""
15
- with get_conn () as conn :
16
- with conn .cursor () as cur :
17
- cur .execute ("SELECT * FROM difficulties" )
18
- difficulties = [row [0 ] for row in cur .fetchall ()]
15
+ with get_conn () as conn , conn .cursor () as cur :
16
+ cur .execute ("SELECT * FROM difficulties" )
17
+ difficulties = [row [0 ] for row in cur .fetchall ()]
19
18
20
- cur .execute ("SELECT * FROM topics" )
21
- topics = [row [0 ] for row in cur .fetchall ()]
19
+ cur .execute ("SELECT * FROM topics" )
20
+ topics = [row [0 ] for row in cur .fetchall ()]
22
21
23
- return {"difficulties" : difficulties , "topics" : topics }
22
+ return {"difficulties" : difficulties , "topics" : topics }
24
23
25
24
def add_difficulty (difficulty : str ):
26
- with get_conn () as conn :
27
- with conn .cursor () as cur :
28
- cur .execute ("INSERT INTO difficulties (name) VALUES (%s) ON CONFLICT DO NOTHING" , (difficulty ,))
25
+ with get_conn () as conn , conn .cursor () as cur :
26
+ cur .execute ("INSERT INTO difficulties (name) VALUES (%s) ON CONFLICT DO NOTHING" , (difficulty ,))
29
27
30
28
def delete_difficulty (difficulty : str ):
31
- with get_conn () as conn :
32
- with conn .cursor () as cur :
33
- cur .execute ("DELETE FROM difficulties WHERE level = %s" , (difficulty ,))
29
+ with get_conn () as conn , conn .cursor () as cur :
30
+ cur .execute ("DELETE FROM difficulties WHERE level = %s" , (difficulty ,))
34
31
35
32
def add_topic (topic : str ):
36
- with get_conn () as conn :
37
- with conn .cursor () as cur :
38
- cur .execute ("INSERT INTO topics (name) VALUES (%s) ON CONFLICT DO NOTHING" , (topic ,))
33
+ with get_conn () as conn , conn .cursor () as cur :
34
+ cur .execute ("INSERT INTO topics (name) VALUES (%s) ON CONFLICT DO NOTHING" , (topic ,))
39
35
40
36
def delete_topic (topic : str ):
41
- with get_conn () as conn :
42
- with conn .cursor () as cur :
43
- cur .execute ("DELETE FROM topics WHERE name = %s" , (topic ,))
37
+ with get_conn () as conn , conn .cursor () as cur :
38
+ cur .execute ("DELETE FROM topics WHERE name = %s" , (topic ,))
44
39
45
40
def create_question (
46
41
name : str ,
@@ -121,34 +116,33 @@ def get_question(qid: str):
121
116
Note:
122
117
Images are returned as raw bytes data retrieved directly from S3.
123
118
"""
124
- with get_conn () as conn :
125
- with conn .cursor () as cur :
126
- # Fetch the main question data
127
- cur .execute (
128
- "SELECT name, description, difficulty, topic FROM questions WHERE id = %s" ,
129
- (qid ,),
130
- )
131
- question_data = cur .fetchone ()
119
+ with get_conn () as conn , conn .cursor () as cur :
120
+ # Fetch the main question data
121
+ cur .execute (
122
+ "SELECT name, description, difficulty, topic FROM questions WHERE id = %s" ,
123
+ (qid ,),
124
+ )
125
+ question_data = cur .fetchone ()
132
126
133
- if not question_data :
134
- raise QuestionNotFoundException (qid )
127
+ if not question_data :
128
+ raise QuestionNotFoundException (qid )
135
129
136
- # Fetch associated image keys
137
- cur .execute (
138
- "SELECT s3_key FROM question_images WHERE question_id = %s" ,
139
- (qid ,)
140
- )
141
- image_keys = [row [0 ] for row in cur .fetchall ()]
142
- image_data = get_from_s3 (image_keys )
130
+ # Fetch associated image keys
131
+ cur .execute (
132
+ "SELECT s3_key FROM question_images WHERE question_id = %s" ,
133
+ (qid ,)
134
+ )
135
+ image_keys = [row [0 ] for row in cur .fetchall ()]
136
+ image_data = get_from_s3 (image_keys )
143
137
144
- return {
145
- "id" : qid ,
146
- "name" : question_data [0 ],
147
- "description" : question_data [1 ],
148
- "difficulty" : question_data [2 ],
149
- "topic" : question_data [3 ],
150
- "images" : image_data , # Raw bytes
151
- }
138
+ return {
139
+ "id" : qid ,
140
+ "name" : question_data [0 ],
141
+ "description" : question_data [1 ],
142
+ "difficulty" : question_data [2 ],
143
+ "topic" : question_data [3 ],
144
+ "images" : image_data , # Raw bytes
145
+ }
152
146
153
147
154
148
def get_random_question_by_difficulty_and_topic (difficulty : str , topic : str ):
@@ -170,39 +164,38 @@ def get_random_question_by_difficulty_and_topic(difficulty: str, topic: str):
170
164
Images are returned as raw bytes data retrieved directly from S3.
171
165
Uses database RANDOM() function for selection.
172
166
"""
173
- with get_conn () as conn :
174
- with conn .cursor () as cur :
175
- cur .execute (
176
- """
177
- SELECT id, name, description, difficulty, topic
178
- FROM questions
179
- WHERE difficulty = %s AND topic = %s
180
- ORDER BY RANDOM()
181
- LIMIT 1
182
- """ ,
183
- (difficulty , topic ),
184
- )
185
- row = cur .fetchone ()
186
- if not row :
187
- raise QuestionNotFoundException (topic = topic , difficulty = difficulty )
167
+ with get_conn () as conn , conn .cursor () as cur :
168
+ cur .execute (
169
+ """
170
+ SELECT id, name, description, difficulty, topic
171
+ FROM questions
172
+ WHERE difficulty = %s AND topic = %s
173
+ ORDER BY RANDOM()
174
+ LIMIT 1
175
+ """ ,
176
+ (difficulty , topic ),
177
+ )
178
+ row = cur .fetchone ()
179
+ if not row :
180
+ raise QuestionNotFoundException (topic = topic , difficulty = difficulty )
188
181
189
- qid = row [0 ]
190
- # Fetch associated image keys
191
- cur .execute (
192
- "SELECT s3_key FROM question_images WHERE question_id = %s" ,
193
- (qid ,),
194
- )
195
- image_keys = [r [0 ] for r in cur .fetchall ()]
196
- image_data = get_from_s3 (image_keys )
182
+ qid = row [0 ]
183
+ # Fetch associated image keys
184
+ cur .execute (
185
+ "SELECT s3_key FROM question_images WHERE question_id = %s" ,
186
+ (qid ,),
187
+ )
188
+ image_keys = [r [0 ] for r in cur .fetchall ()]
189
+ image_data = get_from_s3 (image_keys )
197
190
198
- return {
199
- "id" : qid ,
200
- "name" : row [1 ],
201
- "description" : row [2 ],
202
- "difficulty" : row [3 ],
203
- "topic" : row [4 ],
204
- "images" : image_data , # Raw bytes
205
- }
191
+ return {
192
+ "id" : qid ,
193
+ "name" : row [1 ],
194
+ "description" : row [2 ],
195
+ "difficulty" : row [3 ],
196
+ "topic" : row [4 ],
197
+ "images" : image_data , # Raw bytes
198
+ }
206
199
207
200
208
201
def override_question (
@@ -287,25 +280,24 @@ def delete_question(qid: str):
287
280
This function is atomic: if deleting images from S3 fails,
288
281
the database transaction is rolled back to maintain consistency.
289
282
"""
290
- with get_conn () as conn :
291
- with conn .cursor () as cur :
292
- # Fetch associated image keys
293
- cur .execute (
294
- "SELECT s3_key FROM question_images WHERE question_id = %s" ,
295
- (qid ,)
296
- )
297
- image_keys = [row [0 ] for row in cur .fetchall ()]
283
+ with get_conn () as conn , conn .cursor () as cur :
284
+ # Fetch associated image keys
285
+ cur .execute (
286
+ "SELECT s3_key FROM question_images WHERE question_id = %s" ,
287
+ (qid ,)
288
+ )
289
+ image_keys = [row [0 ] for row in cur .fetchall ()]
298
290
299
- # Delete the question and verify it existed
300
- cur .execute ("DELETE FROM questions WHERE id = %s RETURNING id" , (qid ,))
301
- deleted = cur .fetchone ()
302
- if not deleted :
303
- raise QuestionNotFoundException (qid )
291
+ # Delete the question and verify it existed
292
+ cur .execute ("DELETE FROM questions WHERE id = %s RETURNING id" , (qid ,))
293
+ deleted = cur .fetchone ()
294
+ if not deleted :
295
+ raise QuestionNotFoundException (qid )
304
296
305
- # Delete images from S3; rollback DB if this fails
306
- try :
307
- delete_from_s3 (image_keys )
308
- except Exception :
309
- conn .rollback ()
310
- raise
297
+ # Delete images from S3; rollback DB if this fails
298
+ try :
299
+ delete_from_s3 (image_keys )
300
+ except Exception :
301
+ conn .rollback ()
302
+ raise
311
303
0 commit comments