feat: harden analytics dashboard

This commit is contained in:
2026-05-27 15:19:31 +08:00
parent 5e0ca6a504
commit 356039d9cf
34 changed files with 1424 additions and 879 deletions

54
lib/query-shared.ts Normal file
View File

@@ -0,0 +1,54 @@
import { query } from "./db";
import { queryCache } from "./query-cache";
export const cached = queryCache.cached;
export function cacheKey(...parts: unknown[]): string {
return parts.map((p) => String(p ?? "")).join(":");
}
export const REAL_MODEL = `COALESCE(
CASE WHEN other IS NOT NULL AND other != '' AND other::jsonb ? 'upstream_model_name'
THEN other::jsonb->>'upstream_model_name' END,
model_name)`;
export const CACHE_CREATION = `COALESCE(
CASE WHEN other IS NOT NULL AND other != '' AND other::jsonb ? 'cache_creation_tokens'
THEN (other::jsonb->>'cache_creation_tokens')::bigint END,
0)`;
export const CACHE_READ = `COALESCE(
CASE WHEN other IS NOT NULL AND other != '' AND other::jsonb ? 'cache_tokens'
THEN (other::jsonb->>'cache_tokens')::bigint END,
0)`;
export const TOKEN_NAME = `COALESCE(NULLIF(BTRIM(token_name), ''), '')`;
export function timeWhere(
params: (string | number | boolean | null)[],
startTs?: number,
endTs?: number
): string {
let where = "type = 2";
if (startTs) {
params.push(startTs);
where += ` AND created_at >= $${params.length}`;
}
if (endTs) {
params.push(endTs);
where += ` AND created_at <= $${params.length}`;
}
return where;
}
export async function getDisplayNames(): Promise<Record<number, string>> {
const rows = await query(
"SELECT id, display_name FROM users WHERE display_name IS NOT NULL AND display_name != ''"
);
return Object.fromEntries(rows.map((r) => [r.id, r.display_name]));
}
export async function getChannelNames(): Promise<Record<number, string>> {
const rows = await query("SELECT id, name FROM channels");
return Object.fromEntries(rows.map((r) => [r.id, r.name]));
}