Files
qb/mqe/index.go
2026-06-19 07:25:46 +03:00

321 lines
6.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package mqe
import (
"fmt"
"sort"
"strconv"
)
type GetYearIndexReq struct {
Since int64 `json:"since"` // из фильтр-формы
Until int64 `json:"until"` // из фильтр-формы
LastDayOfMonth int `json:"lastDayOfMonth"` // например, конец месяца 25 число
FirstHourOfDay int `json:"firstHourOfDay"` // например день начинается в 6:00
MetricIDs []int64 `json:"metricIDs"`
}
func (s *MeasureQueryEngine) GetYearIndex(req GetYearIndexReq) (years []int, err error) {
if len(req.MetricIDs) == 0 {
return
}
var (
lte, gte string
args = []any{
req.MetricIDs,
}
)
if req.Since > 0 {
lte = " AND tm >= ?"
args = append(args, req.Since)
}
if req.Until > 0 {
gte = " AND tm <= ?"
args = append(args, req.Until)
}
q := fmt.Sprintf(`
SELECT YEAR(FROM_UNIXTIME(tm)) as y
FROM f64
WHERE metricID IN (?)%s%s
GROUP BY y`,
lte, gte)
// fmt.Println(q)
// fmt.Printf("%v\n", args)
err = s.db.ListQuery(&years, q, args...)
if err != nil {
return
}
sort.Ints(years)
return
}
type GetMonthIndexReq struct {
Since int64 `json:"since"` // из фильтр-формы
Until int64 `json:"until"` // из фильтр-формы
LastDayOfMonth int `json:"lastDayOfMonth"` // например, конец месяца 25 число
FirstHourOfDay int `json:"firstHourOfDay"` // например день начинается в 6:00
MetricIDs []int64 `json:"metricIDs"`
}
type YearMonth struct {
Year int `json:"year"`
Months []int `json:"months"`
}
func (s *MeasureQueryEngine) GetMonthIndex(req GetMonthIndexReq) (years []YearMonth, err error) {
if len(req.MetricIDs) == 0 {
return
}
dt, err := getDateTimeFacingFHDAndLDM(req.FirstHourOfDay, req.LastDayOfMonth)
if err != nil {
return
}
var (
lte, gte string
args = []any{
req.MetricIDs,
}
)
if req.Since > 0 {
lte = " AND tm >= ?"
args = append(args, req.Since)
}
if req.Until > 0 {
gte = " AND tm <= ?"
args = append(args, req.Until)
}
// ВАЖНО!
// Не сортируем средствами MySQL чтобы не создавать временный файл
query := fmt.Sprintf(`
SELECT DATE_FORMAT(%s, '%s') as p
FROM f64
WHERE metricID IN (?)%s%s
GROUP BY p`,
dt, "%Y%m", lte, gte)
var (
temp []string
yms []int
)
err = s.db.ListQuery(&temp, query, args...)
if err != nil {
return
}
for _, str := range temp {
var ym int
ym, err = strconv.Atoi(str)
if err != nil {
return
}
yms = append(yms, ym)
}
return IndexYms(yms), nil
}
type GetDayIndexReq struct {
Since int64 `json:"since"` // из фильтр-формы
Until int64 `json:"until"` // из фильтр-формы
FirstHourOfDay int `json:"firstHourOfDay"` // например день начинается в 6:00
MetricIDs []int64 `json:"metricIDs"`
}
type YearMonthDay struct {
Year int `json:"year"`
Months []MonthDay `json:"months"`
}
type MonthDay struct {
Month int `json:"month"`
Days []int `json:"days"`
}
func (s *MeasureQueryEngine) GetDayIndex(req GetDayIndexReq) (years []YearMonthDay, err error) {
if len(req.MetricIDs) == 0 {
return
}
dt, err := getDateTimeFacingFHD(req.FirstHourOfDay)
if err != nil {
return
}
var (
lte, gte string
args = []any{
req.MetricIDs,
}
)
if req.Since > 0 {
lte = " AND tm >= ?"
args = append(args, req.Since)
}
if req.Until > 0 {
gte = " AND tm <= ?"
args = append(args, req.Until)
}
// ВАЖНО!
// Не сортируем средствами MySQL чтобы не создавать временный файл
query := fmt.Sprintf(`
SELECT DATE_FORMAT(%s, '%s') as p
FROM f64
WHERE metricID IN(?)%s%s
GROUP BY p`,
dt, "%Y%m%d", lte, gte)
//fmt.Printf("%s\n", query)
var (
temp []string
ymds []int
)
err = s.db.ListQuery(&temp, query, args...)
if err != nil {
return
}
//pretty.PPrintln("temp", temp)
for _, str := range temp {
var ymd int
ymd, err = strconv.Atoi(str)
if err != nil {
return
}
ymds = append(ymds, ymd)
}
return IndexYmds(ymds), nil
}
func IndexYmds(ymds []int) (years []YearMonthDay) {
if len(ymds) == 0 {
return
}
sort.Ints(ymds)
var (
months []MonthDay
days []int
year, month, day int
)
for _, ymd := range ymds {
y := ymd / 10000
m := (ymd % 10000) / 100
d := ymd % 100
if year == 0 {
// инициализация
year = y
month = m
day = d
} else {
if y != year {
days = append(days, day)
months = append(months, MonthDay{
Month: month,
Days: days,
})
years = append(years, YearMonthDay{
Year: year,
Months: months,
})
year = y
month = m
day = d
months = nil
days = nil
} else if m != month {
days = append(days, day)
months = append(months, MonthDay{
Month: month,
Days: days,
})
month = m
day = d
days = nil
} else if d != day {
days = append(days, day)
day = d
}
}
}
days = append(days, day)
months = append(months, MonthDay{
Month: month,
Days: days,
})
years = append(years, YearMonthDay{
Year: year,
Months: months,
})
return
}
func IndexYms(yms []int) (years []YearMonth) {
if len(yms) == 0 {
return
}
sort.Ints(yms)
var (
months []int
year, month int
)
for _, ym := range yms {
y := ym / 100
m := ym % 100
if year == 0 {
// инициализация
year = y
month = m
} else {
if y != year {
months = append(months, month)
years = append(years, YearMonth{
Year: year,
Months: months,
})
year = y
month = m
months = nil
} else if m != month {
months = append(months, month)
month = m
}
}
}
months = append(months, month)
years = append(years, YearMonth{
Year: year,
Months: months,
})
return
}
//SELECT DATE_FORMAT(FROM_UNIXTIME(tm), '%Y%m%d') as p FROM f64 WHERE metricID IN (50) AND tm >= 1700863200 AND tm <= 1700949599 GROUP BY p;