From 3671860b7d3e0b85bae0d09d7237584933915b2e Mon Sep 17 00:00:00 2001 From: Nathan Coad Date: Fri, 23 Jan 2026 10:11:14 +1100 Subject: [PATCH] another fix to aggregation reports --- internal/report/snapshots.go | 20 +++++++++++++++----- internal/tasks/dailyAggregate.go | 2 +- server/handler/snapshotAggregate.go | 7 +++---- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/internal/report/snapshots.go b/internal/report/snapshots.go index f61c4ee..539ca88 100644 --- a/internal/report/snapshots.go +++ b/internal/report/snapshots.go @@ -1088,6 +1088,16 @@ WHERE %s func buildDailyTotals(ctx context.Context, dbConn *sqlx.DB, records []SnapshotRecord, prorateByAvg bool) ([]totalsPoint, error) { points := make([]totalsPoint, 0, len(records)) + tinExpr := `COALESCE(SUM(CASE WHEN "Tin" IS NOT NULL THEN "Tin" ELSE 0 END) / 100.0, 0)` + bronzeExpr := `COALESCE(SUM(CASE WHEN "Bronze" IS NOT NULL THEN "Bronze" ELSE 0 END) / 100.0, 0)` + silverExpr := `COALESCE(SUM(CASE WHEN "Silver" IS NOT NULL THEN "Silver" ELSE 0 END) / 100.0, 0)` + goldExpr := `COALESCE(SUM(CASE WHEN "Gold" IS NOT NULL THEN "Gold" ELSE 0 END) / 100.0, 0)` + if prorateByAvg { + tinExpr = `COALESCE(SUM(CASE WHEN "Tin" IS NOT NULL THEN "Tin" * COALESCE("AvgIsPresent", 0) ELSE 0 END) / 100.0, 0)` + bronzeExpr = `COALESCE(SUM(CASE WHEN "Bronze" IS NOT NULL THEN "Bronze" * COALESCE("AvgIsPresent", 0) ELSE 0 END) / 100.0, 0)` + silverExpr = `COALESCE(SUM(CASE WHEN "Silver" IS NOT NULL THEN "Silver" * COALESCE("AvgIsPresent", 0) ELSE 0 END) / 100.0, 0)` + goldExpr = `COALESCE(SUM(CASE WHEN "Gold" IS NOT NULL THEN "Gold" * COALESCE("AvgIsPresent", 0) ELSE 0 END) / 100.0, 0)` + } for _, record := range records { if err := db.ValidateTableName(record.TableName); err != nil { return nil, err @@ -1101,13 +1111,13 @@ SELECT COALESCE(SUM(CASE WHEN "AvgVcpuCount" IS NOT NULL THEN "AvgVcpuCount" ELSE 0 END), 0) AS vcpu_total, COALESCE(SUM(CASE WHEN "AvgRamGB" IS NOT NULL THEN "AvgRamGB" ELSE 0 END), 0) AS ram_total, COALESCE(AVG(CASE WHEN "AvgIsPresent" IS NOT NULL THEN "AvgIsPresent" ELSE 0 END), 0) AS presence_ratio, - COALESCE(SUM(CASE WHEN "Tin" IS NOT NULL THEN "Tin" ELSE 0 END) / 100.0, 0) AS tin_total, - COALESCE(SUM(CASE WHEN "Bronze" IS NOT NULL THEN "Bronze" ELSE 0 END) / 100.0, 0) AS bronze_total, - COALESCE(SUM(CASE WHEN "Silver" IS NOT NULL THEN "Silver" ELSE 0 END) / 100.0, 0) AS silver_total, - COALESCE(SUM(CASE WHEN "Gold" IS NOT NULL THEN "Gold" ELSE 0 END) / 100.0, 0) AS gold_total + %s AS tin_total, + %s AS bronze_total, + %s AS silver_total, + %s AS gold_total FROM %s WHERE %s -`, record.TableName, templateExclusionFilter()) +`, tinExpr, bronzeExpr, silverExpr, goldExpr, record.TableName, templateExclusionFilter()) var row struct { VmCount int64 `db:"vm_count"` VcpuTotal float64 `db:"vcpu_total"` diff --git a/internal/tasks/dailyAggregate.go b/internal/tasks/dailyAggregate.go index fd7cde3..10fd35c 100644 --- a/internal/tasks/dailyAggregate.go +++ b/internal/tasks/dailyAggregate.go @@ -913,7 +913,7 @@ INSERT INTO %s ( avgDisk, avgPresent, tinPct, bronzePct, silverPct, goldPct, - float64(v.tinHits), float64(v.bronzeHits), float64(v.silverHits), float64(v.goldHits), + tinPct, bronzePct, silverPct, goldPct, } if driver != "sqlite" { // Postgres expects primitive types, nulls are handled by pq via nil. diff --git a/server/handler/snapshotAggregate.go b/server/handler/snapshotAggregate.go index c0f3c5f..0fa3691 100644 --- a/server/handler/snapshotAggregate.go +++ b/server/handler/snapshotAggregate.go @@ -40,14 +40,13 @@ func (h *Handler) SnapshotAggregateForce(w http.ResponseWriter, r *http.Request) } if granularity != "" && snapshotType != "monthly" { - h.Logger.Warn("Snapshot aggregation granularity supplied for non-monthly request", + h.Logger.Debug("Snapshot aggregation ignoring granularity for non-monthly request", "type", snapshotType, "granularity", granularity, ) - writeJSONError(w, http.StatusBadRequest, "granularity is only supported for monthly aggregation") - return + granularity = "" } - if granularity != "" && granularity != "hourly" && granularity != "daily" { + if snapshotType == "monthly" && granularity != "" && granularity != "hourly" && granularity != "daily" { h.Logger.Warn("Snapshot aggregation invalid granularity", "granularity", granularity) writeJSONError(w, http.StatusBadRequest, "granularity must be hourly or daily") return