Skip to content

Commit b6fd7f5

Browse files
committed
Better performance when calculating 'isLatest', which should help with the submissions endpoint
1 parent d6c9749 commit b6fd7f5

File tree

2 files changed

+79
-26
lines changed

2 files changed

+79
-26
lines changed

src/api/review-summation/review-summation.controller.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,14 +179,15 @@ export class ReviewSummationController {
179179
`Getting review summations with filters - ${JSON.stringify(queryDto)}`,
180180
);
181181
const authUser: JwtUser = req['user'] as JwtUser;
182+
const wantsTabSeparated = this.requestWantsTabSeparated(req);
182183
const results = await this.service.searchSummation(
183184
authUser,
184185
queryDto,
185186
paginationDto,
186187
sortDto,
187188
);
188189

189-
if (!this.requestWantsTabSeparated(req)) {
190+
if (!wantsTabSeparated) {
190191
return results;
191192
}
192193

@@ -199,7 +200,13 @@ export class ReviewSummationController {
199200
});
200201
}
201202

202-
const payload = this.buildReviewSummationTsv(results);
203+
const completeResults = await this.loadAllReviewSummationsForExport(
204+
authUser,
205+
queryDto,
206+
sortDto,
207+
results,
208+
);
209+
const payload = this.buildReviewSummationTsv(completeResults);
203210
const safeChallengeSlug = this.buildFilenameSlug(challengeId);
204211
const filename = `${ReviewSummationController.TSV_FILENAME_PREFIX}-${safeChallengeSlug}.tsv`;
205212
res.setHeader(
@@ -321,6 +328,28 @@ export class ReviewSummationController {
321328
};
322329
}
323330

331+
private async loadAllReviewSummationsForExport(
332+
authUser: JwtUser,
333+
queryDto: ReviewSummationQueryDto,
334+
sortDto: SortDto | undefined,
335+
initialResults: PaginatedResponse<ReviewSummationResponseDto>,
336+
): Promise<PaginatedResponse<ReviewSummationResponseDto>> {
337+
const totalCount =
338+
initialResults.meta?.totalCount ?? initialResults.data.length;
339+
const currentCount = initialResults.data.length;
340+
341+
if (!Number.isFinite(totalCount) || totalCount <= currentCount) {
342+
return initialResults;
343+
}
344+
345+
return this.service.searchSummation(
346+
authUser,
347+
queryDto,
348+
{ page: 1, perPage: totalCount },
349+
sortDto,
350+
);
351+
}
352+
324353
private requestWantsTabSeparated(req: Request): boolean {
325354
const acceptHeader = Array.isArray(req.headers.accept)
326355
? req.headers.accept.join(',')

src/api/submission/submission.service.ts

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3085,34 +3085,58 @@ export class SubmissionService {
30853085
return;
30863086
}
30873087

3088-
const latestIds = new Set<string>();
3089-
await Promise.all(
3090-
Array.from(uniquePairs.values()).map(
3091-
async ({ challengeId, memberId }) => {
3092-
const latest = await this.prisma.submission.findFirst({
3093-
where: {
3094-
challengeId,
3095-
memberId,
3096-
},
3097-
orderBy: [
3098-
{ submittedDate: 'desc' },
3099-
{ createdAt: 'desc' },
3100-
{ updatedAt: 'desc' },
3101-
],
3102-
select: { id: true },
3103-
});
3104-
3105-
if (latest?.id) {
3106-
latestIds.add(latest.id);
3107-
}
3108-
},
3088+
const challengeIds = Array.from(
3089+
new Set(
3090+
Array.from(uniquePairs.values()).map((entry) => entry.challengeId),
31093091
),
31103092
);
3093+
const memberIds = Array.from(
3094+
new Set(Array.from(uniquePairs.values()).map((entry) => entry.memberId)),
3095+
);
31113096

3112-
for (const submission of submissions) {
3113-
if (latestIds.has(submission.id)) {
3114-
(submission as any).isLatest = true;
3097+
if (!challengeIds.length || !memberIds.length) {
3098+
return;
3099+
}
3100+
3101+
try {
3102+
// Use a single windowed query to locate the latest submission per (challengeId, memberId)
3103+
const latestEntries = await this.prisma.$queryRaw<
3104+
Array<{ id: string }>
3105+
>(Prisma.sql`
3106+
SELECT "id"
3107+
FROM (
3108+
SELECT
3109+
"id",
3110+
ROW_NUMBER() OVER (
3111+
PARTITION BY "challengeId", "memberId"
3112+
ORDER BY "submittedDate" DESC NULLS LAST,
3113+
"createdAt" DESC,
3114+
"updatedAt" DESC NULLS LAST
3115+
) AS row_num
3116+
FROM "submission"
3117+
WHERE "challengeId" IN (${Prisma.join(challengeIds)})
3118+
AND "memberId" IN (${Prisma.join(memberIds)})
3119+
) ranked
3120+
WHERE row_num = 1
3121+
`);
3122+
3123+
const latestIds = new Set(
3124+
latestEntries
3125+
.map((entry) => String(entry.id ?? '').trim())
3126+
.filter((id) => id.length > 0),
3127+
);
3128+
3129+
for (const submission of submissions) {
3130+
if (latestIds.has(submission.id)) {
3131+
(submission as any).isLatest = true;
3132+
}
31153133
}
3134+
} catch (error) {
3135+
const message = error instanceof Error ? error.message : String(error);
3136+
this.logger.warn(
3137+
`[populateLatestSubmissionFlags] Failed to resolve latest submissions via bulk query: ${message}`,
3138+
);
3139+
throw error;
31163140
}
31173141
}
31183142

0 commit comments

Comments
 (0)