diff --git a/backend/services/reporting-service/prisma/schema.prisma b/backend/services/reporting-service/prisma/schema.prisma index f4c8718b..9100bd1f 100644 --- a/backend/services/reporting-service/prisma/schema.prisma +++ b/backend/services/reporting-service/prisma/schema.prisma @@ -386,7 +386,7 @@ model RealtimeStats { id BigInt @id @default(autoincrement()) @map("stats_id") // === 统计日期 === - statsDate DateTime @map("stats_date") @db.Date + statsDate DateTime @unique(map: "uk_realtime_stats_date") @map("stats_date") @db.Date // === 认种统计 (来自 planting.order.paid) === dailyPlantingCount Int @default(0) @map("daily_planting_count") @@ -405,7 +405,6 @@ model RealtimeStats { updatedAt DateTime @updatedAt @map("updated_at") @@map("realtime_stats") - @@unique([statsDate], name: "uk_realtime_stats_date") @@index([statsDate(sort: Desc)], name: "idx_rs_date") } 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 fa5fd4c3..9f59120b 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,7 +15,7 @@ export class RealtimeStatsRepository implements IRealtimeStatsRepository { async getOrCreateByDate(date: Date): Promise { const statsDate = this.normalizeDate(date); - const existing = await this.prisma.realtimeStats.findFirst({ + const existing = await this.prisma.realtimeStats.findUnique({ where: { statsDate }, }); @@ -33,7 +33,7 @@ export class RealtimeStatsRepository implements IRealtimeStatsRepository { async findByDate(date: Date): Promise { const statsDate = this.normalizeDate(date); - const found = await this.prisma.realtimeStats.findFirst({ + const found = await this.prisma.realtimeStats.findUnique({ where: { statsDate }, }); @@ -54,85 +54,57 @@ export class RealtimeStatsRepository implements IRealtimeStatsRepository { `Incrementing planting: date=${statsDate.toISOString()}, trees=${safeTreeCount}, amount=${safeAmount}`, ); - // 使用 findFirst + create/update 替代 upsert,避免 Prisma 唯一约束语法问题 - const existing = await this.prisma.realtimeStats.findFirst({ + const result = await this.prisma.realtimeStats.upsert({ where: { statsDate }, + create: { + statsDate, + dailyPlantingCount: safeTreeCount, + dailyOrderCount: 1, + dailyPlantingAmount: safeAmount, + }, + update: { + dailyPlantingCount: { increment: safeTreeCount }, + dailyOrderCount: { increment: 1 }, + dailyPlantingAmount: { increment: safeAmount }, + }, }); - 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); - } + return this.toDomain(result); } async incrementOrder(date: Date): Promise { const statsDate = this.normalizeDate(date); - const existing = await this.prisma.realtimeStats.findFirst({ + const result = await this.prisma.realtimeStats.upsert({ where: { statsDate }, + create: { + statsDate, + dailyOrderCount: 1, + }, + update: { + dailyOrderCount: { increment: 1 }, + }, }); - 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); - } + return this.toDomain(result); } async incrementNewUser(date: Date): Promise { const statsDate = this.normalizeDate(date); this.logger.debug(`Incrementing new user: date=${statsDate.toISOString()}`); - const existing = await this.prisma.realtimeStats.findFirst({ + const result = await this.prisma.realtimeStats.upsert({ where: { statsDate }, + create: { + statsDate, + dailyNewUserCount: 1, + }, + update: { + dailyNewUserCount: { increment: 1 }, + }, }); - 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); - } + return this.toDomain(result); } async incrementProvinceAuth(date: Date): Promise { @@ -141,54 +113,36 @@ export class RealtimeStatsRepository implements IRealtimeStatsRepository { `Incrementing province auth: date=${statsDate.toISOString()}`, ); - const existing = await this.prisma.realtimeStats.findFirst({ + const result = await this.prisma.realtimeStats.upsert({ where: { statsDate }, + create: { + statsDate, + dailyProvinceAuthCount: 1, + }, + update: { + dailyProvinceAuthCount: { increment: 1 }, + }, }); - 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); - } + return this.toDomain(result); } async incrementCityAuth(date: Date): Promise { const statsDate = this.normalizeDate(date); this.logger.debug(`Incrementing city auth: date=${statsDate.toISOString()}`); - const existing = await this.prisma.realtimeStats.findFirst({ + const result = await this.prisma.realtimeStats.upsert({ where: { statsDate }, + create: { + statsDate, + dailyCityAuthCount: 1, + }, + update: { + dailyCityAuthCount: { increment: 1 }, + }, }); - 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); - } + return this.toDomain(result); } async findRecentDays(days: number): Promise {