90 lines
2.4 KiB
TypeScript
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,
|
|
},
|
|
};
|
|
}
|
|
}
|