@hotmeshio/hotmesh 0.24.1 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/package.json
CHANGED
|
@@ -315,6 +315,26 @@ const KVTables = (context) => ({
|
|
|
315
315
|
CREATE INDEX IF NOT EXISTS idx_hmsh_esc_task
|
|
316
316
|
ON public.hmsh_escalations(task_id)
|
|
317
317
|
WHERE task_id IS NOT NULL;
|
|
318
|
+
`);
|
|
319
|
+
// v0.25.0: escalationStats indexes. Callers filter by role (optional) and
|
|
320
|
+
// namespace (optional) — never namespace-first — so the pending index leads
|
|
321
|
+
// with role and the two windowed indexes lead with their time column: the
|
|
322
|
+
// scan stays window-bounded even for unfiltered (admin) calls. Trailing
|
|
323
|
+
// columns cover every column the stats aggregates touch, keeping each of
|
|
324
|
+
// the three CTE scans index-only.
|
|
325
|
+
await client.query(`
|
|
326
|
+
CREATE INDEX IF NOT EXISTS idx_hmsh_esc_stats_pending
|
|
327
|
+
ON public.hmsh_escalations(role, type, assigned_to, assigned_until, namespace)
|
|
328
|
+
WHERE status = 'pending';
|
|
329
|
+
`);
|
|
330
|
+
await client.query(`
|
|
331
|
+
CREATE INDEX IF NOT EXISTS idx_hmsh_esc_stats_created
|
|
332
|
+
ON public.hmsh_escalations(created_at, role, namespace);
|
|
333
|
+
`);
|
|
334
|
+
await client.query(`
|
|
335
|
+
CREATE INDEX IF NOT EXISTS idx_hmsh_esc_stats_resolved
|
|
336
|
+
ON public.hmsh_escalations(resolved_at, type, role, namespace)
|
|
337
|
+
WHERE status = 'resolved';
|
|
318
338
|
`);
|
|
319
339
|
await client.query('COMMIT');
|
|
320
340
|
},
|
|
@@ -440,6 +460,23 @@ const KVTables = (context) => ({
|
|
|
440
460
|
CREATE INDEX IF NOT EXISTS idx_hmsh_esc_task
|
|
441
461
|
ON public.hmsh_escalations(task_id)
|
|
442
462
|
WHERE task_id IS NOT NULL;
|
|
463
|
+
`);
|
|
464
|
+
// escalationStats indexes: role/time-led so aggregate scans stay
|
|
465
|
+
// bounded (backlog or window) and index-only. See migrate() for
|
|
466
|
+
// the column-order rationale.
|
|
467
|
+
await client.query(`
|
|
468
|
+
CREATE INDEX IF NOT EXISTS idx_hmsh_esc_stats_pending
|
|
469
|
+
ON public.hmsh_escalations(role, type, assigned_to, assigned_until, namespace)
|
|
470
|
+
WHERE status = 'pending';
|
|
471
|
+
`);
|
|
472
|
+
await client.query(`
|
|
473
|
+
CREATE INDEX IF NOT EXISTS idx_hmsh_esc_stats_created
|
|
474
|
+
ON public.hmsh_escalations(created_at, role, namespace);
|
|
475
|
+
`);
|
|
476
|
+
await client.query(`
|
|
477
|
+
CREATE INDEX IF NOT EXISTS idx_hmsh_esc_stats_resolved
|
|
478
|
+
ON public.hmsh_escalations(resolved_at, type, role, namespace)
|
|
479
|
+
WHERE status = 'resolved';
|
|
443
480
|
`);
|
|
444
481
|
break;
|
|
445
482
|
case 'relational_connection':
|
|
@@ -2051,45 +2051,65 @@ class PostgresStoreService extends __1.StoreService {
|
|
|
2051
2051
|
queryParams.push(namespace);
|
|
2052
2052
|
if (roles?.length)
|
|
2053
2053
|
queryParams.push(roles);
|
|
2054
|
+
// Three bounded sources instead of one all-history scan (v0.25.0):
|
|
2055
|
+
// backlog — status='pending' partial (bounded by queue depth, never history)
|
|
2056
|
+
// created — created_at window range (all statuses)
|
|
2057
|
+
// resolved — status='resolved' + resolved_at window range
|
|
2058
|
+
// Totals derive from the grouped CTEs (NULL role/type groups included, so
|
|
2059
|
+
// totals match the pre-0.25.0 all-row counts); NULL groups are excluded
|
|
2060
|
+
// only from the by_role/by_type rollups, as before. resolved_at is only
|
|
2061
|
+
// ever set alongside status='resolved' (and never survives a transition
|
|
2062
|
+
// back to pending), so the status predicate is a pure index enabler.
|
|
2063
|
+
// Roles/types with no pending rows and no window activity no longer emit
|
|
2064
|
+
// zero-count rollup entries.
|
|
2054
2065
|
const result = await this.pgClient.query(`
|
|
2055
|
-
WITH
|
|
2056
|
-
SELECT * FROM public.hmsh_escalations
|
|
2057
|
-
WHERE true ${nsClause} ${rolClause}
|
|
2058
|
-
),
|
|
2059
|
-
totals AS (
|
|
2060
|
-
SELECT
|
|
2061
|
-
COUNT(*) FILTER (WHERE status = 'pending')::int AS pending,
|
|
2062
|
-
COUNT(*) FILTER (WHERE status = 'pending'
|
|
2063
|
-
AND assigned_to IS NOT NULL
|
|
2064
|
-
AND assigned_until IS NOT NULL AND assigned_until > NOW())::int AS claimed,
|
|
2065
|
-
COUNT(*) FILTER (WHERE created_at >= NOW() - ($1 * INTERVAL '1 hour'))::int AS created,
|
|
2066
|
-
COUNT(*) FILTER (WHERE resolved_at >= NOW() - ($1 * INTERVAL '1 hour'))::int AS resolved
|
|
2067
|
-
FROM base
|
|
2068
|
-
),
|
|
2069
|
-
by_role AS (
|
|
2066
|
+
WITH pending_by_role AS (
|
|
2070
2067
|
SELECT role,
|
|
2071
|
-
COUNT(*)
|
|
2072
|
-
COUNT(*) FILTER (WHERE
|
|
2073
|
-
AND assigned_to IS NOT NULL
|
|
2068
|
+
COUNT(*)::int AS pending,
|
|
2069
|
+
COUNT(*) FILTER (WHERE assigned_to IS NOT NULL
|
|
2074
2070
|
AND assigned_until IS NOT NULL AND assigned_until > NOW())::int AS claimed
|
|
2075
|
-
FROM
|
|
2071
|
+
FROM public.hmsh_escalations
|
|
2072
|
+
WHERE status = 'pending' ${nsClause} ${rolClause}
|
|
2076
2073
|
GROUP BY role
|
|
2077
2074
|
),
|
|
2078
|
-
|
|
2075
|
+
pending_by_type AS (
|
|
2079
2076
|
SELECT type,
|
|
2080
|
-
COUNT(*)
|
|
2081
|
-
COUNT(*) FILTER (WHERE
|
|
2082
|
-
AND
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2077
|
+
COUNT(*)::int AS pending,
|
|
2078
|
+
COUNT(*) FILTER (WHERE assigned_to IS NOT NULL
|
|
2079
|
+
AND assigned_until IS NOT NULL AND assigned_until > NOW())::int AS claimed
|
|
2080
|
+
FROM public.hmsh_escalations
|
|
2081
|
+
WHERE status = 'pending' ${nsClause} ${rolClause}
|
|
2082
|
+
GROUP BY type
|
|
2083
|
+
),
|
|
2084
|
+
created_agg AS (
|
|
2085
|
+
SELECT COUNT(*)::int AS created
|
|
2086
|
+
FROM public.hmsh_escalations
|
|
2087
|
+
WHERE created_at >= NOW() - ($1 * INTERVAL '1 hour') ${nsClause} ${rolClause}
|
|
2088
|
+
),
|
|
2089
|
+
resolved_by_type AS (
|
|
2090
|
+
SELECT type, COUNT(*)::int AS resolved
|
|
2091
|
+
FROM public.hmsh_escalations
|
|
2092
|
+
WHERE status = 'resolved'
|
|
2093
|
+
AND resolved_at >= NOW() - ($1 * INTERVAL '1 hour') ${nsClause} ${rolClause}
|
|
2086
2094
|
GROUP BY type
|
|
2087
2095
|
)
|
|
2088
2096
|
SELECT
|
|
2089
|
-
|
|
2090
|
-
COALESCE((SELECT
|
|
2091
|
-
|
|
2092
|
-
|
|
2097
|
+
COALESCE((SELECT SUM(pending)::int FROM pending_by_role), 0) AS pending,
|
|
2098
|
+
COALESCE((SELECT SUM(claimed)::int FROM pending_by_role), 0) AS claimed,
|
|
2099
|
+
(SELECT created FROM created_agg) AS created,
|
|
2100
|
+
COALESCE((SELECT SUM(resolved)::int FROM resolved_by_type), 0) AS resolved,
|
|
2101
|
+
COALESCE((SELECT json_agg(json_build_object('role',role,'pending',pending,'claimed',claimed))
|
|
2102
|
+
FROM pending_by_role WHERE role IS NOT NULL), '[]'::json) AS by_role,
|
|
2103
|
+
COALESCE((SELECT json_agg(json_build_object('type',t.type,'pending',t.pending,'claimed',t.claimed,'resolved',t.resolved))
|
|
2104
|
+
FROM (
|
|
2105
|
+
SELECT COALESCE(p.type, r.type) AS type,
|
|
2106
|
+
COALESCE(p.pending, 0) AS pending,
|
|
2107
|
+
COALESCE(p.claimed, 0) AS claimed,
|
|
2108
|
+
COALESCE(r.resolved, 0) AS resolved
|
|
2109
|
+
FROM pending_by_type p
|
|
2110
|
+
FULL OUTER JOIN resolved_by_type r ON r.type = p.type
|
|
2111
|
+
WHERE COALESCE(p.type, r.type) IS NOT NULL
|
|
2112
|
+
) t), '[]'::json) AS by_type
|
|
2093
2113
|
`, queryParams);
|
|
2094
2114
|
const row = result.rows[0];
|
|
2095
2115
|
return {
|