166 lines
5.7 KiB
TypeScript
166 lines
5.7 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
import { Repository } from 'typeorm';
|
|
import { BaseTenantRepository, TenantContextService } from '@iconsulting/shared';
|
|
import { ConversationORM } from '../../../infrastructure/database/postgres/entities/conversation.orm';
|
|
import { IConversationRepository } from '../../../domain/repositories/conversation.repository.interface';
|
|
import {
|
|
ConversationEntity,
|
|
ConversationStatusType,
|
|
} from '../../../domain/entities/conversation.entity';
|
|
|
|
@Injectable()
|
|
export class ConversationPostgresRepository
|
|
extends BaseTenantRepository<ConversationEntity, ConversationORM>
|
|
implements IConversationRepository
|
|
{
|
|
constructor(
|
|
@InjectRepository(ConversationORM) repo: Repository<ConversationORM>,
|
|
tenantContext: TenantContextService,
|
|
) {
|
|
super(repo, tenantContext);
|
|
}
|
|
|
|
async save(conversation: ConversationEntity): Promise<ConversationEntity> {
|
|
const orm = this.toORM(conversation);
|
|
orm.tenantId = this.getTenantId();
|
|
const saved = await this.repo.save(orm);
|
|
return this.toEntity(saved);
|
|
}
|
|
|
|
async findById(id: string): Promise<ConversationEntity | null> {
|
|
const orm = await this.findOneWithTenant({ id } as any);
|
|
return orm ? this.toEntity(orm) : null;
|
|
}
|
|
|
|
async findByUserId(
|
|
userId: string,
|
|
options?: { status?: ConversationStatusType; limit?: number },
|
|
): Promise<ConversationEntity[]> {
|
|
const queryBuilder = this.createTenantQueryBuilder('conversation')
|
|
.andWhere('conversation.user_id = :userId', { userId })
|
|
.andWhere('conversation.status != :deletedStatus', { deletedStatus: 'DELETED' });
|
|
|
|
if (options?.status) {
|
|
queryBuilder.andWhere('conversation.status = :status', { status: options.status });
|
|
}
|
|
|
|
queryBuilder.orderBy('conversation.created_at', 'DESC');
|
|
|
|
if (options?.limit) {
|
|
queryBuilder.limit(options.limit);
|
|
}
|
|
|
|
const orms = await queryBuilder.getMany();
|
|
return orms.map((orm) => this.toEntity(orm));
|
|
}
|
|
|
|
async findForEvolution(options: {
|
|
status?: ConversationStatusType;
|
|
hoursBack?: number;
|
|
minMessageCount?: number;
|
|
}): Promise<ConversationEntity[]> {
|
|
const queryBuilder = this.createTenantQueryBuilder('conversation')
|
|
.andWhere('conversation.status != :deletedStatus', { deletedStatus: 'DELETED' });
|
|
|
|
if (options.status) {
|
|
queryBuilder.andWhere('conversation.status = :status', { status: options.status });
|
|
}
|
|
|
|
if (options.hoursBack) {
|
|
const cutoffDate = new Date();
|
|
cutoffDate.setHours(cutoffDate.getHours() - options.hoursBack);
|
|
queryBuilder.andWhere('conversation.created_at >= :cutoffDate', { cutoffDate });
|
|
}
|
|
|
|
if (options.minMessageCount) {
|
|
queryBuilder.andWhere('conversation.message_count >= :minCount', {
|
|
minCount: options.minMessageCount,
|
|
});
|
|
}
|
|
|
|
const orms = await queryBuilder.getMany();
|
|
return orms.map((orm) => this.toEntity(orm));
|
|
}
|
|
|
|
async update(conversation: ConversationEntity): Promise<ConversationEntity> {
|
|
const orm = this.toORM(conversation);
|
|
orm.tenantId = this.getTenantId();
|
|
const updated = await this.repo.save(orm);
|
|
return this.toEntity(updated);
|
|
}
|
|
|
|
async count(options?: { status?: ConversationStatusType; daysBack?: number }): Promise<number> {
|
|
const queryBuilder = this.createTenantQueryBuilder('conversation');
|
|
|
|
if (options?.status) {
|
|
queryBuilder.andWhere('conversation.status = :status', { status: options.status });
|
|
}
|
|
|
|
if (options?.daysBack) {
|
|
const cutoffDate = new Date();
|
|
cutoffDate.setDate(cutoffDate.getDate() - options.daysBack);
|
|
queryBuilder.andWhere('conversation.created_at >= :cutoffDate', { cutoffDate });
|
|
}
|
|
|
|
return queryBuilder.getCount();
|
|
}
|
|
|
|
private toORM(entity: ConversationEntity): ConversationORM {
|
|
const orm = new ConversationORM();
|
|
orm.id = entity.id;
|
|
orm.tenantId = this.getTenantId();
|
|
orm.userId = entity.userId;
|
|
orm.status = entity.status;
|
|
orm.title = entity.title;
|
|
orm.summary = entity.summary;
|
|
orm.category = entity.category;
|
|
orm.messageCount = entity.messageCount;
|
|
orm.userMessageCount = entity.userMessageCount;
|
|
orm.assistantMessageCount = entity.assistantMessageCount;
|
|
orm.totalInputTokens = entity.totalInputTokens;
|
|
orm.totalOutputTokens = entity.totalOutputTokens;
|
|
orm.rating = entity.rating;
|
|
orm.feedback = entity.feedback;
|
|
orm.hasConverted = entity.hasConverted;
|
|
orm.consultingStage = entity.consultingStage;
|
|
orm.consultingState = entity.consultingState;
|
|
orm.collectedInfo = entity.collectedInfo;
|
|
orm.recommendedPrograms = entity.recommendedPrograms;
|
|
orm.conversionPath = entity.conversionPath;
|
|
orm.deviceInfo = entity.deviceInfo;
|
|
orm.createdAt = entity.createdAt;
|
|
orm.updatedAt = entity.updatedAt;
|
|
orm.endedAt = entity.endedAt;
|
|
return orm;
|
|
}
|
|
|
|
private toEntity(orm: ConversationORM): ConversationEntity {
|
|
return ConversationEntity.fromPersistence({
|
|
id: orm.id,
|
|
userId: orm.userId,
|
|
status: orm.status,
|
|
title: orm.title,
|
|
summary: orm.summary,
|
|
category: orm.category,
|
|
messageCount: orm.messageCount,
|
|
userMessageCount: orm.userMessageCount,
|
|
assistantMessageCount: orm.assistantMessageCount,
|
|
totalInputTokens: orm.totalInputTokens,
|
|
totalOutputTokens: orm.totalOutputTokens,
|
|
rating: orm.rating,
|
|
feedback: orm.feedback,
|
|
hasConverted: orm.hasConverted,
|
|
consultingStage: orm.consultingStage,
|
|
consultingState: orm.consultingState,
|
|
collectedInfo: orm.collectedInfo,
|
|
recommendedPrograms: orm.recommendedPrograms,
|
|
conversionPath: orm.conversionPath,
|
|
deviceInfo: orm.deviceInfo,
|
|
createdAt: orm.createdAt,
|
|
updatedAt: orm.updatedAt,
|
|
endedAt: orm.endedAt,
|
|
});
|
|
}
|
|
}
|