Files
gridpilot.gg/core/racing/application/queries/GetTeamRatingLedgerQuery.ts
2026-01-16 19:46:49 +01:00

106 lines
3.0 KiB
TypeScript

/**
* Query: GetTeamRatingLedgerQuery
*
* Paginated/filtered query for team rating events (ledger).
* Mirrors user slice 6 pattern but for teams.
*/
import { PaginatedQueryOptions, TeamRatingEventFilter, TeamRatingEventRepository } from '../../domain/repositories/TeamRatingEventRepository';
import { PaginatedTeamLedgerResult, TeamLedgerEntryDto, TeamLedgerFilter } from '../dtos/TeamLedgerEntryDto';
export interface GetTeamRatingLedgerQuery {
teamId: string;
limit?: number;
offset?: number;
filter?: TeamLedgerFilter;
}
export class GetTeamRatingLedgerQueryHandler {
constructor(
private readonly ratingEventRepo: TeamRatingEventRepository
) {}
async execute(query: GetTeamRatingLedgerQuery): Promise<PaginatedTeamLedgerResult> {
const { teamId, limit = 20, offset = 0, filter } = query;
// Build repo options
const repoOptions: PaginatedQueryOptions = {
limit,
offset,
};
// Add filter if provided
if (filter) {
const ratingEventFilter: TeamRatingEventFilter = {};
if (filter.dimensions) {
ratingEventFilter.dimensions = filter.dimensions;
}
if (filter.sourceTypes) {
ratingEventFilter.sourceTypes = filter.sourceTypes;
}
if (filter.from) {
ratingEventFilter.from = new Date(filter.from);
}
if (filter.to) {
ratingEventFilter.to = new Date(filter.to);
}
if (filter.reasonCodes) {
ratingEventFilter.reasonCodes = filter.reasonCodes;
}
repoOptions.filter = ratingEventFilter;
}
// Query repository
const result = await this.ratingEventRepo.findEventsPaginated(teamId, repoOptions);
// Convert domain entities to DTOs
const entries: TeamLedgerEntryDto[] = result.items.map(event => {
const source: { type: 'race' | 'penalty' | 'vote' | 'adminAction' | 'manualAdjustment'; id?: string } = {
type: event.source.type,
};
if (event.source.id !== undefined) {
source.id = event.source.id;
}
const reason: { code: string; description?: string } = {
code: event.reason.code,
};
if (event.reason.description !== undefined) {
reason.description = event.reason.description;
}
const dto: TeamLedgerEntryDto = {
id: event.id.value,
teamId: event.teamId,
dimension: event.dimension.value,
delta: event.delta.value,
occurredAt: event.occurredAt.toISOString(),
createdAt: event.createdAt.toISOString(),
source,
reason,
visibility: {
public: event.visibility.public,
},
};
if (event.weight !== undefined) {
dto.weight = event.weight;
}
return dto;
});
const nextOffset = result.nextOffset !== undefined ? result.nextOffset : null;
return {
entries,
pagination: {
total: result.total,
limit: result.limit,
offset: result.offset,
hasMore: result.hasMore,
nextOffset,
},
};
}
}