2026-08-06 14:41:39 -05:00
|
|
|
import { and, asc, eq, gte, lt, lte } from "drizzle-orm";
|
2026-07-19 12:29:52 -05:00
|
|
|
import { hostMetricsHistory } from "../db/schema.js";
|
|
|
|
|
import type { DatabaseContext } from "./database-context.js";
|
2026-08-06 14:41:39 -05:00
|
|
|
import { sqlTimestampDaysAgo } from "./sql-timestamp.js";
|
2026-07-19 12:29:52 -05:00
|
|
|
|
|
|
|
|
export type HostMetricsHistoryRecord = typeof hostMetricsHistory.$inferSelect;
|
|
|
|
|
|
|
|
|
|
export interface HostMetricsHistoryCreateInput {
|
|
|
|
|
hostId: number;
|
|
|
|
|
cpuPercent?: number | null;
|
|
|
|
|
memPercent?: number | null;
|
|
|
|
|
diskPercent?: number | null;
|
|
|
|
|
netRxBytes?: number | null;
|
|
|
|
|
netTxBytes?: number | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class HostMetricsHistoryRepository {
|
|
|
|
|
constructor(
|
|
|
|
|
private readonly context: DatabaseContext,
|
|
|
|
|
private readonly onWrite?: () => void | Promise<void>,
|
|
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
async create(input: HostMetricsHistoryCreateInput): Promise<void> {
|
|
|
|
|
await this.context.drizzle.insert(hostMetricsHistory).values({
|
|
|
|
|
hostId: input.hostId,
|
|
|
|
|
cpuPercent: input.cpuPercent,
|
|
|
|
|
memPercent: input.memPercent,
|
|
|
|
|
diskPercent: input.diskPercent,
|
|
|
|
|
netRxBytes: input.netRxBytes,
|
|
|
|
|
netTxBytes: input.netTxBytes,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await this.afterWrite();
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-06 14:41:39 -05:00
|
|
|
async pruneOlderThan(hostId: number, retentionDays: number): Promise<void> {
|
|
|
|
|
await this.context.drizzle
|
|
|
|
|
.delete(hostMetricsHistory)
|
|
|
|
|
.where(
|
|
|
|
|
and(
|
|
|
|
|
eq(hostMetricsHistory.hostId, hostId),
|
|
|
|
|
lt(hostMetricsHistory.ts, sqlTimestampDaysAgo(retentionDays)),
|
|
|
|
|
),
|
|
|
|
|
);
|
2026-07-19 12:29:52 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async listRange(
|
|
|
|
|
hostId: number,
|
|
|
|
|
fromTs: string,
|
|
|
|
|
toTs: string,
|
|
|
|
|
): Promise<HostMetricsHistoryRecord[]> {
|
|
|
|
|
return this.context.drizzle
|
|
|
|
|
.select()
|
|
|
|
|
.from(hostMetricsHistory)
|
|
|
|
|
.where(
|
|
|
|
|
and(
|
|
|
|
|
eq(hostMetricsHistory.hostId, hostId),
|
|
|
|
|
gte(hostMetricsHistory.ts, fromTs),
|
|
|
|
|
lte(hostMetricsHistory.ts, toTs),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
.orderBy(asc(hostMetricsHistory.ts));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async afterWrite(): Promise<void> {
|
|
|
|
|
await this.onWrite?.();
|
|
|
|
|
}
|
|
|
|
|
}
|