From 4e201d3a665e8b560d784d3bd6be55b7c9501215 Mon Sep 17 00:00:00 2001 From: hailin Date: Tue, 6 Jan 2026 21:36:26 -0800 Subject: [PATCH] fix(reporting-service): use findFirst + update instead of upsert for realtimeStats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace upsert with findFirst + create/update pattern to avoid Prisma unique constraint syntax issues. The @@unique constraint with a custom name doesn't allow direct field-based queries in findUnique/upsert. This approach maintains the same behavior without schema changes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../realtime-stats.repository.impl.ts | 162 +++++++++++------- 1 file changed, 104 insertions(+), 58 deletions(-) diff --git a/backend/services/reporting-service/src/infrastructure/persistence/repositories/realtime-stats.repository.impl.ts b/backend/services/reporting-service/src/infrastructure/persistence/repositories/realtime-stats.repository.impl.ts index 0cbba232..fa5fd4c3 100644 --- a/backend/services/reporting-service/src/infrastructure/persistence/repositories/realtime-stats.repository.impl.ts +++ b/backend/services/reporting-service/src/infrastructure/persistence/repositories/realtime-stats.repository.impl.ts @@ -15,8 +15,8 @@ export class RealtimeStatsRepository implements IRealtimeStatsRepository { async getOrCreateByDate(date: Date): Promise { const statsDate = this.normalizeDate(date); - const existing = await this.prisma.realtimeStats.findUnique({ - where: { uk_realtime_stats_date: { statsDate } }, + const existing = await this.prisma.realtimeStats.findFirst({ + where: { statsDate }, }); if (existing) { @@ -33,8 +33,8 @@ export class RealtimeStatsRepository implements IRealtimeStatsRepository { async findByDate(date: Date): Promise { const statsDate = this.normalizeDate(date); - const found = await this.prisma.realtimeStats.findUnique({ - where: { uk_realtime_stats_date: { statsDate } }, + const found = await this.prisma.realtimeStats.findFirst({ + where: { statsDate }, }); return found ? this.toDomain(found) : null; @@ -54,57 +54,85 @@ export class RealtimeStatsRepository implements IRealtimeStatsRepository { `Incrementing planting: date=${statsDate.toISOString()}, trees=${safeTreeCount}, amount=${safeAmount}`, ); - const result = await this.prisma.realtimeStats.upsert({ - where: { uk_realtime_stats_date: { statsDate } }, - create: { - statsDate, - dailyPlantingCount: safeTreeCount, - dailyOrderCount: 1, - dailyPlantingAmount: safeAmount, - }, - update: { - dailyPlantingCount: { increment: safeTreeCount }, - dailyOrderCount: { increment: 1 }, - dailyPlantingAmount: { increment: safeAmount }, - }, + // 使用 findFirst + create/update 替代 upsert,避免 Prisma 唯一约束语法问题 + const existing = await this.prisma.realtimeStats.findFirst({ + where: { statsDate }, }); - return this.toDomain(result); + if (existing) { + const result = await this.prisma.realtimeStats.update({ + where: { id: existing.id }, + data: { + dailyPlantingCount: { increment: safeTreeCount }, + dailyOrderCount: { increment: 1 }, + dailyPlantingAmount: { increment: safeAmount }, + }, + }); + return this.toDomain(result); + } else { + const result = await this.prisma.realtimeStats.create({ + data: { + statsDate, + dailyPlantingCount: safeTreeCount, + dailyOrderCount: 1, + dailyPlantingAmount: safeAmount, + }, + }); + return this.toDomain(result); + } } async incrementOrder(date: Date): Promise { const statsDate = this.normalizeDate(date); - const result = await this.prisma.realtimeStats.upsert({ - where: { uk_realtime_stats_date: { statsDate } }, - create: { - statsDate, - dailyOrderCount: 1, - }, - update: { - dailyOrderCount: { increment: 1 }, - }, + const existing = await this.prisma.realtimeStats.findFirst({ + where: { statsDate }, }); - return this.toDomain(result); + if (existing) { + const result = await this.prisma.realtimeStats.update({ + where: { id: existing.id }, + data: { + dailyOrderCount: { increment: 1 }, + }, + }); + return this.toDomain(result); + } else { + const result = await this.prisma.realtimeStats.create({ + data: { + statsDate, + dailyOrderCount: 1, + }, + }); + return this.toDomain(result); + } } async incrementNewUser(date: Date): Promise { const statsDate = this.normalizeDate(date); this.logger.debug(`Incrementing new user: date=${statsDate.toISOString()}`); - const result = await this.prisma.realtimeStats.upsert({ - where: { uk_realtime_stats_date: { statsDate } }, - create: { - statsDate, - dailyNewUserCount: 1, - }, - update: { - dailyNewUserCount: { increment: 1 }, - }, + const existing = await this.prisma.realtimeStats.findFirst({ + where: { statsDate }, }); - return this.toDomain(result); + if (existing) { + const result = await this.prisma.realtimeStats.update({ + where: { id: existing.id }, + data: { + dailyNewUserCount: { increment: 1 }, + }, + }); + return this.toDomain(result); + } else { + const result = await this.prisma.realtimeStats.create({ + data: { + statsDate, + dailyNewUserCount: 1, + }, + }); + return this.toDomain(result); + } } async incrementProvinceAuth(date: Date): Promise { @@ -113,36 +141,54 @@ export class RealtimeStatsRepository implements IRealtimeStatsRepository { `Incrementing province auth: date=${statsDate.toISOString()}`, ); - const result = await this.prisma.realtimeStats.upsert({ - where: { uk_realtime_stats_date: { statsDate } }, - create: { - statsDate, - dailyProvinceAuthCount: 1, - }, - update: { - dailyProvinceAuthCount: { increment: 1 }, - }, + const existing = await this.prisma.realtimeStats.findFirst({ + where: { statsDate }, }); - return this.toDomain(result); + if (existing) { + const result = await this.prisma.realtimeStats.update({ + where: { id: existing.id }, + data: { + dailyProvinceAuthCount: { increment: 1 }, + }, + }); + return this.toDomain(result); + } else { + const result = await this.prisma.realtimeStats.create({ + data: { + statsDate, + dailyProvinceAuthCount: 1, + }, + }); + return this.toDomain(result); + } } async incrementCityAuth(date: Date): Promise { const statsDate = this.normalizeDate(date); this.logger.debug(`Incrementing city auth: date=${statsDate.toISOString()}`); - const result = await this.prisma.realtimeStats.upsert({ - where: { uk_realtime_stats_date: { statsDate } }, - create: { - statsDate, - dailyCityAuthCount: 1, - }, - update: { - dailyCityAuthCount: { increment: 1 }, - }, + const existing = await this.prisma.realtimeStats.findFirst({ + where: { statsDate }, }); - return this.toDomain(result); + if (existing) { + const result = await this.prisma.realtimeStats.update({ + where: { id: existing.id }, + data: { + dailyCityAuthCount: { increment: 1 }, + }, + }); + return this.toDomain(result); + } else { + const result = await this.prisma.realtimeStats.create({ + data: { + statsDate, + dailyCityAuthCount: 1, + }, + }); + return this.toDomain(result); + } } async findRecentDays(days: number): Promise {