wp
This commit is contained in:
226
mqe/instant.go
Normal file
226
mqe/instant.go
Normal file
@@ -0,0 +1,226 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user