Files
MemeMind-Server/src/modules/share/repositories/share-participant.repository.ts
2026-05-10 16:04:21 +08:00

177 lines
5.2 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ShareParticipant } from '../entities/share-participant.entity';
type ShareParticipantCountRow = {
shareConfigId: string;
participantCount: string;
};
export type ShareParticipantRankingRow = {
shareConfigId: string;
participantId: string;
correctCount: number;
totalTimeSpent: number;
submittedAt: Date;
};
@Injectable()
export class ShareParticipantRepository {
constructor(
@InjectRepository(ShareParticipant)
private readonly repository: Repository<ShareParticipant>,
) {}
/** 添加参与者(已存在则忽略) */
async addParticipant(
shareConfigId: string,
participantId: string,
): Promise<void> {
await this.repository
.createQueryBuilder()
.insert()
.into(ShareParticipant)
.values({ shareConfigId, participantId })
.orIgnore()
.execute();
}
async countByShareConfigId(shareConfigId: string): Promise<number> {
return this.repository.count({ where: { shareConfigId } });
}
async countByShareConfigIds(
shareConfigIds: string[],
): Promise<Map<string, number>> {
if (shareConfigIds.length === 0) {
return new Map();
}
const rows = await this.repository
.createQueryBuilder('participant')
.select('participant.shareConfigId', 'shareConfigId')
.addSelect('COUNT(*)', 'participantCount')
.where('participant.shareConfigId IN (:...shareConfigIds)', {
shareConfigIds,
})
.groupBy('participant.shareConfigId')
.getRawMany<ShareParticipantCountRow>();
return new Map(
rows.map((row) => [row.shareConfigId, Number(row.participantCount)]),
);
}
async upsertSubmissionSummary(data: {
shareConfigId: string;
participantId: string;
correctCount: number;
totalTimeSpent: number;
submittedAt: Date;
}): Promise<void> {
await this.repository
.createQueryBuilder()
.insert()
.into(ShareParticipant)
.values(data)
.orUpdate(
['correctCount', 'totalTimeSpent', 'submittedAt'],
['shareConfigId', 'participantId'],
)
.execute();
}
async countSubmittedByShareConfigId(shareConfigId: string): Promise<number> {
return this.repository
.createQueryBuilder('participant')
.where('participant.shareConfigId = :shareConfigId', { shareConfigId })
.andWhere('participant.submittedAt IS NOT NULL')
.getCount();
}
async countSubmittedByShareConfigIds(
shareConfigIds: string[],
): Promise<Map<string, number>> {
if (shareConfigIds.length === 0) {
return new Map();
}
const rows = await this.repository
.createQueryBuilder('participant')
.select('participant.shareConfigId', 'shareConfigId')
.addSelect('COUNT(*)', 'participantCount')
.where('participant.shareConfigId IN (:...shareConfigIds)', {
shareConfigIds,
})
.andWhere('participant.submittedAt IS NOT NULL')
.groupBy('participant.shareConfigId')
.getRawMany<ShareParticipantCountRow>();
return new Map(
rows.map((row) => [row.shareConfigId, Number(row.participantCount)]),
);
}
async findSubmittedRankingsByShareConfigId(
shareConfigId: string,
): Promise<ShareParticipantRankingRow[]> {
const rows = await this.repository
.createQueryBuilder('participant')
.where('participant.shareConfigId = :shareConfigId', { shareConfigId })
.andWhere('participant.submittedAt IS NOT NULL')
.orderBy('participant.correctCount', 'DESC')
.addOrderBy('participant.totalTimeSpent', 'ASC')
.addOrderBy('participant.submittedAt', 'ASC')
.addOrderBy('participant.participantId', 'ASC')
.getMany();
return rows.map((row) => ({
shareConfigId: row.shareConfigId,
participantId: row.participantId,
correctCount: row.correctCount,
totalTimeSpent: row.totalTimeSpent,
submittedAt: row.submittedAt!,
}));
}
async findSubmittedRankingsByShareConfigIds(
shareConfigIds: string[],
): Promise<ShareParticipantRankingRow[]> {
if (shareConfigIds.length === 0) {
return [];
}
const rows = await this.repository
.createQueryBuilder('participant')
.where('participant.shareConfigId IN (:...shareConfigIds)', {
shareConfigIds,
})
.andWhere('participant.submittedAt IS NOT NULL')
.orderBy('participant.shareConfigId', 'ASC')
.addOrderBy('participant.correctCount', 'DESC')
.addOrderBy('participant.totalTimeSpent', 'ASC')
.addOrderBy('participant.submittedAt', 'ASC')
.addOrderBy('participant.participantId', 'ASC')
.getMany();
return rows.map((row) => ({
shareConfigId: row.shareConfigId,
participantId: row.participantId,
correctCount: row.correctCount,
totalTimeSpent: row.totalTimeSpent,
submittedAt: row.submittedAt!,
}));
}
async existsByShareConfigAndParticipant(
shareConfigId: string,
participantId: string,
): Promise<boolean> {
const count = await this.repository.count({
where: { shareConfigId, participantId },
});
return count > 0;
}
}