mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-10-16 20:20:07 +00:00
Stats endpoints read hourly rollup tables filled once per closed hour by one advisory-locked task, instead of materialized views that re-scanned every observation on each refresh. IATA-set tables give exact distinct counts for any IATA set or region. Cleanup holds raw rows for unrolled hours (up to 24h). Adds /stats/series; ingest keeps packet observation counts, observer last IATA, channel message counts and trace tag summaries. 001_baseline.sql is rewritten, so pre-release 2.0 databases must be recreated. See docs/historical-stats.md.
91 lines
3.0 KiB
Go
91 lines
3.0 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.31.1
|
|
// source: signal.sql
|
|
|
|
package db
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
const getSignalStats = `-- name: GetSignalStats :many
|
|
WITH readings AS (
|
|
SELECT iata, hour, kind, snr_bin, rssi_bin, receptions, snr_samples, snr_sum, rssi_samples, rssi_sum FROM analytics_hourly_signal
|
|
WHERE hour >= $1::timestamptz AND hour < $2::timestamptz
|
|
AND COALESCE(cardinality($3::bpchar[]), 0) = 0
|
|
UNION ALL
|
|
SELECT iata, hour, kind, snr_bin, rssi_bin, receptions, snr_samples, snr_sum, rssi_samples, rssi_sum FROM analytics_hourly_signal
|
|
WHERE hour >= $1::timestamptz AND hour < $2::timestamptz
|
|
AND cardinality($3::bpchar[]) > 0 AND iata = ANY($3::bpchar[])
|
|
)
|
|
SELECT (3 + 4 * grouping(hour))::integer AS kind,
|
|
COALESCE(hour, 'epoch'::timestamptz)::timestamptz AS hour,
|
|
-1::integer AS snr_bin, -1::integer AS rssi_bin,
|
|
COALESCE(sum(receptions), 0)::bigint AS receptions,
|
|
COALESCE(sum(snr_samples), 0)::bigint AS snr_samples,
|
|
COALESCE(sum(snr_sum) / NULLIF(sum(snr_samples), 0), 0)::double precision AS snr_average,
|
|
COALESCE(sum(rssi_samples), 0)::bigint AS rssi_samples,
|
|
COALESCE(sum(rssi_sum) / NULLIF(sum(rssi_samples), 0), 0)::double precision AS rssi_average
|
|
FROM readings WHERE kind = 3
|
|
GROUP BY GROUPING SETS ((), (hour))
|
|
UNION ALL
|
|
SELECT (kind + 4)::integer, 'epoch'::timestamptz, snr_bin, rssi_bin,
|
|
sum(receptions)::bigint, 0::bigint, 0::double precision, 0::bigint, 0::double precision
|
|
FROM readings WHERE kind IN (1, 2)
|
|
GROUP BY kind, snr_bin, rssi_bin
|
|
ORDER BY kind, hour, snr_bin, rssi_bin
|
|
`
|
|
|
|
type GetSignalStatsParams struct {
|
|
Since pgtype.Timestamptz `json:"since"`
|
|
Until pgtype.Timestamptz `json:"until"`
|
|
Iatas []string `json:"iatas"`
|
|
}
|
|
|
|
type GetSignalStatsRow struct {
|
|
Kind int32 `json:"kind"`
|
|
Hour pgtype.Timestamptz `json:"hour"`
|
|
SnrBin int32 `json:"snr_bin"`
|
|
RssiBin int32 `json:"rssi_bin"`
|
|
Receptions int64 `json:"receptions"`
|
|
SnrSamples int64 `json:"snr_samples"`
|
|
SnrAverage float64 `json:"snr_average"`
|
|
RssiSamples int64 `json:"rssi_samples"`
|
|
RssiAverage float64 `json:"rssi_average"`
|
|
}
|
|
|
|
// Read the hourly rollup, never observations on an HTTP request.
|
|
// Weight averages by sample counts instead of averaging regional/hourly means.
|
|
func (q *Queries) GetSignalStats(ctx context.Context, arg GetSignalStatsParams) ([]GetSignalStatsRow, error) {
|
|
rows, err := q.db.Query(ctx, getSignalStats, arg.Since, arg.Until, arg.Iatas)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
items := []GetSignalStatsRow{}
|
|
for rows.Next() {
|
|
var i GetSignalStatsRow
|
|
if err := rows.Scan(
|
|
&i.Kind,
|
|
&i.Hour,
|
|
&i.SnrBin,
|
|
&i.RssiBin,
|
|
&i.Receptions,
|
|
&i.SnrSamples,
|
|
&i.SnrAverage,
|
|
&i.RssiSamples,
|
|
&i.RssiAverage,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|