Skip to content

Commit 4bfe62d

Browse files
committed
rankings endpoint updates
1 parent 847a481 commit 4bfe62d

File tree

1 file changed

+79
-54
lines changed

1 file changed

+79
-54
lines changed

src/services/score-service.ts

Lines changed: 79 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export const getRankings = async (environment: Environment): Promise<RankingResu
6868
return acc;
6969
};
7070

71-
const participants = (await UserRepository.getUsersOfRole(Role.Participant)).reduce(reduceFunc, {});
71+
const participants = (await UserRepository.getUsersOfRole(Role.Participant)).filter(p => !p.disabled).reduce(reduceFunc, {});
7272
let scores: Score[] = [];
7373

7474
// For each participant, calculate their score
@@ -137,28 +137,17 @@ export const getRankings = async (environment: Environment): Promise<RankingResu
137137

138138
// Least moves and most completed mazes
139139
// -------------------------
140-
const leastMoves = await pgQuery<AwardWithProps<{ exitCount: number; moveCount: string }>>(
140+
const leastMoves = await pgQuery<AwardWithProps<{ exitCount: string; moveCount: string }>>(
141141
`
142-
WITH exit_counts AS (
143-
SELECT user_id, COUNT(*) as exit_count
144-
FROM actions
145-
WHERE maze_id = ANY($1) AND action_type = $2 AND success = true
146-
GROUP BY user_id
147-
),
148-
move_counts AS (
149-
SELECT user_id, COUNT(*) as move_count
150-
FROM actions
151-
WHERE maze_id = ANY($1) AND action_type = $3
152-
GROUP BY user_id
153-
)
154-
SELECT e.user_id, e.exit_count, m.move_count
155-
FROM exit_counts e
156-
JOIN move_counts m ON e.user_id = m.user_id
157-
WHERE e.exit_count = (SELECT MAX(exit_count) FROM exit_counts)
158-
AND m.move_count = (SELECT MIN(move_count) FROM move_counts)
159-
ORDER BY e.exit_count DESC, m.move_count ASC
142+
SELECT users.id as user_id,
143+
(SELECT COUNT(*) FROM actions WHERE user_id = users.id AND action_type = $1 AND success = TRUE) AS exit_count,
144+
(SELECT COUNT(*) FROM actions WHERE user_id = users.id AND action_type = $2 AND success = TRUE) AS move_count
145+
FROM users
146+
WHERE role = $3
147+
ORDER BY exit_count DESC, move_count ASC
148+
LIMIT 1;
160149
`,
161-
[mazeIds, ActionType.Exit, ActionType.Move],
150+
[ActionType.Exit, ActionType.Move, Role.Participant],
162151
);
163152

164153
const leastMovesAward: Award = {
@@ -169,18 +158,13 @@ export const getRankings = async (environment: Environment): Promise<RankingResu
169158

170159
// *AWARD* Least Moves
171160
if (leastMoves.length > 0) {
172-
// Because the query is ordered by exit_count DESC and move_count ASC, the first item represents the least moves
173-
const minMoveCount = leastMoves[0].moveCount;
174-
for (const result of leastMoves) {
175-
if (result.moveCount != minMoveCount) {
176-
break;
177-
}
161+
const result = leastMoves[0];
162+
163+
leastMovesAward.winners.push({
164+
userName: participants[result.userId.toString()].name,
165+
value: result.exitCount,
166+
});
178167

179-
leastMovesAward.winners.push({
180-
userName: participants[result.userId.toString()].name,
181-
value: result.moveCount,
182-
});
183-
}
184168
awards.push(leastMovesAward);
185169
}
186170

@@ -243,6 +227,43 @@ export const getRankings = async (environment: Environment): Promise<RankingResu
243227
}
244228
}
245229

