wp
This commit is contained in:
168
mqe/period_producers.go
Normal file
168
mqe/period_producers.go
Normal file
@@ -0,0 +1,168 @@
|
||||
package mqe
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type periodProducer interface {
|
||||
Next() (time.Time, PeriodBound, PeriodBound, bool, error)
|
||||
Last() (PeriodBound, bool, error)
|
||||
}
|
||||
|
||||
type PeriodBound struct {
|
||||
Time int64
|
||||
Value float64
|
||||
}
|
||||
|
||||
type PeriodProducer struct {
|
||||
metricID int64
|
||||
parsePeriodLayout string
|
||||
location *time.Location
|
||||
until int64
|
||||
corrections []_f64Correction
|
||||
rows *sql.Rows
|
||||
tx *sql.Tx
|
||||
}
|
||||
|
||||
type PeriodProducerOptions struct {
|
||||
MetricID int64
|
||||
ParsePeriodLayout string
|
||||
Location *time.Location
|
||||
Until int64
|
||||
Corrections []_f64Correction
|
||||
Rows *sql.Rows
|
||||
Tx *sql.Tx
|
||||
}
|
||||
|
||||
func NewPeriodProducer(opt PeriodProducerOptions) *PeriodProducer {
|
||||
if opt.Location == nil {
|
||||
panic("Location option is required")
|
||||
}
|
||||
|
||||
if opt.MetricID == 0 {
|
||||
panic("MetricID option is required")
|
||||
}
|
||||
|
||||
if opt.ParsePeriodLayout == "" {
|
||||
panic("ParsePeriodLayout option is required")
|
||||
}
|
||||
|
||||
if opt.Until == 0 {
|
||||
panic("Until option is required")
|
||||
}
|
||||
|
||||
if opt.Rows == nil {
|
||||
panic("Rows option is required")
|
||||
}
|
||||
|
||||
if opt.Tx == nil {
|
||||
panic("Tx option is required")
|
||||
}
|
||||
|
||||
s := new(PeriodProducer)
|
||||
s.metricID = opt.MetricID
|
||||
s.parsePeriodLayout = opt.ParsePeriodLayout
|
||||
s.location = opt.Location
|
||||
s.until = opt.Until
|
||||
s.corrections = opt.Corrections
|
||||
s.rows = opt.Rows
|
||||
s.tx = opt.Tx
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *PeriodProducer) Next() (period time.Time, first PeriodBound, last PeriodBound, found bool, err error) {
|
||||
var frameStr string
|
||||
|
||||
hasNext := s.rows.Next()
|
||||
if hasNext {
|
||||
err = s.rows.Scan(&frameStr, &first.Time, &first.Value, &last.Time, &last.Value)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
first.Value = applyCorrectionsToMeasure(s.corrections, first.Time, first.Value)
|
||||
last.Value = applyCorrectionsToMeasure(s.corrections, last.Time, last.Value)
|
||||
|
||||
period, err = time.ParseInLocation(s.parsePeriodLayout, frameStr, s.location)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("time.ParseInLocation: %s; layout=%q; str=%q",
|
||||
err, s.parsePeriodLayout, frameStr)
|
||||
return
|
||||
}
|
||||
|
||||
found = true
|
||||
} else {
|
||||
err = s.rows.Err()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *PeriodProducer) Last() (next PeriodBound, found bool, err error) {
|
||||
// Находим следующее показание метрики.
|
||||
err = s.tx.QueryRow(`
|
||||
SELECT tm, value, true
|
||||
FROM f64
|
||||
WHERE metricID=? AND tm > ?
|
||||
ORDER BY tm ASC
|
||||
LIMIT 1`,
|
||||
s.metricID, s.until).Scan(&next.Time, &next.Value, &found)
|
||||
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return
|
||||
}
|
||||
// Нет записей
|
||||
err = nil
|
||||
}
|
||||
|
||||
next.Value = applyCorrectionsToMeasure(s.corrections, next.Time, next.Value)
|
||||
return
|
||||
}
|
||||
|
||||
// ДЛЯ ТЕСТИРОВАНИЯ
|
||||
|
||||
type stubPeriod struct {
|
||||
Period time.Time
|
||||
First PeriodBound
|
||||
Last PeriodBound
|
||||
}
|
||||
|
||||
type StubPeriodProducerOptions struct {
|
||||
Last *PeriodBound
|
||||
Periods []stubPeriod
|
||||
}
|
||||
|
||||
func NewStubPeriodProducer(opt StubPeriodProducerOptions) *StubPeriodProducer {
|
||||
s := new(StubPeriodProducer)
|
||||
s.last = opt.Last
|
||||
s.periods = opt.Periods
|
||||
return s
|
||||
}
|
||||
|
||||
type StubPeriodProducer struct {
|
||||
last *PeriodBound // для отдельного запроса
|
||||
periods []stubPeriod
|
||||
idx int
|
||||
}
|
||||
|
||||
func (s *StubPeriodProducer) Next() (period time.Time, first PeriodBound, last PeriodBound, found bool, err error) {
|
||||
if s.idx < len(s.periods) {
|
||||
p := s.periods[s.idx]
|
||||
s.idx++
|
||||
period = p.Period
|
||||
first = p.First
|
||||
last = p.Last
|
||||
found = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *StubPeriodProducer) Last() (next PeriodBound, found bool, err error) {
|
||||
if s.last != nil {
|
||||
next = *s.last
|
||||
found = true
|
||||
}
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user