team rating
This commit is contained in:
106
core/racing/application/queries/GetTeamRatingLedgerQuery.ts
Normal file
106
core/racing/application/queries/GetTeamRatingLedgerQuery.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Query: GetTeamRatingLedgerQuery
|
||||
*
|
||||
* Paginated/filtered query for team rating events (ledger).
|
||||
* Mirrors user slice 6 pattern but for teams.
|
||||
*/
|
||||
|
||||
import { TeamLedgerEntryDto, TeamLedgerFilter, PaginatedTeamLedgerResult } from '../dtos/TeamLedgerEntryDto';
|
||||
import { ITeamRatingEventRepository, PaginatedQueryOptions, TeamRatingEventFilter } from '../../domain/repositories/ITeamRatingEventRepository';
|
||||
|
||||
export interface GetTeamRatingLedgerQuery {
|
||||
teamId: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
filter?: TeamLedgerFilter;
|
||||
}
|
||||
|
||||
export class GetTeamRatingLedgerQueryHandler {
|
||||
constructor(
|
||||
private readonly ratingEventRepo: ITeamRatingEventRepository
|
||||
) {}
|
||||
|
||||
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,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user