1
0

feat: target 软删除机制,配置移除时保留历史数据

This commit is contained in:
2026-05-20 00:43:39 +08:00
parent 9b53c746f6
commit b591dcca97
7 changed files with 294 additions and 38 deletions

View File

@@ -17,7 +17,8 @@ CREATE TABLE IF NOT EXISTS targets (
interval_ms INTEGER NOT NULL,
timeout_ms INTEGER NOT NULL,
expect TEXT,
grp TEXT NOT NULL DEFAULT 'default'
grp TEXT NOT NULL DEFAULT 'default',
active INTEGER NOT NULL DEFAULT 1
)
`;
@@ -30,7 +31,7 @@ CREATE TABLE IF NOT EXISTS check_results (
duration_ms REAL,
observation TEXT,
failure TEXT,
FOREIGN KEY (target_id) REFERENCES targets(id) ON DELETE CASCADE
FOREIGN KEY (target_id) REFERENCES targets(id) ON DELETE RESTRICT
)
`;
@@ -58,6 +59,11 @@ export class ProbeStore {
this.db.close();
}
deleteTargetRaw(id: string): void {
if (this.closed) return;
this.db.run("DELETE FROM targets WHERE id = ?", [id]);
}
getAllRecentSamples(
limit: number,
): Map<string, Array<{ duration_ms: null | number; matched: number; timestamp: string }>> {
@@ -74,6 +80,7 @@ export class ProbeStore {
matched,
ROW_NUMBER() OVER (PARTITION BY target_id ORDER BY timestamp DESC) as row_num
FROM check_results
WHERE target_id IN (SELECT id FROM targets WHERE active = 1)
)
WHERE row_num <= ?
ORDER BY target_id, timestamp DESC`,
@@ -107,6 +114,7 @@ export class ProbeStore {
COALESCE(SUM(CASE WHEN matched = 0 THEN 1 ELSE 0 END), 0) as downChecks
FROM check_results
WHERE timestamp >= ? AND timestamp <= ?
AND target_id IN (SELECT id FROM targets WHERE active = 1)
GROUP BY target_id`,
)
.all(from, to) as Array<{ downChecks: number; target_id: string; totalChecks: number; upChecks: number }>;
@@ -138,6 +146,7 @@ export class ProbeStore {
`SELECT target_id, timestamp, matched
FROM check_results
WHERE timestamp >= ? AND timestamp <= ?
AND target_id IN (SELECT id FROM targets WHERE active = 1)
ORDER BY target_id ASC, timestamp ASC`,
)
.all(from, to) as Array<{ matched: number; target_id: string; timestamp: string }>;
@@ -177,6 +186,7 @@ export class ProbeStore {
INNER JOIN (
SELECT target_id, MAX(timestamp) as max_ts
FROM check_results
WHERE target_id IN (SELECT id FROM targets WHERE active = 1)
GROUP BY target_id
) latest ON cr.target_id = latest.target_id AND cr.timestamp = latest.max_ts`,
)
@@ -199,9 +209,15 @@ export class ProbeStore {
}>;
}
getTargetActive(id: string): null | number {
if (this.closed) return null;
const row = this.db.query("SELECT active FROM targets WHERE id = ?").get(id) as null | { active: number };
return row?.active ?? null;
}
getTargetById(id: string): null | StoredTarget {
if (this.closed) return null;
return this.db.query("SELECT * FROM targets WHERE id = ?").get(id) as null | StoredTarget;
return this.db.query("SELECT * FROM targets WHERE id = ? AND active = 1").get(id) as null | StoredTarget;
}
getTargetCheckpoints(
@@ -239,7 +255,7 @@ export class ProbeStore {
getTargets(): StoredTarget[] {
if (this.closed) return [];
return this.db
.query("SELECT * FROM targets ORDER BY CASE WHEN grp='default' THEN 0 ELSE 1 END, id")
.query("SELECT * FROM targets WHERE active = 1 ORDER BY CASE WHEN grp='default' THEN 0 ELSE 1 END, id")
.all() as StoredTarget[];
}
@@ -277,6 +293,12 @@ export class ProbeStore {
};
}
hasTargetRow(id: string): boolean {
if (this.closed) return false;
const row = this.db.query("SELECT 1 FROM targets WHERE id = ?").get(id) as null | { "1": number };
return row !== null;
}
insertCheckResult(result: {
durationMs: null | number;
failure: CheckFailure | null;
@@ -304,6 +326,9 @@ export class ProbeStore {
if (this.closed) return 0;
const cutoff = new Date(Date.now() - retentionMs).toISOString();
const result = this.db.run("DELETE FROM check_results WHERE timestamp < ?", [cutoff]);
this.db.run(
"DELETE FROM targets WHERE active = 0 AND NOT EXISTS (SELECT 1 FROM check_results WHERE check_results.target_id = targets.id)",
);
return result.changes;
}
@@ -317,9 +342,9 @@ export class ProbeStore {
"INSERT INTO targets (id, name, description, type, target, config, interval_ms, timeout_ms, expect, grp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
);
const updateStmt = this.db.prepare(
"UPDATE targets SET name = ?, description = ?, type = ?, target = ?, config = ?, interval_ms = ?, timeout_ms = ?, expect = ?, grp = ? WHERE id = ?",
"UPDATE targets SET name = ?, description = ?, type = ?, target = ?, config = ?, interval_ms = ?, timeout_ms = ?, expect = ?, grp = ?, active = 1 WHERE id = ?",
);
const deleteStmt = this.db.prepare("DELETE FROM targets WHERE id = ?");
const deactivateStmt = this.db.prepare("UPDATE targets SET active = 0 WHERE id = ? AND active = 1");
const tx = this.db.transaction(() => {
for (const t of targets) {
@@ -338,7 +363,7 @@ export class ProbeStore {
for (const id of existingIds) {
if (!configIds.has(id)) {
deleteStmt.run(id);
deactivateStmt.run(id);
}
}
});

View File

@@ -66,6 +66,7 @@ export interface StoredCheckResult {
}
export interface StoredTarget {
active: number;
config: string;
description: null | string;
expect: null | string;