230+
// Most Cheese Eaten
231+
// -------------------------
232+
const cheeseDropped = await pgQuery<AwardWithProps<{ cheeseCount: number }>>(
233+
`
234+
SELECT user_id, COUNT(*) as cheese_count
235+
FROM actions
236+
WHERE maze_id = ANY($1) AND action_type = $2 AND success = true
237+
GROUP BY user_id
238+
ORDER BY cheese_count DESC
239+
`,
240+
[mazeIds, ActionType.Drop],
241+
);
242+
243+
const mostCheeseDroppedAward: Award = {
244+
name: "Cheese Hoarder",
245+
description: "The rat who dropped the most cheese",
246+
winners: [],
247+
};
248+
249+
// *AWARD* Most Cheese Eaten
250+
if (cheeseDropped.length > 0) {
251+
// Because the query is ordered by cheese_count DESC, the first item represents the most cheese eaten
252+
const maxCheeseCount = cheeseDropped[0].cheeseCount;
253+
for (const result of cheeseDropped) {
254+
if (result.cheeseCount != maxCheeseCount) {
255+
break;
256+
}
257+
258+
mostCheeseDroppedAward.winners.push({
259+
userName: participants[result.userId.toString()].name,
260+
value: result.cheeseCount,
261+
});
262+
}
263+
264+
awards.push(mostCheeseDroppedAward);
265+
}
266+
246267
// Most smells
247268
// -------------------------
248269
const mostSmells = await pgQuery<AwardWithProps<{ smellCount: number }>>(
@@ -416,13 +437,16 @@ export const getRankings = async (environment: Environment): Promise<RankingResu
416437
// -------------------------
417438
const mostFailedActions = await pgQuery<AwardWithProps<{ failCount: number }>>(
418439
`
419-
SELECT user_id, COUNT(*) as fail_count
420-
FROM actions
421-
WHERE maze_id = ANY($1) AND success = false
422-
GROUP BY user_id
423-
ORDER BY fail_count DESC
440+
SELECT
441+
users.id as user_id,
442+
(SELECT COUNT(*) FROM actions WHERE user_id = users.id AND success = FALSE) AS fail_count
443+
FROM users
444+
WHERE role = $1
445+
AND disabled = FALSE
446+
ORDER BY fail_count DESC
447+
LIMIT 1;
424448
`,
425-
[mazeIds],
449+
[Role.Participant],
426450
);
427451

428452
const mostFailedActionsAward: Award = {
@@ -494,14 +518,16 @@ export const getRankings = async (environment: Environment): Promise<RankingResu
494518
// -------------------------
495519
const lastToHitAPI = await pgQuery<AwardWithProps<{ lastHit: string }>>(
496520
`
497-
SELECT user_id, MAX(time_ts) as last_hit
498-
FROM analytics
499-
WHERE user_id = ANY($1)
500-
GROUP BY user_id
501-
ORDER BY last_hit DESC
502-
LIMIT 1
521+
SELECT first_hits.user_id, first_hits.time_ts AS last_hit
522+
FROM (SELECT user_id, u.name AS name, MIN(time_ts) AS time_ts
523+
FROM analytics a
524+
LEFT JOIN users u ON a.user_id = u.id
525+
WHERE role = $1
526+
GROUP BY user_id, name) first_hits
527+
ORDER BY first_hits.time_ts DESC
528+
LIMIT 1;
503529
`,
504-
[Object.keys(participants)],
530+
[Role.Participant],
505531
);
506532
const lastToHitAPIAward: Award = {
507533
name: "Procrastinator",
@@ -520,16 +546,15 @@ export const getRankings = async (environment: Environment): Promise<RankingResu
520546

521547
// Hit the API first (Sandbox OR Competition)
522548
// -------------------------
523-
const firstToHitAPI = await pgQuery<AwardWithProps<{ firstHit: string }>>(
549+
const firstToHitAPI = await pgQuery<AwardWithProps<{ name: string; firstHit: string }>>(
524550
`
525-
SELECT user_id, MIN(time_ts) as first_hit
526-
FROM analytics
527-
WHERE user_id = ANY($1)
528-
GROUP BY user_id
529-
ORDER BY first_hit ASC
530-
LIMIT 1
551+
SELECT user_id, u.name as name, MIN(time_ts) as first_hit
552+
FROM analytics a left join users u on u.id = a.user_id
553+
GROUP BY user_id, u.name
554+
ORDER BY first_hit ASC
555+
LIMIT 1
531556
`,
532-
[Object.keys(participants)],
557+
[],
533558
);
534559

535560
const firstToHitAPIAward: Award = {
@@ -541,7 +566,7 @@ export const getRankings = async (environment: Environment): Promise<RankingResu
541566
// *AWARD* First to hit the API
542567
if (firstToHitAPI.length > 0) {
543568
firstToHitAPIAward.winners.push({
544-
userName: participants[firstToHitAPI[0].userId.toString()].name,
569+
userName: firstToHitAPI[0].name,
545570
value: firstToHitAPI[0].firstHit,
546571
});
547572
awards.push(firstToHitAPIAward);

0 commit comments

Comments
 (0)