@@ -20,6 +20,190 @@ def get_connection():
20
20
21
21
return conn
22
22
23
+ conn = get_connection ()
24
+ cur = conn .cursor ()
25
+
26
+ # IMPORTANT: executing a query is expensive, so we would rather write more functions than write more execute queries.
27
+
28
+ # Get all the information about a question given its day number
29
+ # Returns all information in the form of a dictionary
30
+ # You might want to use this function to find the total number of parts in a question, and then use getPartInfo
31
+ def getQuestionInfo (compName , dayNum ):
32
+ query = f"""
33
+ select * from Questions q
34
+ join Competitions c on q.cid = c.cid
35
+ where q.dayNum = { dayNum } and c.name = { compName } ;
36
+ """
37
+ cur .execute (query )
38
+
39
+ # only one entry should be returned since day number is unique
40
+ t = cur .fetchone ()
41
+ return t
42
+
43
+ # Get all the parts given a day number of a question
44
+ # Returns all information in the form of a list of dictionaries
45
+ def getQuestionParts (compName , dayNum ):
46
+ query = f"""
47
+ select * from Parts p
48
+ join Questions q on p.qid = q.qid
49
+ join Competitions c on q.cid = c.cid
50
+ where q.dayNum = { dayNum } and c.name = { compName } ;
51
+ """
52
+ cur .execute (query )
53
+
54
+ partsList = []
55
+ for t in cur .fetchall ():
56
+ partsList .append (t )
57
+
58
+ # sort the list based off the part number
59
+ sortedList = sorted (partsList , key = lambda x : x ['partNum' ])
60
+ return sortedList
61
+
62
+ # Get all the information about a part of a question (e.g. day 1 part 2) given the day number and part number
63
+ # Same as above but more specific
64
+ # Returns all information in the form of a dictionary
65
+ def getPartInfo (compName , dayNum , partNum ):
66
+ query = f"""
67
+ select * from Parts p
68
+ join Questions q on p.qid = q.qid
69
+ join Competitions c on q.cid = c.cid
70
+ where q.dayNum = { dayNum } and p.partNum = { partNum } and c.name = { compName } ;
71
+ """
72
+ cur .execute (query )
73
+
74
+ # only one entry should be returned since day number is unique
75
+ t = cur .fetchone ()
76
+ return t
77
+
78
+ # Get all the questions that pertain to a certain competition, by name
79
+ # Returns None if the competition does not exist
80
+ def getCompetitionQuestions (compName ):
81
+ query = f"""
82
+ select * from Parts p
83
+ join Questions q on p.qid = q.qid
84
+ join Competitions c on q.cid = c.cid
85
+ where c.name = { compName } ;
86
+ """
87
+ cur .execute (query )
88
+
89
+ # only one entry should be returned since day number is unique
90
+ return cur .fetchall ()
91
+
92
+ # Unfinished function.
93
+ # Dynamically generates a new input for a user and day number
94
+ def generateInput (dayNum , uid ):
95
+ pass
96
+
97
+ # Gets the input for a day number and user, if it exists
98
+ # Returns the input string, else returns None
99
+ def getInput (compName , dayNum , uid ):
100
+ query = f"""
101
+ select i.input from Inputs i
102
+ join Questions q on i.qid = q.qid
103
+ join Competitions c on q.cid = c.cid
104
+ where q.dayNum = { dayNum } and i.uid = { uid } and c.name = { compName } ;
105
+ """
106
+ cur .execute (query )
107
+
108
+ t = cur .fetchone ()
109
+ return t ['input' ] if t is not None else t
110
+
111
+ # Gets the input for a day number and user, if it exists
112
+ # Returns a tuple:
113
+ # the tuple is None if the value does not exist
114
+ # the first entry of the tuple is True if the solution is correct (and exists), False otherwise
115
+ # the second entry of the tuple is a string outlining the reason if the solution was incorrect
116
+ # not sure what to put here so just leaving as empty string for now
117
+ def checkInput (compName , dayNum , uid , solution ):
118
+ query = f"""
119
+ select i.input, i.solution from Inputs i
120
+ join Questions q on i.qid = q.qid
121
+ join Competitions c on q.cid = c.cid
122
+ where q.dayNum = { dayNum } and i.uid = { uid } and c.name = { compName } ;
123
+ """
124
+ cur .execute (query )
125
+
126
+ t = cur .fetchone ()
127
+ if t is None :
128
+ return None
129
+ elif t ['solution' ].lower () == solution .strip ().lower ():
130
+ # can change this later, but iirc advent of code is also not case sensitive
131
+ return (True , "" )
132
+ else :
133
+ return (False , "" )
134
+
135
+ # note: for more advanced processing, we might consider having a timeout if a user tries too many things too quickly
136
+ # but idk how to implement this too well
137
+
138
+ # Get all the information about a user given their uid
139
+ # Returns all information in the form of a dictionary
140
+ def getUserInfo (uid ):
141
+ query = f"""
142
+ select * from Users where uid = { uid } ;
143
+ """
144
+ cur .execute (query )
145
+
146
+ # only one entry should be returned since day number is unique
147
+ t = cur .fetchone ()
148
+ return t
149
+
150
+ # Get all the information about a user's stats in a certain competition
151
+ # Returns all information in the form of a list of 'solved objects'
152
+ def getUserStatsPerComp (compName , uid ):
153
+
154
+ # A right outer join returns all the results from the parts table, even if there is no solves
155
+ # Best to look up examples :D
156
+ # Use this information to deduce whether a user has solved a part or not
157
+ query = f"""
158
+ select q.dayNum, p.partNum, s.points, s.solveTime from Solves s
159
+ right outer join Parts p on s.pid = p.pid
160
+ join Questions q on p.qid = q.qid
161
+ join Competitions c on q.cid = c.cid
162
+ where i.uid = { uid } and c.name = { compName } ;
163
+ """
164
+ cur .execute (query )
165
+
166
+ return cur .fetchall ()
167
+
168
+ # Could be very large
169
+ def getAllUsers ():
170
+ query = f"""
171
+ select * from Users;
172
+ """
173
+ cur .execute (query )
174
+
175
+ return cur .fetchall ()
176
+
177
+ # Could be very large
178
+ def getAllCompetitions ():
179
+ query = f"""
180
+ select * from Competitions;
181
+ """
182
+ cur .execute (query )
183
+
184
+ return cur .fetchall ()
185
+
186
+ # Pre conditions assume we have already checked that noone has that username
187
+ # No idea whether this works lol never done something like this before
188
+ def updateUsername (username , uid ):
189
+ query = f"""
190
+ update Users
191
+ set username = { username }
192
+ where uid = { uid } ;
193
+ """
194
+ cur .execute (query )
195
+ conn .commit ()
196
+
197
+ # DO NOT EVER EXECUTE THIS FUNCTION BRUH
198
+ def dropDatabase ():
199
+ query = f"""
200
+ SELECT 'DROP TABLE IF EXISTS "' || tablename || '" CASCADE;'
201
+ from
202
+ pg_tables WHERE schemaname = 'advent';
203
+ """
204
+ cur .execute (query )
205
+ conn .commit ()
206
+
23
207
def clear_database ():
24
208
conn = get_connection ()
25
209
cursor = conn .cursor ()
@@ -30,4 +214,4 @@ def clear_database():
30
214
conn .commit ()
31
215
32
216
cursor .close ()
33
- conn .close ()
217
+ conn .close ()
0 commit comments