Files
qb/mqe/index.go

321 lines
6.1 KiB
Go
Raw Permalink Normal View History

2026-06-19 07:25:46 +03:00
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;