Browse Source

refactor(repo): migrate overview.ts read paths to usage_ledger

- getOverviewMetrics: read from usageLedger instead of messageRequest
- getOverviewMetricsWithComparison: same migration for all 3 parallel queries
- Error rate: statusCode >= 400 -> NOT isSuccess (pre-computed boolean)
- EXCLUDE_WARMUP_CONDITION -> LEDGER_BILLING_CONDITION
- Removed deletedAt null checks (ledger has no deletedAt)
ding113 1 week ago
parent
commit
399cf65518
2 changed files with 56 additions and 31 deletions
  1. 29 0
      .sisyphus/evidence/task-9-overview-migrated.txt
  2. 27 31
      src/repository/overview.ts

+ 29 - 0
.sisyphus/evidence/task-9-overview-migrated.txt

@@ -0,0 +1,29 @@
+Task 9: Migrate overview.ts read paths to usage_ledger
+========================================================
+
+File: src/repository/overview.ts
+
+Changes:
+- Imports: messageRequest -> usageLedger, EXCLUDE_WARMUP_CONDITION -> LEDGER_BILLING_CONDITION
+- Removed: isNull import (no deletedAt on ledger)
+
+getOverviewMetrics():
+- .from(messageRequest) -> .from(usageLedger)
+- messageRequest.costUsd -> usageLedger.costUsd
+- messageRequest.durationMs -> usageLedger.durationMs
+- messageRequest.createdAt -> usageLedger.createdAt
+- Error rate: statusCode >= 400 -> NOT isSuccess (pre-computed boolean)
+- Removed: isNull(messageRequest.deletedAt)
+- EXCLUDE_WARMUP_CONDITION -> LEDGER_BILLING_CONDITION
+
+getOverviewMetricsWithComparison():
+- Same pattern as above for all 3 parallel queries (today, yesterday, RPM)
+- messageRequest.userId -> usageLedger.userId
+- Error rate: statusCode >= 400 -> NOT isSuccess
+
+Interfaces unchanged:
+- OverviewMetrics: todayRequests, todayCost, avgResponseTime, todayErrorRate
+- OverviewMetricsWithComparison: extends OverviewMetrics + yesterday comparison + RPM
+
+Verification:
+- bun run typecheck: EXIT_CODE:0 (clean)

+ 27 - 31
src/repository/overview.ts

@@ -1,11 +1,11 @@
 "use server";
 
-import { and, avg, count, eq, gte, isNull, lt, sql, sum } from "drizzle-orm";
+import { and, avg, count, eq, gte, lt, sql, sum } from "drizzle-orm";
 import { db } from "@/drizzle/db";
-import { messageRequest } from "@/drizzle/schema";
+import { usageLedger } from "@/drizzle/schema";
 import { Decimal, toCostDecimal } from "@/lib/utils/currency";
 import { resolveSystemTimezone } from "@/lib/utils/timezone";
-import { EXCLUDE_WARMUP_CONDITION } from "./_shared/message-request-conditions";
+import { LEDGER_BILLING_CONDITION } from "./_shared/ledger-conditions";
 
 /**
  * 今日概览统计数据
@@ -50,17 +50,16 @@ export async function getOverviewMetrics(): Promise<OverviewMetrics> {
   const [result] = await db
     .select({
       requestCount: count(),
-      totalCost: sum(messageRequest.costUsd),
-      avgDuration: avg(messageRequest.durationMs),
-      errorCount: sql<number>`count(*) FILTER (WHERE ${messageRequest.statusCode} >= 400)`,
+      totalCost: sum(usageLedger.costUsd),
+      avgDuration: avg(usageLedger.durationMs),
+      errorCount: sql<number>`count(*) FILTER (WHERE NOT ${usageLedger.isSuccess})`,
     })
-    .from(messageRequest)
+    .from(usageLedger)
     .where(
       and(
-        isNull(messageRequest.deletedAt),
-        EXCLUDE_WARMUP_CONDITION,
-        gte(messageRequest.createdAt, todayStart),
-        lt(messageRequest.createdAt, tomorrowStart)
+        LEDGER_BILLING_CONDITION,
+        gte(usageLedger.createdAt, todayStart),
+        lt(usageLedger.createdAt, tomorrowStart)
       )
     );
 
@@ -104,7 +103,7 @@ export async function getOverviewMetricsWithComparison(
   const yesterdayEnd = sql`(${yesterdayEndLocal} AT TIME ZONE ${timezone})`;
 
   // 用户过滤条件
-  const userCondition = userId ? eq(messageRequest.userId, userId) : undefined;
+  const userCondition = userId ? eq(usageLedger.userId, userId) : undefined;
 
   // 并行查询今日数据、昨日同时段数据、最近1分钟数据
   const [todayResult, yesterdayResult, rpmResult] = await Promise.all([
@@ -112,18 +111,17 @@ export async function getOverviewMetricsWithComparison(
     db
       .select({
         requestCount: count(),
-        totalCost: sum(messageRequest.costUsd),
-        avgDuration: avg(messageRequest.durationMs),
-        errorCount: sql<number>`count(*) FILTER (WHERE ${messageRequest.statusCode} >= 400)`,
+        totalCost: sum(usageLedger.costUsd),
+        avgDuration: avg(usageLedger.durationMs),
+        errorCount: sql<number>`count(*) FILTER (WHERE NOT ${usageLedger.isSuccess})`,
       })
-      .from(messageRequest)
+      .from(usageLedger)
       .where(
         and(
-          isNull(messageRequest.deletedAt),
-          EXCLUDE_WARMUP_CONDITION,
+          LEDGER_BILLING_CONDITION,
           userCondition,
-          gte(messageRequest.createdAt, todayStart),
-          lt(messageRequest.createdAt, tomorrowStart)
+          gte(usageLedger.createdAt, todayStart),
+          lt(usageLedger.createdAt, tomorrowStart)
         )
       ),
 
@@ -131,17 +129,16 @@ export async function getOverviewMetricsWithComparison(
     db
       .select({
         requestCount: count(),
-        totalCost: sum(messageRequest.costUsd),
-        avgDuration: avg(messageRequest.durationMs),
+        totalCost: sum(usageLedger.costUsd),
+        avgDuration: avg(usageLedger.durationMs),
       })
-      .from(messageRequest)
+      .from(usageLedger)
       .where(
         and(
-          isNull(messageRequest.deletedAt),
-          EXCLUDE_WARMUP_CONDITION,
+          LEDGER_BILLING_CONDITION,
           userCondition,
-          gte(messageRequest.createdAt, yesterdayStart),
-          lt(messageRequest.createdAt, yesterdayEnd)
+          gte(usageLedger.createdAt, yesterdayStart),
+          lt(usageLedger.createdAt, yesterdayEnd)
         )
       ),
 
@@ -150,13 +147,12 @@ export async function getOverviewMetricsWithComparison(
       .select({
         requestCount: count(),
       })
-      .from(messageRequest)
+      .from(usageLedger)
       .where(
         and(
-          isNull(messageRequest.deletedAt),
-          EXCLUDE_WARMUP_CONDITION,
+          LEDGER_BILLING_CONDITION,
           userCondition,
-          gte(messageRequest.createdAt, sql`CURRENT_TIMESTAMP - INTERVAL '1 minute'`)
+          gte(usageLedger.createdAt, sql`CURRENT_TIMESTAMP - INTERVAL '1 minute'`)
         )
       ),
   ]);