refactor db

This commit is contained in:
2026-04-09 19:18:04 +04:00
parent a58030323a
commit 29a9d6cea6
8 changed files with 109 additions and 139 deletions
+2 -2
View File
@@ -32,8 +32,8 @@ export async function dispatchForMonitor(monitorId: string, event: NotificationE
const channels = await sql<ChannelRow[]>`
SELECT c.id, c.account_id, c.name, c.kind, c.config, c.enabled
FROM notification_channels c
JOIN monitor_notifications mn ON mn.channel_id = c.id
WHERE mn.monitor_id = ${monitorId} AND c.enabled = true
WHERE c.id = ANY((SELECT channel_ids FROM monitors WHERE id = ${monitorId}))
AND c.enabled = true
`;
if (channels.length === 0) return;
await Promise.all(channels.map((c) => dispatch(c, event)));
+5
View File
@@ -89,6 +89,11 @@ export const channels = new Elysia({ prefix: "/notifications/channels" })
RETURNING id
`;
if (!row) { set.status = 404; return { error: "Not found" }; }
// Remove this channel from any monitors that reference it.
await sql`
UPDATE monitors SET channel_ids = array_remove(channel_ids, ${params.id}::uuid)
WHERE account_id = ${accountId} AND ${params.id}::uuid = ANY(channel_ids)
`;
return { deleted: true };
}, { detail: { summary: "Delete notification channel", tags: ["notifications"] } })
+31 -44
View File
@@ -23,28 +23,18 @@ const MonitorBody = t.Object({
tags: t.Optional(t.Array(t.String({ pattern: "^[a-z0-9][a-z0-9-]{0,40}$" }), { description: "Lowercase tag slugs for grouping. Replaces the existing tag set." })),
});
async function replaceMonitorTags(monitorId: string, tags: string[]) {
await sql`DELETE FROM monitor_tags WHERE monitor_id = ${monitorId}`;
if (tags.length === 0) return;
const unique = Array.from(new Set(tags.map((t) => t.trim()).filter(Boolean)));
if (unique.length === 0) return;
const rows = unique.map((tag) => ({ monitor_id: monitorId, tag }));
await sql`INSERT INTO monitor_tags ${sql(rows, "monitor_id", "tag")}`;
function dedupeTags(tags: string[]): string[] {
return Array.from(new Set(tags.map((t) => t.trim()).filter(Boolean)));
}
async function replaceMonitorChannels(monitorId: string, accountId: string, channelIds: string[]) {
await sql`DELETE FROM monitor_notifications WHERE monitor_id = ${monitorId}`;
if (channelIds.length === 0) return;
// Only attach channels that belong to the same account. Cast to uuid[] so the
// ANY() comparison against the uuid id column type-checks.
async function validateChannelIds(accountId: string, channelIds: string[]): Promise<string[]> {
if (channelIds.length === 0) return [];
const owned = await sql<{ id: string }[]>`
SELECT id FROM notification_channels
WHERE account_id = ${accountId}
AND id = ANY(${sql.array(channelIds)}::uuid[])
`;
if (owned.length === 0) return;
const rows = owned.map((o) => ({ monitor_id: monitorId, channel_id: o.id }));
await sql`INSERT INTO monitor_notifications ${sql(rows, "monitor_id", "channel_id")}`;
return owned.map((o) => o.id);
}
export const monitors = new Elysia({ prefix: "/monitors" })
@@ -54,10 +44,9 @@ export const monitors = new Elysia({ prefix: "/monitors" })
const tag = (query as any)?.tag;
if (tag) {
return sql`
SELECT m.* FROM monitors m
JOIN monitor_tags mt ON mt.monitor_id = m.id
WHERE m.account_id = ${accountId} AND mt.tag = ${tag}
ORDER BY m.created_at DESC
SELECT * FROM monitors
WHERE account_id = ${accountId} AND ${tag} = ANY(tags)
ORDER BY created_at DESC
`;
}
return sql`SELECT * FROM monitors WHERE account_id = ${accountId} ORDER BY created_at DESC`;
@@ -92,8 +81,10 @@ export const monitors = new Elysia({ prefix: "/monitors" })
const ssrfError = await validateMonitorUrl(body.url);
if (ssrfError) { set.status = 400; return { error: ssrfError }; }
const tags = body.tags ? dedupeTags(body.tags) : [];
const channelIds = body.channel_ids ? await validateChannelIds(accountId, body.channel_ids) : [];
const [monitor] = await sql`
INSERT INTO monitors (account_id, name, url, method, request_headers, request_body, timeout_ms, interval_s, max_retries, retry_interval_s, resend_interval, cert_alert_days, query, regions)
INSERT INTO monitors (account_id, name, url, method, request_headers, request_body, timeout_ms, interval_s, max_retries, retry_interval_s, resend_interval, cert_alert_days, query, regions, tags, channel_ids)
VALUES (
${accountId}, ${body.name}, ${body.url},
${(body.method ?? 'GET').toUpperCase()},
@@ -106,12 +97,12 @@ export const monitors = new Elysia({ prefix: "/monitors" })
${body.resend_interval ?? 0},
${body.cert_alert_days ?? 0},
${body.query ? sql.json(body.query) : null},
${sql.array(regions)}
${sql.array(regions)},
${sql.array(tags)},
${sql.array(channelIds)}::uuid[]
)
RETURNING *
`;
if (body.channel_ids) await replaceMonitorChannels(monitor.id, accountId, body.channel_ids);
if (body.tags) await replaceMonitorTags(monitor.id, body.tags);
invalidateMonitorList();
return monitor;
}, { body: MonitorBody, detail: { summary: "Create monitor", tags: ["monitors"] } })
@@ -126,13 +117,7 @@ export const monitors = new Elysia({ prefix: "/monitors" })
SELECT * FROM pings WHERE monitor_id = ${params.id}
ORDER BY checked_at DESC LIMIT 100
`;
const channels = await sql<{ channel_id: string }[]>`
SELECT channel_id FROM monitor_notifications WHERE monitor_id = ${params.id}
`;
const tagRows = await sql<{ tag: string }[]>`
SELECT tag FROM monitor_tags WHERE monitor_id = ${params.id} ORDER BY tag
`;
return { ...monitor, results, channel_ids: channels.map((c) => c.channel_id), tags: tagRows.map((t) => t.tag) };
return { ...monitor, results };
}, { detail: { summary: "Get monitor with results", tags: ["monitors"] } })
.patch("/:id", async ({ accountId, plan, params, body, set }) => {
@@ -158,27 +143,29 @@ export const monitors = new Elysia({ prefix: "/monitors" })
if (ssrfError) { set.status = 400; return { error: ssrfError }; }
}
const validatedChannelIds = body.channel_ids ? await validateChannelIds(accountId, body.channel_ids) : null;
const [monitor] = await sql`
UPDATE monitors SET
name = COALESCE(${body.name ?? null}, name),
url = COALESCE(${body.url ?? null}, url),
method = COALESCE(${body.method ? body.method.toUpperCase() : null}, method),
request_headers = COALESCE(${body.request_headers ? sql.json(body.request_headers) : null}, request_headers),
request_body = COALESCE(${body.request_body ?? null}, request_body),
timeout_ms = COALESCE(${body.timeout_ms ?? null}, timeout_ms),
interval_s = COALESCE(${body.interval_s ?? null}, interval_s),
max_retries = COALESCE(${body.max_retries ?? null}, max_retries),
name = COALESCE(${body.name ?? null}, name),
url = COALESCE(${body.url ?? null}, url),
method = COALESCE(${body.method ? body.method.toUpperCase() : null}, method),
request_headers = COALESCE(${body.request_headers ? sql.json(body.request_headers) : null}, request_headers),
request_body = COALESCE(${body.request_body ?? null}, request_body),
timeout_ms = COALESCE(${body.timeout_ms ?? null}, timeout_ms),
interval_s = COALESCE(${body.interval_s ?? null}, interval_s),
max_retries = COALESCE(${body.max_retries ?? null}, max_retries),
retry_interval_s = COALESCE(${body.retry_interval_s ?? null}, retry_interval_s),
resend_interval = COALESCE(${body.resend_interval ?? null}, resend_interval),
cert_alert_days = COALESCE(${body.cert_alert_days ?? null}, cert_alert_days),
query = COALESCE(${body.query ? sql.json(body.query) : null}, query),
regions = COALESCE(${body.regions ? sql.array(body.regions) : null}, regions)
resend_interval = COALESCE(${body.resend_interval ?? null}, resend_interval),
cert_alert_days = COALESCE(${body.cert_alert_days ?? null}, cert_alert_days),
query = COALESCE(${body.query ? sql.json(body.query) : null}, query),
regions = COALESCE(${body.regions ? sql.array(body.regions) : null}, regions),
tags = COALESCE(${body.tags ? sql.array(dedupeTags(body.tags)) : null}, tags),
channel_ids = COALESCE(${validatedChannelIds ? sql.array(validatedChannelIds) : null}::uuid[], channel_ids),
updated_at = now()
WHERE id = ${params.id} AND account_id = ${accountId}
RETURNING *
`;
if (!monitor) { set.status = 404; return { error: "Not found" }; }
if (body.channel_ids) await replaceMonitorChannels(monitor.id, accountId, body.channel_ids);
if (body.tags) await replaceMonitorTags(monitor.id, body.tags);
invalidateMonitorList();
return monitor;
}, { body: t.Partial(MonitorBody), detail: { summary: "Update monitor", tags: ["monitors"] } })
+3 -3
View File
@@ -81,7 +81,6 @@ export const ingest = new Elysia()
if (!monitor_check) { set.status = 404; return { error: "Monitor not found" }; }
const meta = body.meta ? { ...body.meta } : {};
if (body.cert_expiry_days != null) meta.cert_expiry_days = body.cert_expiry_days;
const responseBody: string | null = meta.body_preview ?? null;
delete meta.body_preview;
@@ -133,7 +132,7 @@ export const ingest = new Elysia()
`;
const [ping] = await sql`
INSERT INTO pings (monitor_id, checked_at, scheduled_at, jitter_ms, status_code, latency_ms, up, important, error, meta, region, run_id)
INSERT INTO pings (monitor_id, checked_at, scheduled_at, jitter_ms, status_code, latency_ms, up, important, error, meta, region, run_id, cert_expiry_days)
VALUES (
${body.monitor_id},
${checkedAt ?? sql`now()`},
@@ -146,7 +145,8 @@ export const ingest = new Elysia()
${body.error ?? null},
${Object.keys(meta).length > 0 ? sql.json(meta) : null},
${region},
${body.run_id ?? null}
${body.run_id ?? null},
${body.cert_expiry_days ?? null}
)
RETURNING *
`;