Files
qb/mqe/instant.go

227 lines
4.7 KiB
Go
Raw Permalink Normal View History

2026-06-19 07:25:46 +03:00
package mqe
import (
"database/sql"
"fmt"
"time"
)
type CurrentValue struct {
MetricID uint32
Time int64 `json:"t"`
Value float64 `json:"v"`
}
func (s *MeasureQueryEngine) ListCurrentValues(metricIDs []uint32) (result []CurrentValue, err error) {
driver := s.db.Driver()
for _, metricID := range metricIDs {
var rows *sql.Rows
rows, err = driver.Query(`
SELECT tm, value
FROM f64
WHERE metricID=?
ORDER BY tm DESC
LIMIT 1`,
metricID)
if err != nil {
if err == sql.ErrNoRows {
err = nil
}
return
}
for rows.Next() {
var (
tm int64
value float64
)
err = rows.Scan(&tm, &value)
if err != nil {
return
}
result = append(result, CurrentValue{
MetricID: metricID,
Time: tm,
Value: value,
})
}
if err = rows.Err(); err != nil {
return
}
rows.Close()
}
return
}
// ListInstantMeasures - cписок показаний мгновенных метрик (Температура, Давление, Расход)
// за за интервал без группировки
func (s *MeasureQueryEngine) listInstantMeasures(req MetricMeasuresFilter) (_ []Measure, err error) {
rows, err := s.db.Driver().Query(`
SELECT tm, value
FROM f64
WHERE metricID=? AND tm BETWEEN ? AND ?
ORDER BY tm ASC`,
req.MetricID, req.Since, req.Until)
if err != nil {
if err == sql.ErrNoRows {
err = nil
}
return
}
defer rows.Close()
var result []Measure
for rows.Next() {
var (
tm int64
value float64
)
err = rows.Scan(&tm, &value)
if err != nil {
return
}
result = append(result, Measure{
Time: tm,
Values: []float64{
value,
},
})
}
if err = rows.Err(); err != nil {
return
}
return result, nil
}
type AggregatedInstantMeasuresIn struct {
MetricID int64 `json:"metricID"`
Since int64 `json:"since"`
Until int64 `json:"until"`
GroupBy GroupBy `json:"groupBy"`
Flags byte `json:"flags"` // из настроек по умолчанию либо из запроса
LastDayOfMonth int `json:"lastDayOfMonth"` // например, конец месяца 25 число
FirstHourOfDay int `json:"firstHourOfDay"` // например день начинается в 6:00
}
// Заполняет поля Period и Values (от 1 до 3 значений) в структуре AggregatedMeasure
func (s *MeasureQueryEngine) listAggregatedInstantMeasures(req AggregatedInstantMeasuresIn) (_ []AggregatedMeasure, err error) {
var (
groupByFormat string
parsePeriodLayout string
result []AggregatedMeasure
)
switch req.GroupBy {
case ByHour:
groupByFormat = "%Y%m%d%H"
parsePeriodLayout = hourPeriodLayout
case ByDay:
groupByFormat = "%Y%m%d"
parsePeriodLayout = dayPeriodLayout
case ByMonth:
groupByFormat = "%Y%m"
parsePeriodLayout = monthPeriodLayout
default:
// Защита от дурака
err = fmt.Errorf("unknown GroupBy: %s", req.GroupBy)
return
}
valuesQty := 0
values := ""
if (req.Flags & AggregateMin) == AggregateMin {
values += " MIN(value),"
valuesQty++
}
if (req.Flags & AggregateMax) == AggregateMax {
values += " MAX(value),"
valuesQty++
}
if (req.Flags & AggregateAvg) == AggregateAvg {
values += " AVG(value),"
valuesQty++
}
dt, err := getPeriodDateTime(req.GroupBy, req.LastDayOfMonth, req.FirstHourOfDay)
if err != nil {
return
}
query := fmt.Sprintf(`
SELECT%s DATE_FORMAT(%s, '%s') as periodStr
FROM f64
WHERE metricID=? AND tm BETWEEN ? AND ?
GROUP BY periodStr
ORDER BY periodStr ASC`,
values, dt, groupByFormat)
rows, err := s.db.Driver().Query(query, req.MetricID, req.Since, req.Until)
if err != nil {
if err == sql.ErrNoRows {
err = nil
}
return
}
for rows.Next() {
var (
m = AggregatedMeasure{
Values: make([]float64, valuesQty),
}
periodStr string
period time.Time
valueIdx int
dest []interface{}
)
if (req.Flags & AggregateMin) == AggregateMin {
dest = append(dest, &m.Values[valueIdx])
valueIdx++
}
if (req.Flags & AggregateMax) == AggregateMax {
dest = append(dest, &m.Values[valueIdx])
valueIdx++
}
if (req.Flags & AggregateAvg) == AggregateAvg {
dest = append(dest, &m.Values[valueIdx])
}
dest = append(dest, &periodStr)
err = rows.Scan(dest...)
if err != nil {
return
}
period, err = time.ParseInLocation(parsePeriodLayout, periodStr, s.location)
if err != nil {
err = fmt.Errorf("time.ParseInLocation: %s; layout=%q; str=%q",
err, parsePeriodLayout, periodStr)
return
}
m.Period = period.Unix()
result = append(result, m)
}
if err = rows.Err(); err != nil {
return
}
return result, nil
}