/** * Query: GetUserRatingLedgerQuery * * Paginated/filtered query for user rating events (ledger). */ import { LedgerEntryDto, LedgerFilter, PaginatedLedgerResult } from '../dtos/LedgerEntryDto'; import { IRatingEventRepository, PaginatedQueryOptions, RatingEventFilter } from '../../domain/repositories/IRatingEventRepository'; export interface GetUserRatingLedgerQuery { userId: string; limit?: number; offset?: number; filter?: LedgerFilter; } export class GetUserRatingLedgerQueryHandler { constructor( private readonly ratingEventRepo: IRatingEventRepository ) {} async execute(query: GetUserRatingLedgerQuery): Promise { const { userId, limit = 20, offset = 0, filter } = query; // Build repo options const repoOptions: PaginatedQueryOptions = { limit, offset, }; // Add filter if provided if (filter) { const ratingEventFilter: RatingEventFilter = {}; 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(userId, repoOptions); // Convert domain entities to DTOs const entries: LedgerEntryDto[] = result.items.map(event => { const dto: LedgerEntryDto = { id: event.id.value, userId: event.userId, dimension: event.dimension.value, delta: event.delta.value, occurredAt: event.occurredAt.toISOString(), createdAt: event.createdAt.toISOString(), source: event.source, reason: event.reason, visibility: event.visibility, }; 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, }, }; } }