5
5
eq ,
6
6
getTableColumns ,
7
7
inArray ,
8
+ InferSelectModel ,
8
9
isNull ,
9
10
or ,
10
11
sql ,
@@ -86,8 +87,17 @@ type Params = {
86
87
difficulty ?: string ;
87
88
} ;
88
89
90
+ type IGetRandomQuestionResponse = InferSelectModel < typeof QUESTIONS_TABLE > & {
91
+ attemptCount : number ;
92
+ } ;
93
+
89
94
// Fetch an unattempted question or fallback to the least attempted one
90
- export const getRandomQuestion = async ( { userId1, userId2, topics, difficulty } : Params ) => {
95
+ export const getRandomQuestion = async ( {
96
+ userId1,
97
+ userId2,
98
+ topics,
99
+ difficulty,
100
+ } : Params ) : Promise < IGetRandomQuestionResponse | null > => {
91
101
// If an attempt contains either user's ID
92
102
const ids = [ userId1 , userId2 ] ;
93
103
const userIdClause = [
@@ -128,14 +138,15 @@ export const getRandomQuestion = async ({ userId1, userId2, topics, difficulty }
128
138
}
129
139
130
140
for ( const filterClause of filterCombinations ) {
131
- // Check if questions exist with current filters
132
- const questionExists = await db
133
- . select ( { count : sql < number > `count(*)` } )
141
+ // Check if AT LEAST 1 question exists with current filters
142
+ const questionCounts = await db
143
+ . select ( { id : QUESTIONS_TABLE . id } )
134
144
. from ( QUESTIONS_TABLE )
135
145
. where ( and ( ...filterClause ) )
136
- . then ( ( result ) => Number ( result [ 0 ] . count ) > 0 ) ;
146
+ . limit ( 1 ) ;
137
147
138
- if ( ! questionExists ) {
148
+ // No questions exist with the filter.
149
+ if ( ! questionCounts || ! questionCounts . length ) {
139
150
continue ;
140
151
}
141
152
@@ -149,28 +160,33 @@ export const getRandomQuestion = async ({ userId1, userId2, topics, difficulty }
149
160
. limit ( 1 ) ;
150
161
151
162
if ( bothUnattempted && bothUnattempted . length > 0 ) {
152
- return bothUnattempted [ 0 ] . question ;
163
+ return { ... bothUnattempted [ 0 ] . question , attemptCount : 0 } ;
153
164
}
154
165
155
166
// If no unattempted question, try least attempted
156
- const attempts = db . $with ( 'at' ) . as (
157
- db
158
- . select ( {
159
- ...getTableColumns ( QUESTIONS_TABLE ) ,
160
- user1Count :
161
- sql `SUM(CASE WHEN ${ QUESTION_ATTEMPTS_TABLE . userId1 } = ${ userId1 } ::uuid OR ${ QUESTION_ATTEMPTS_TABLE . userId2 } = ${ userId1 } ::uuid THEN 1 END)` . as (
162
- 'user1_attempts'
163
- ) ,
164
- user2Count :
165
- sql `SUM(CASE WHEN ${ QUESTION_ATTEMPTS_TABLE . userId1 } = ${ userId2 } ::uuid OR ${ QUESTION_ATTEMPTS_TABLE . userId2 } = ${ userId2 } ::uuid THEN 1 END)` . as (
166
- 'user2_attempts'
167
- ) ,
168
- } )
169
- . from ( QUESTIONS_TABLE )
170
- . innerJoin ( QUESTION_ATTEMPTS_TABLE , and ( ...joinClause ) )
171
- . where ( and ( ...filterClause ) )
172
- . groupBy ( QUESTIONS_TABLE . id )
173
- ) ;
167
+ let nestedQuery = db
168
+ . select ( {
169
+ ...getTableColumns ( QUESTIONS_TABLE ) ,
170
+ user1Count :
171
+ sql `SUM(CASE WHEN ${ QUESTION_ATTEMPTS_TABLE . userId1 } = ${ userId1 } ::uuid OR ${ QUESTION_ATTEMPTS_TABLE . userId2 } = ${ userId1 } ::uuid THEN 1 END)` . as (
172
+ 'user1_attempts'
173
+ ) ,
174
+ user2Count :
175
+ sql `SUM(CASE WHEN ${ QUESTION_ATTEMPTS_TABLE . userId1 } = ${ userId2 } ::uuid OR ${ QUESTION_ATTEMPTS_TABLE . userId2 } = ${ userId2 } ::uuid THEN 1 END)` . as (
176
+ 'user2_attempts'
177
+ ) ,
178
+ } )
179
+ . from ( QUESTIONS_TABLE )
180
+ . innerJoin ( QUESTION_ATTEMPTS_TABLE , and ( ...joinClause ) )
181
+ . $dynamic ( ) ;
182
+
183
+ if ( filterClause . length ) {
184
+ nestedQuery = nestedQuery . where ( and ( ...filterClause ) ) ;
185
+ }
186
+
187
+ nestedQuery = nestedQuery . groupBy ( QUESTIONS_TABLE . id ) ;
188
+
189
+ const attempts = db . $with ( 'at' ) . as ( nestedQuery ) ;
174
190
175
191
const result = await db
176
192
. with ( attempts )
@@ -180,7 +196,10 @@ export const getRandomQuestion = async ({ userId1, userId2, topics, difficulty }
180
196
. limit ( 1 ) ;
181
197
182
198
if ( result && result . length > 0 ) {
183
- return { ...result [ 0 ] , user1Count : undefined , user2Count : undefined } ;
199
+ const { user1Count, user2Count, ...details } = result [ 0 ] ;
200
+ const attemptCount =
201
+ ( user1Count ? ( user1Count as number ) : 0 ) + ( user2Count ? ( user2Count as number ) : 0 ) ;
202
+ return { ...details , attemptCount } ;
184
203
}
185
204
}
186
205
0 commit comments