227 lines
4.7 KiB
Go
227 lines
4.7 KiB
Go
|
|
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
|
|||
|
|
}
|