Files
gridpilot.gg/core/identity/application/queries/GetUserRatingLedgerQuery.ts
2026-01-16 16:46:57 +01:00

90 lines
2.4 KiB
TypeScript

/**
* Query: GetUserRatingLedgerQuery
*
* Paginated/filtered query for user rating events (ledger).
*/
import { LedgerEntryDto, LedgerFilter, PaginatedLedgerResult } from '../dtos/LedgerEntryDto';
import { RatingEventRepository, PaginatedQueryOptions, RatingEventFilter } from '../../domain/repositories/RatingEventRepository';
export interface GetUserRatingLedgerQuery {
userId: string;
limit?: number;
offset?: number;
filter?: LedgerFilter;
}
export class GetUserRatingLedgerQueryHandler {
constructor(
private readonly ratingEventRepo: RatingEventRepository
) {}
async execute(query: GetUserRatingLedgerQuery): Promise<PaginatedLedgerResult> {
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,
},
};
}
}