106 lines
3.0 KiB
TypeScript
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,
|
|
},
|
|
};
|
|
}
|
|
} |