Files
beacon-server/db/sqlc/series.sql.go
T
MrAlders0n ff8758b932 fix(db): read observer activity raw rows back to the rollup watermark
Hourly activity read raw rows only 3h back, so a longer rollup backlog left
hours drawn as zero. The raw tail now starts at the newest complete rollup
hour, capped at the 24h raw holdback, and the response reports rolledUntil
and rawFrom so clients can show anything still uncovered.
2026-10-02 19:03:46 -04:00

181 lines
7.7 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: series.sql
package db
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const getEarliestCompleteRollupHour = `-- name: GetEarliestCompleteRollupHour :one
SELECT min(hour)::timestamptz FROM analytics_rollup_hours WHERE status = 'complete'
`
func (q *Queries) GetEarliestCompleteRollupHour(ctx context.Context) (pgtype.Timestamptz, error) {
row := q.db.QueryRow(ctx, getEarliestCompleteRollupHour)
var column_1 pgtype.Timestamptz
err := row.Scan(&column_1)
return column_1, err
}
const getLatestCompleteRollupHour = `-- name: GetLatestCompleteRollupHour :one
SELECT max(hour)::timestamptz FROM analytics_rollup_hours WHERE status = 'complete'
`
func (q *Queries) GetLatestCompleteRollupHour(ctx context.Context) (pgtype.Timestamptz, error) {
row := q.db.QueryRow(ctx, getLatestCompleteRollupHour)
var column_1 pgtype.Timestamptz
err := row.Scan(&column_1)
return column_1, err
}
const getStatsSeries = `-- name: GetStatsSeries :many
WITH hours AS (
SELECT g.h::timestamptz AS hour, COALESCE(r.status, 'missing')::text AS status
FROM generate_series($1::timestamptz, $2::timestamptz, INTERVAL '1 hour') g(h)
LEFT JOIN analytics_rollup_hours r ON r.hour = g.h
WHERE g.h < $2::timestamptz
), complete AS (
SELECT hour FROM hours WHERE status = 'complete'
), obs AS (
SELECT o.hour, o.iata, o.observation_count FROM analytics_hourly_iata_observations o JOIN complete c ON c.hour = o.hour
WHERE COALESCE(cardinality($3::bpchar[]), 0) = 0
UNION ALL
SELECT o.hour, o.iata, o.observation_count FROM analytics_hourly_iata_observations o JOIN complete c ON c.hour = o.hour
WHERE cardinality($3::bpchar[]) > 0 AND o.iata = ANY($3::bpchar[])
), obs_agg AS (
SELECT hour, sum(observation_count)::bigint AS observations, count(DISTINCT iata)::bigint AS active_iatas
FROM obs GROUP BY GROUPING SETS ((), (hour))
), pkt AS (
SELECT s.hour, s.packets FROM analytics_hourly_packet_sets s JOIN complete c ON c.hour = s.hour
WHERE COALESCE(cardinality($3::bpchar[]), 0) = 0
UNION ALL
SELECT s.hour, s.packets FROM analytics_hourly_packet_sets s JOIN complete c ON c.hour = s.hour
WHERE cardinality($3::bpchar[]) > 0 AND s.iatas && $3::bpchar[]
), pkt_agg AS (
SELECT hour, sum(packets)::bigint AS unique_packets FROM pkt GROUP BY GROUPING SETS ((), (hour))
), obsr AS (
SELECT i.hour, i.observer_id FROM analytics_hourly_observer_identity i JOIN complete c ON c.hour = i.hour
WHERE COALESCE(cardinality($3::bpchar[]), 0) = 0
UNION ALL
SELECT i.hour, i.observer_id FROM analytics_hourly_observer_identity i JOIN complete c ON c.hour = i.hour
WHERE cardinality($3::bpchar[]) > 0 AND i.iata = ANY($3::bpchar[])
), obsr_agg AS (
SELECT hour, count(DISTINCT observer_id)::bigint AS active_observers FROM obsr GROUP BY GROUPING SETS ((), (hour))
), scp AS (
SELECT s.hour, s.scope_id, s.packets FROM analytics_hourly_scope_sets s JOIN complete c ON c.hour = s.hour
WHERE COALESCE(cardinality($3::bpchar[]), 0) = 0
UNION ALL
SELECT s.hour, s.scope_id, s.packets FROM analytics_hourly_scope_sets s JOIN complete c ON c.hour = s.hour
WHERE cardinality($3::bpchar[]) > 0 AND s.iatas && $3::bpchar[]
), scp_agg AS (
SELECT hour, sum(packets)::bigint AS scoped_packets, count(DISTINCT scope_id)::bigint AS active_scopes
FROM scp GROUP BY GROUPING SETS ((), (hour))
), pth AS (
SELECT p.hour, p.entries FROM analytics_hourly_paths p JOIN complete c ON c.hour = p.hour
WHERE p.category = 0 AND COALESCE(cardinality($3::bpchar[]), 0) = 0
UNION ALL
SELECT p.hour, p.entries FROM analytics_hourly_paths p JOIN complete c ON c.hour = p.hour
WHERE p.category = 0 AND cardinality($3::bpchar[]) > 0 AND p.iata = ANY($3::bpchar[])
), pth_agg AS (
SELECT hour, max(entries)::integer AS max_path_entries FROM pth GROUP BY GROUPING SETS ((), (hour))
), sig AS (
SELECT s.hour, s.snr_sum, s.snr_samples, s.rssi_sum, s.rssi_samples FROM analytics_hourly_signal s JOIN complete c ON c.hour = s.hour
WHERE s.kind = 3 AND COALESCE(cardinality($3::bpchar[]), 0) = 0
UNION ALL
SELECT s.hour, s.snr_sum, s.snr_samples, s.rssi_sum, s.rssi_samples FROM analytics_hourly_signal s JOIN complete c ON c.hour = s.hour
WHERE s.kind = 3 AND cardinality($3::bpchar[]) > 0 AND s.iata = ANY($3::bpchar[])
), sig_agg AS (
SELECT hour, sum(snr_sum)::double precision AS snr_sum, sum(snr_samples)::bigint AS snr_samples,
sum(rssi_sum)::double precision AS rssi_sum, sum(rssi_samples)::bigint AS rssi_samples
FROM sig GROUP BY GROUPING SETS ((), (hour))
), keys AS (
SELECT hour, status FROM hours
UNION ALL
SELECT NULL::timestamptz, 'summary'::text
)
SELECT k.hour, k.status,
COALESCE(o.observations, 0)::bigint AS observations,
COALESCE(p.unique_packets, 0)::bigint AS unique_packets,
COALESCE(ob.active_observers, 0)::bigint AS active_observers,
COALESCE(o.active_iatas, 0)::bigint AS active_iatas,
COALESCE(s.scoped_packets, 0)::bigint AS scoped_packets,
COALESCE(s.active_scopes, 0)::bigint AS active_scopes,
COALESCE(pa.max_path_entries, 0)::integer AS max_path_entries,
COALESCE(sg.snr_sum, 0)::double precision AS snr_sum,
COALESCE(sg.snr_samples, 0)::bigint AS snr_samples,
COALESCE(sg.rssi_sum, 0)::double precision AS rssi_sum,
COALESCE(sg.rssi_samples, 0)::bigint AS rssi_samples
FROM keys k
LEFT JOIN obs_agg o ON o.hour IS NOT DISTINCT FROM k.hour
LEFT JOIN pkt_agg p ON p.hour IS NOT DISTINCT FROM k.hour
LEFT JOIN obsr_agg ob ON ob.hour IS NOT DISTINCT FROM k.hour
LEFT JOIN scp_agg s ON s.hour IS NOT DISTINCT FROM k.hour
LEFT JOIN pth_agg pa ON pa.hour IS NOT DISTINCT FROM k.hour
LEFT JOIN sig_agg sg ON sg.hour IS NOT DISTINCT FROM k.hour
ORDER BY k.hour NULLS LAST
`
type GetStatsSeriesParams struct {
Since pgtype.Timestamptz `json:"since"`
Until pgtype.Timestamptz `json:"until"`
Iatas []string `json:"iatas"`
}
type GetStatsSeriesRow struct {
Hour pgtype.Timestamptz `json:"hour"`
Status string `json:"status"`
Observations int64 `json:"observations"`
UniquePackets int64 `json:"unique_packets"`
ActiveObservers int64 `json:"active_observers"`
ActiveIatas int64 `json:"active_iatas"`
ScopedPackets int64 `json:"scoped_packets"`
ActiveScopes int64 `json:"active_scopes"`
MaxPathEntries int32 `json:"max_path_entries"`
SnrSum float64 `json:"snr_sum"`
SnrSamples int64 `json:"snr_samples"`
RssiSum float64 `json:"rssi_sum"`
RssiSamples int64 `json:"rssi_samples"`
}
// One row per hour in [since, until) plus a summary row (hour NULL) over its complete hours.
// Counts sum; observers, IATAs and scopes are distinct across the window; packets count
// once per hour heard. Each branch pair keeps "all IATAs" and "these IATAs" plans separate.
func (q *Queries) GetStatsSeries(ctx context.Context, arg GetStatsSeriesParams) ([]GetStatsSeriesRow, error) {
rows, err := q.db.Query(ctx, getStatsSeries, arg.Since, arg.Until, arg.Iatas)
if err != nil {
return nil, err
}
defer rows.Close()
items := []GetStatsSeriesRow{}
for rows.Next() {
var i GetStatsSeriesRow
if err := rows.Scan(
&i.Hour,
&i.Status,
&i.Observations,
&i.UniquePackets,
&i.ActiveObservers,
&i.ActiveIatas,
&i.ScopedPackets,
&i.ActiveScopes,
&i.MaxPathEntries,
&i.SnrSum,
&i.SnrSamples,
&i.RssiSum,
&i.RssiSamples,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}