mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-11 22:14:02 +01:00
console: use a less hacky way to pass context to build SQL templates
Instead of trying to embed that in the template, provide a list of templates with their associated input contexts and join them with UNION ALL.
This commit is contained in:
@@ -5,7 +5,6 @@ package console
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -82,33 +81,17 @@ AND (engine LIKE '%MergeTree' OR engine = 'Distributed')
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// finalizeQuery builds the finalized query. A single "context"
|
// inputContext is the intermeidate context provided by the input handler.
|
||||||
// function is provided to return a `Context` struct with all the
|
|
||||||
// information needed.
|
|
||||||
func (c *Component) finalizeQuery(query string) string {
|
|
||||||
t := template.Must(template.New("query").
|
|
||||||
Funcs(template.FuncMap{
|
|
||||||
"context": c.contextFunc,
|
|
||||||
}).
|
|
||||||
Option("missingkey=error").
|
|
||||||
Parse(strings.TrimSpace(query)))
|
|
||||||
buf := bytes.NewBufferString("")
|
|
||||||
if err := t.Execute(buf, nil); err != nil {
|
|
||||||
c.r.Err(err).Str("query", query).Msg("invalid query")
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
type inputContext struct {
|
type inputContext struct {
|
||||||
Start time.Time `json:"start"`
|
Start time.Time
|
||||||
End time.Time `json:"end"`
|
End time.Time
|
||||||
StartForInterval *time.Time `json:"start-for-interval,omitempty"`
|
StartForTableSelection *time.Time
|
||||||
MainTableRequired bool `json:"main-table-required,omitempty"`
|
MainTableRequired bool
|
||||||
Points uint `json:"points"`
|
Points uint
|
||||||
Units string `json:"units,omitempty"`
|
Units string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// context is the context to finalize the template.
|
||||||
type context struct {
|
type context struct {
|
||||||
Table string
|
Table string
|
||||||
Timefilter string
|
Timefilter string
|
||||||
@@ -119,6 +102,12 @@ type context struct {
|
|||||||
ToStartOfInterval func(string) string
|
ToStartOfInterval func(string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// templateQuery holds a template string and its associated input context.
|
||||||
|
type templateQuery struct {
|
||||||
|
Template string
|
||||||
|
Context inputContext
|
||||||
|
}
|
||||||
|
|
||||||
// templateEscape escapes `{{` and `}}` from a string. In fact, only
|
// templateEscape escapes `{{` and `}}` from a string. In fact, only
|
||||||
// the opening tag needs to be escaped.
|
// the opening tag needs to be escaped.
|
||||||
func templateEscape(input string) string {
|
func templateEscape(input string) string {
|
||||||
@@ -133,22 +122,20 @@ func templateWhere(qf query.Filter) string {
|
|||||||
return fmt.Sprintf(`{{ .Timefilter }} AND (%s)`, templateEscape(qf.Direct()))
|
return fmt.Sprintf(`{{ .Timefilter }} AND (%s)`, templateEscape(qf.Direct()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// templateTable builds a template directive to select the right table
|
// finalizeTemplateQueries builds the finalized queries from a list of templateQuery.
|
||||||
func templateContext(context inputContext) string {
|
// Each template is processed with its associated context and combined with UNION ALL.
|
||||||
encoded, err := json.Marshal(context)
|
func (c *Component) finalizeTemplateQueries(queries []templateQuery) string {
|
||||||
if err != nil {
|
parts := make([]string, len(queries))
|
||||||
panic(err)
|
for i, q := range queries {
|
||||||
|
parts[i] = c.finalizeTemplateQuery(q)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("context `%s`", string(encoded))
|
return strings.Join(parts, "\nUNION ALL\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Component) contextFunc(inputStr string) context {
|
// finalizeTemplateQuery builds the finalized query for a single templateQuery
|
||||||
var input inputContext
|
func (c *Component) finalizeTemplateQuery(query templateQuery) string {
|
||||||
if err := json.Unmarshal([]byte(inputStr), &input); err != nil {
|
input := query.Context
|
||||||
panic(err)
|
table, computedInterval, targetInterval := c.computeTableAndInterval(query.Context)
|
||||||
}
|
|
||||||
|
|
||||||
table, computedInterval, targetInterval := c.computeTableAndInterval(input)
|
|
||||||
|
|
||||||
// Make start/end match the computed interval (currently equal to the table resolution)
|
// Make start/end match the computed interval (currently equal to the table resolution)
|
||||||
start := input.Start.Truncate(computedInterval)
|
start := input.Start.Truncate(computedInterval)
|
||||||
@@ -195,7 +182,8 @@ func (c *Component) contextFunc(inputStr string) context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.metrics.clickhouseQueries.WithLabelValues(table).Inc()
|
c.metrics.clickhouseQueries.WithLabelValues(table).Inc()
|
||||||
return context{
|
|
||||||
|
context := context{
|
||||||
Table: table,
|
Table: table,
|
||||||
Timefilter: timefilter,
|
Timefilter: timefilter,
|
||||||
TimefilterStart: timefilterStart,
|
TimefilterStart: timefilterStart,
|
||||||
@@ -211,6 +199,16 @@ func (c *Component) contextFunc(inputStr string) context {
|
|||||||
diffOffset)
|
diffOffset)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t := template.Must(template.New("query").
|
||||||
|
Option("missingkey=error").
|
||||||
|
Parse(strings.TrimSpace(query.Template)))
|
||||||
|
buf := bytes.NewBufferString("")
|
||||||
|
if err := t.Execute(buf, context); err != nil {
|
||||||
|
c.r.Err(err).Str("query", query.Template).Msg("invalid query")
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Component) computeTableAndInterval(input inputContext) (string, time.Duration, time.Duration) {
|
func (c *Component) computeTableAndInterval(input inputContext) (string, time.Duration, time.Duration) {
|
||||||
@@ -223,8 +221,8 @@ func (c *Component) computeTableAndInterval(input inputContext) (string, time.Du
|
|||||||
targetIntervalForTableSelection = time.Second
|
targetIntervalForTableSelection = time.Second
|
||||||
}
|
}
|
||||||
startForTableSelection := input.Start
|
startForTableSelection := input.Start
|
||||||
if input.StartForInterval != nil {
|
if input.StartForTableSelection != nil {
|
||||||
startForTableSelection = *input.StartForInterval
|
startForTableSelection = *input.StartForTableSelection
|
||||||
}
|
}
|
||||||
table, computedInterval := c.getBestTable(startForTableSelection, targetIntervalForTableSelection)
|
table, computedInterval := c.getBestTable(startForTableSelection, targetIntervalForTableSelection)
|
||||||
return table, computedInterval, targetInterval
|
return table, computedInterval, targetInterval
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
package console
|
package console
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -192,7 +191,7 @@ func TestFinalizeQuery(t *testing.T) {
|
|||||||
Context: inputContext{
|
Context: inputContext{
|
||||||
Start: time.Date(2022, 3, 10, 15, 45, 10, 0, time.UTC),
|
Start: time.Date(2022, 3, 10, 15, 45, 10, 0, time.UTC),
|
||||||
End: time.Date(2022, 3, 11, 15, 45, 10, 0, time.UTC),
|
End: time.Date(2022, 3, 11, 15, 45, 10, 0, time.UTC),
|
||||||
StartForInterval: func() *time.Time {
|
StartForTableSelection: func() *time.Time {
|
||||||
t := time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC)
|
t := time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC)
|
||||||
return &t
|
return &t
|
||||||
}(),
|
}(),
|
||||||
@@ -294,10 +293,12 @@ func TestFinalizeQuery(t *testing.T) {
|
|||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
t.Run(tc.Description, func(t *testing.T) {
|
t.Run(tc.Description, func(t *testing.T) {
|
||||||
c.flowsTables = tc.Tables
|
c.flowsTables = tc.Tables
|
||||||
got := c.finalizeQuery(
|
got := c.finalizeTemplateQuery(templateQuery{
|
||||||
fmt.Sprintf(`{{ with %s }}%s{{ end }}`, templateContext(tc.Context), tc.Query))
|
Template: tc.Query,
|
||||||
|
Context: tc.Context,
|
||||||
|
})
|
||||||
if diff := helpers.Diff(got, tc.Expected); diff != "" {
|
if diff := helpers.Diff(got, tc.Expected); diff != "" {
|
||||||
t.Fatalf("finalizeQuery(): (-got, +want):\n%s", diff)
|
t.Fatalf("finalizeTemplateQuery(): (-got, +want):\n%s", diff)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ type toSQL1Options struct {
|
|||||||
mainTableRequired bool
|
mainTableRequired bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (input graphLineHandlerInput) toSQL1(axis int, options toSQL1Options) string {
|
func (input graphLineHandlerInput) toSQL1(axis int, options toSQL1Options) templateQuery {
|
||||||
var startForInterval *time.Time
|
var startForInterval *time.Time
|
||||||
var offsetShift string
|
var offsetShift string
|
||||||
if !options.offsetedStart.IsZero() {
|
if !options.offsetedStart.IsZero() {
|
||||||
@@ -159,8 +159,7 @@ func (input graphLineHandlerInput) toSQL1(axis int, options toSQL1Options) strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlQuery := fmt.Sprintf(`
|
template := fmt.Sprintf(`%s
|
||||||
{{ with %s }}%s
|
|
||||||
SELECT %d AS axis, * FROM (
|
SELECT %d AS axis, * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
%s
|
%s
|
||||||
@@ -171,54 +170,58 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}%s
|
FROM {{ .TimefilterStart }}%s
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second%s
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second%s
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS %s))
|
INTERPOLATE (dimensions AS %s))`,
|
||||||
{{ end }}`,
|
|
||||||
templateContext(inputContext{
|
|
||||||
Start: input.Start,
|
|
||||||
End: input.End,
|
|
||||||
StartForInterval: startForInterval,
|
|
||||||
MainTableRequired: options.mainTableRequired,
|
|
||||||
Points: input.Points,
|
|
||||||
Units: units,
|
|
||||||
}),
|
|
||||||
withStr, axis, strings.Join(fields, ",\n "), where, offsetShift, offsetShift,
|
withStr, axis, strings.Join(fields, ",\n "), where, offsetShift, offsetShift,
|
||||||
dimensionsInterpolate,
|
dimensionsInterpolate,
|
||||||
)
|
)
|
||||||
return strings.TrimSpace(sqlQuery)
|
|
||||||
|
context := inputContext{
|
||||||
|
Start: input.Start,
|
||||||
|
End: input.End,
|
||||||
|
StartForTableSelection: startForInterval,
|
||||||
|
MainTableRequired: options.mainTableRequired,
|
||||||
|
Points: input.Points,
|
||||||
|
Units: units,
|
||||||
|
}
|
||||||
|
|
||||||
|
return templateQuery{
|
||||||
|
Template: strings.TrimSpace(template),
|
||||||
|
Context: context,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// toSQL converts a graph input to an SQL request
|
// toSQL converts a graph input to an SQL request
|
||||||
func (input graphLineHandlerInput) toSQL() string {
|
func (input graphLineHandlerInput) toSQL() []templateQuery {
|
||||||
// Calculate mainTableRequired once and use it for all axes to ensure
|
// Calculate mainTableRequired once and use it for all axes to ensure
|
||||||
// consistency. This is useful as previous period will remove the
|
// consistency. This is useful as previous period will remove the
|
||||||
// dimensions.
|
// dimensions.
|
||||||
mainTableRequired := requireMainTable(input.schema, input.Dimensions, input.Filter)
|
mainTableRequired := requireMainTable(input.schema, input.Dimensions, input.Filter)
|
||||||
parts := []string{input.toSQL1(1, toSQL1Options{
|
queries := []templateQuery{input.toSQL1(1, toSQL1Options{
|
||||||
mainTableRequired: mainTableRequired,
|
mainTableRequired: mainTableRequired,
|
||||||
})}
|
})}
|
||||||
if input.Bidirectional {
|
if input.Bidirectional {
|
||||||
parts = append(parts, input.reverseDirection().toSQL1(2, toSQL1Options{
|
queries = append(queries, input.reverseDirection().toSQL1(2, toSQL1Options{
|
||||||
skipWithClause: true,
|
skipWithClause: true,
|
||||||
reverseDirection: true,
|
reverseDirection: true,
|
||||||
mainTableRequired: mainTableRequired,
|
mainTableRequired: mainTableRequired,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
if input.PreviousPeriod {
|
if input.PreviousPeriod {
|
||||||
parts = append(parts, input.previousPeriod().toSQL1(3, toSQL1Options{
|
queries = append(queries, input.previousPeriod().toSQL1(3, toSQL1Options{
|
||||||
skipWithClause: true,
|
skipWithClause: true,
|
||||||
offsetedStart: input.Start,
|
offsetedStart: input.Start,
|
||||||
mainTableRequired: mainTableRequired,
|
mainTableRequired: mainTableRequired,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
if input.Bidirectional && input.PreviousPeriod {
|
if input.Bidirectional && input.PreviousPeriod {
|
||||||
parts = append(parts, input.reverseDirection().previousPeriod().toSQL1(4, toSQL1Options{
|
queries = append(queries, input.reverseDirection().previousPeriod().toSQL1(4, toSQL1Options{
|
||||||
skipWithClause: true,
|
skipWithClause: true,
|
||||||
reverseDirection: true,
|
reverseDirection: true,
|
||||||
offsetedStart: input.Start,
|
offsetedStart: input.Start,
|
||||||
mainTableRequired: mainTableRequired,
|
mainTableRequired: mainTableRequired,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
return strings.Join(parts, "\nUNION ALL\n")
|
return queries
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Component) graphLineHandlerFunc(gc *gin.Context) {
|
func (c *Component) graphLineHandlerFunc(gc *gin.Context) {
|
||||||
@@ -243,8 +246,8 @@ func (c *Component) graphLineHandlerFunc(gc *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlQuery := input.toSQL()
|
queries := input.toSQL()
|
||||||
sqlQuery = c.finalizeQuery(sqlQuery)
|
sqlQuery := c.finalizeTemplateQueries(queries)
|
||||||
gc.Header("X-SQL-Query", strings.ReplaceAll(sqlQuery, "\n", " "))
|
gc.Header("X-SQL-Query", strings.ReplaceAll(sqlQuery, "\n", " "))
|
||||||
|
|
||||||
results := []struct {
|
results := []struct {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ package console
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -165,7 +164,7 @@ func TestGraphQuerySQL(t *testing.T) {
|
|||||||
Description string
|
Description string
|
||||||
Pos helpers.Pos
|
Pos helpers.Pos
|
||||||
Input graphLineHandlerInput
|
Input graphLineHandlerInput
|
||||||
Expected string
|
Expected []templateQuery
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Description: "no dimensions, no filters, bps",
|
Description: "no dimensions, no filters, bps",
|
||||||
@@ -180,9 +179,15 @@ func TestGraphQuerySQL(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Points: 100,
|
Points: 100,
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":100,"units":"l3bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1)
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1)
|
||||||
SELECT 1 AS axis, * FROM (
|
SELECT 1 AS axis, * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
@@ -196,8 +201,9 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS emptyArrayString()))
|
INTERPOLATE (dimensions AS emptyArrayString()))`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "no dimensions, no filters, l2 bps",
|
Description: "no dimensions, no filters, l2 bps",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -211,9 +217,15 @@ ORDER BY time WITH FILL
|
|||||||
},
|
},
|
||||||
Points: 100,
|
Points: 100,
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":100,"units":"l2bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "l2bps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1)
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1)
|
||||||
SELECT 1 AS axis, * FROM (
|
SELECT 1 AS axis, * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
@@ -227,9 +239,9 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS emptyArrayString()))
|
INTERPOLATE (dimensions AS emptyArrayString()))`,
|
||||||
{{ end }}
|
},
|
||||||
`,
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "no dimensions, no filters, pps",
|
Description: "no dimensions, no filters, pps",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -243,9 +255,15 @@ ORDER BY time WITH FILL
|
|||||||
},
|
},
|
||||||
Points: 100,
|
Points: 100,
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":100,"units":"pps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "pps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1)
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1)
|
||||||
SELECT 1 AS axis, * FROM (
|
SELECT 1 AS axis, * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
@@ -259,8 +277,9 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS emptyArrayString()))
|
INTERPOLATE (dimensions AS emptyArrayString()))`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "truncated source address",
|
Description: "truncated source address",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -276,9 +295,16 @@ ORDER BY time WITH FILL
|
|||||||
},
|
},
|
||||||
Points: 100,
|
Points: 100,
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","main-table-required":true,"points":100,"units":"l3bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "l3bps",
|
||||||
|
MainTableRequired: true,
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * REPLACE (tupleElement(IPv6CIDRToRange(SrcAddr, if(tupleElement(IPv6CIDRToRange(SrcAddr, 96), 1) = toIPv6('::ffff:0.0.0.0'), 120, 48)), 1) AS SrcAddr) FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
source AS (SELECT * REPLACE (tupleElement(IPv6CIDRToRange(SrcAddr, if(tupleElement(IPv6CIDRToRange(SrcAddr, 96), 1) = toIPv6('::ffff:0.0.0.0'), 120, 48)), 1) AS SrcAddr) FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
||||||
rows AS (SELECT SrcAddr FROM source WHERE {{ .Timefilter }} AND (SrcAddr BETWEEN toIPv6('::ffff:1.0.0.0') AND toIPv6('::ffff:1.255.255.255')) GROUP BY SrcAddr ORDER BY {{ .Units }} DESC LIMIT 0)
|
rows AS (SELECT SrcAddr FROM source WHERE {{ .Timefilter }} AND (SrcAddr BETWEEN toIPv6('::ffff:1.0.0.0') AND toIPv6('::ffff:1.255.255.255')) GROUP BY SrcAddr ORDER BY {{ .Units }} DESC LIMIT 0)
|
||||||
SELECT 1 AS axis, * FROM (
|
SELECT 1 AS axis, * FROM (
|
||||||
@@ -293,8 +319,9 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS ['Other']))
|
INTERPOLATE (dimensions AS ['Other']))`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "no dimensions",
|
Description: "no dimensions",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -308,9 +335,15 @@ ORDER BY time WITH FILL
|
|||||||
},
|
},
|
||||||
Points: 100,
|
Points: 100,
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":100,"units":"l3bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1)
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1)
|
||||||
SELECT 1 AS axis, * FROM (
|
SELECT 1 AS axis, * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
@@ -324,8 +357,9 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS emptyArrayString()))
|
INTERPOLATE (dimensions AS emptyArrayString()))`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "no dimensions, escaped filter",
|
Description: "no dimensions, escaped filter",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -339,9 +373,15 @@ ORDER BY time WITH FILL
|
|||||||
},
|
},
|
||||||
Points: 100,
|
Points: 100,
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":100,"units":"l3bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1)
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1)
|
||||||
SELECT 1 AS axis, * FROM (
|
SELECT 1 AS axis, * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
@@ -355,8 +395,9 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS emptyArrayString()))
|
INTERPOLATE (dimensions AS emptyArrayString()))`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "no dimensions, reverse direction",
|
Description: "no dimensions, reverse direction",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -371,9 +412,15 @@ ORDER BY time WITH FILL
|
|||||||
Points: 100,
|
Points: 100,
|
||||||
Bidirectional: true,
|
Bidirectional: true,
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":100,"units":"l3bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1)
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1)
|
||||||
SELECT 1 AS axis, * FROM (
|
SELECT 1 AS axis, * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
@@ -387,11 +434,15 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS emptyArrayString()))
|
INTERPOLATE (dimensions AS emptyArrayString()))`,
|
||||||
{{ end }}
|
}, {
|
||||||
UNION ALL
|
Context: inputContext{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":100,"units":"l3bps"}@@ }}
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
SELECT 2 AS axis, * FROM (
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `SELECT 2 AS axis, * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
{{ call .ToStartOfInterval "TimeReceived" }} AS time,
|
{{ call .ToStartOfInterval "TimeReceived" }} AS time,
|
||||||
{{ .Units }}/{{ .Interval }} AS xps,
|
{{ .Units }}/{{ .Interval }} AS xps,
|
||||||
@@ -403,8 +454,9 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS emptyArrayString()))
|
INTERPOLATE (dimensions AS emptyArrayString()))`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "no dimensions, reverse direction, inl2%",
|
Description: "no dimensions, reverse direction, inl2%",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -419,9 +471,15 @@ ORDER BY time WITH FILL
|
|||||||
Points: 100,
|
Points: 100,
|
||||||
Bidirectional: true,
|
Bidirectional: true,
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":100,"units":"inl2%"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "inl2%",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1)
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1)
|
||||||
SELECT 1 AS axis, * FROM (
|
SELECT 1 AS axis, * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
@@ -435,11 +493,15 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS emptyArrayString()))
|
INTERPOLATE (dimensions AS emptyArrayString()))`,
|
||||||
{{ end }}
|
}, {
|
||||||
UNION ALL
|
Context: inputContext{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":100,"units":"outl2%"}@@ }}
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
SELECT 2 AS axis, * FROM (
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "outl2%",
|
||||||
|
},
|
||||||
|
Template: `SELECT 2 AS axis, * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
{{ call .ToStartOfInterval "TimeReceived" }} AS time,
|
{{ call .ToStartOfInterval "TimeReceived" }} AS time,
|
||||||
{{ .Units }}/{{ .Interval }} AS xps,
|
{{ .Units }}/{{ .Interval }} AS xps,
|
||||||
@@ -451,8 +513,9 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS emptyArrayString()))
|
INTERPOLATE (dimensions AS emptyArrayString()))`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "no filters",
|
Description: "no filters",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -470,9 +533,15 @@ ORDER BY time WITH FILL
|
|||||||
},
|
},
|
||||||
Points: 100,
|
Points: 100,
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":100,"units":"l3bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
||||||
rows AS (SELECT ExporterName, InIfProvider FROM source WHERE {{ .Timefilter }} GROUP BY ExporterName, InIfProvider ORDER BY {{ .Units }} DESC LIMIT 20)
|
rows AS (SELECT ExporterName, InIfProvider FROM source WHERE {{ .Timefilter }} GROUP BY ExporterName, InIfProvider ORDER BY {{ .Units }} DESC LIMIT 20)
|
||||||
SELECT 1 AS axis, * FROM (
|
SELECT 1 AS axis, * FROM (
|
||||||
@@ -487,8 +556,9 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS ['Other', 'Other']))
|
INTERPOLATE (dimensions AS ['Other', 'Other']))`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "no filters, limitType by max",
|
Description: "no filters, limitType by max",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -507,9 +577,15 @@ ORDER BY time WITH FILL
|
|||||||
},
|
},
|
||||||
Points: 100,
|
Points: 100,
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":100,"units":"l3bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
||||||
rows AS (SELECT ExporterName, InIfProvider FROM ( SELECT ExporterName, InIfProvider, {{ .Units }} AS sum_at_time FROM source WHERE {{ .Timefilter }} GROUP BY ExporterName, InIfProvider ) GROUP BY ExporterName, InIfProvider ORDER BY MAX(sum_at_time) DESC LIMIT 20)
|
rows AS (SELECT ExporterName, InIfProvider FROM ( SELECT ExporterName, InIfProvider, {{ .Units }} AS sum_at_time FROM source WHERE {{ .Timefilter }} GROUP BY ExporterName, InIfProvider ) GROUP BY ExporterName, InIfProvider ORDER BY MAX(sum_at_time) DESC LIMIT 20)
|
||||||
SELECT 1 AS axis, * FROM (
|
SELECT 1 AS axis, * FROM (
|
||||||
@@ -524,8 +600,9 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS ['Other', 'Other']))
|
INTERPOLATE (dimensions AS ['Other', 'Other']))`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "no filters, reverse",
|
Description: "no filters, reverse",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -544,9 +621,15 @@ ORDER BY time WITH FILL
|
|||||||
Points: 100,
|
Points: 100,
|
||||||
Bidirectional: true,
|
Bidirectional: true,
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":100,"units":"l3bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
||||||
rows AS (SELECT ExporterName, InIfProvider FROM source WHERE {{ .Timefilter }} GROUP BY ExporterName, InIfProvider ORDER BY {{ .Units }} DESC LIMIT 20)
|
rows AS (SELECT ExporterName, InIfProvider FROM source WHERE {{ .Timefilter }} GROUP BY ExporterName, InIfProvider ORDER BY {{ .Units }} DESC LIMIT 20)
|
||||||
SELECT 1 AS axis, * FROM (
|
SELECT 1 AS axis, * FROM (
|
||||||
@@ -561,11 +644,15 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS ['Other', 'Other']))
|
INTERPOLATE (dimensions AS ['Other', 'Other']))`,
|
||||||
{{ end }}
|
}, {
|
||||||
UNION ALL
|
Context: inputContext{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":100,"units":"l3bps"}@@ }}
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
SELECT 2 AS axis, * FROM (
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `SELECT 2 AS axis, * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
{{ call .ToStartOfInterval "TimeReceived" }} AS time,
|
{{ call .ToStartOfInterval "TimeReceived" }} AS time,
|
||||||
{{ .Units }}/{{ .Interval }} AS xps,
|
{{ .Units }}/{{ .Interval }} AS xps,
|
||||||
@@ -577,8 +664,9 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS ['Other', 'Other']))
|
INTERPOLATE (dimensions AS ['Other', 'Other']))`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "no filters, previous period",
|
Description: "no filters, previous period",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -597,9 +685,15 @@ ORDER BY time WITH FILL
|
|||||||
Points: 100,
|
Points: 100,
|
||||||
PreviousPeriod: true,
|
PreviousPeriod: true,
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":100,"units":"l3bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 100,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
||||||
rows AS (SELECT ExporterName, InIfProvider FROM source WHERE {{ .Timefilter }} GROUP BY ExporterName, InIfProvider ORDER BY {{ .Units }} DESC LIMIT 20)
|
rows AS (SELECT ExporterName, InIfProvider FROM source WHERE {{ .Timefilter }} GROUP BY ExporterName, InIfProvider ORDER BY {{ .Units }} DESC LIMIT 20)
|
||||||
SELECT 1 AS axis, * FROM (
|
SELECT 1 AS axis, * FROM (
|
||||||
@@ -614,11 +708,19 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS ['Other', 'Other']))
|
INTERPOLATE (dimensions AS ['Other', 'Other']))`,
|
||||||
{{ end }}
|
}, {
|
||||||
UNION ALL
|
Context: inputContext{
|
||||||
{{ with context @@{"start":"2022-04-09T15:45:10Z","end":"2022-04-10T15:45:10Z","start-for-interval":"2022-04-10T15:45:10Z","points":100,"units":"l3bps"}@@ }}
|
Start: time.Date(2022, 4, 9, 15, 45, 10, 0, time.UTC),
|
||||||
SELECT 3 AS axis, * FROM (
|
End: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
StartForTableSelection: func() *time.Time {
|
||||||
|
t := time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC)
|
||||||
|
return &t
|
||||||
|
}(),
|
||||||
|
Points: 100,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `SELECT 3 AS axis, * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
{{ call .ToStartOfInterval "TimeReceived" }} + INTERVAL 86400 second AS time,
|
{{ call .ToStartOfInterval "TimeReceived" }} + INTERVAL 86400 second AS time,
|
||||||
{{ .Units }}/{{ .Interval }} AS xps,
|
{{ .Units }}/{{ .Interval }} AS xps,
|
||||||
@@ -630,8 +732,9 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }} + INTERVAL 86400 second
|
FROM {{ .TimefilterStart }} + INTERVAL 86400 second
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second + INTERVAL 86400 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second + INTERVAL 86400 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS emptyArrayString()))
|
INTERPOLATE (dimensions AS emptyArrayString()))`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "previous period while main table is required",
|
Description: "previous period while main table is required",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -649,9 +752,16 @@ ORDER BY time WITH FILL
|
|||||||
Points: 100,
|
Points: 100,
|
||||||
PreviousPeriod: true,
|
PreviousPeriod: true,
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","main-table-required":true,"points":100,"units":"l3bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
MainTableRequired: true,
|
||||||
|
Points: 100,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
||||||
rows AS (SELECT SrcAddr, DstAddr FROM source WHERE {{ .Timefilter }} AND (InIfBoundary = 'external') GROUP BY SrcAddr, DstAddr ORDER BY {{ .Units }} DESC LIMIT 0)
|
rows AS (SELECT SrcAddr, DstAddr FROM source WHERE {{ .Timefilter }} AND (InIfBoundary = 'external') GROUP BY SrcAddr, DstAddr ORDER BY {{ .Units }} DESC LIMIT 0)
|
||||||
SELECT 1 AS axis, * FROM (
|
SELECT 1 AS axis, * FROM (
|
||||||
@@ -666,11 +776,20 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS ['Other', 'Other']))
|
INTERPOLATE (dimensions AS ['Other', 'Other']))`,
|
||||||
{{ end }}
|
}, {
|
||||||
UNION ALL
|
Context: inputContext{
|
||||||
{{ with context @@{"start":"2022-04-09T15:45:10Z","end":"2022-04-10T15:45:10Z","start-for-interval":"2022-04-10T15:45:10Z","main-table-required":true,"points":100,"units":"l3bps"}@@ }}
|
Start: time.Date(2022, 4, 9, 15, 45, 10, 0, time.UTC),
|
||||||
SELECT 3 AS axis, * FROM (
|
End: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
StartForTableSelection: func() *time.Time {
|
||||||
|
t := time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC)
|
||||||
|
return &t
|
||||||
|
}(),
|
||||||
|
MainTableRequired: true,
|
||||||
|
Points: 100,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `SELECT 3 AS axis, * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
{{ call .ToStartOfInterval "TimeReceived" }} + INTERVAL 86400 second AS time,
|
{{ call .ToStartOfInterval "TimeReceived" }} + INTERVAL 86400 second AS time,
|
||||||
{{ .Units }}/{{ .Interval }} AS xps,
|
{{ .Units }}/{{ .Interval }} AS xps,
|
||||||
@@ -682,8 +801,9 @@ ORDER BY time WITH FILL
|
|||||||
FROM {{ .TimefilterStart }} + INTERVAL 86400 second
|
FROM {{ .TimefilterStart }} + INTERVAL 86400 second
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second + INTERVAL 86400 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second + INTERVAL 86400 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}
|
||||||
INTERPOLATE (dimensions AS emptyArrayString()))
|
INTERPOLATE (dimensions AS emptyArrayString()))`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
@@ -694,11 +814,9 @@ ORDER BY time WITH FILL
|
|||||||
if err := tc.Input.Filter.Validate(tc.Input.schema); err != nil {
|
if err := tc.Input.Filter.Validate(tc.Input.schema); err != nil {
|
||||||
t.Fatalf("%sValidate() error:\n%+v", tc.Pos, err)
|
t.Fatalf("%sValidate() error:\n%+v", tc.Pos, err)
|
||||||
}
|
}
|
||||||
tc.Expected = strings.ReplaceAll(tc.Expected, "@@", "`")
|
|
||||||
t.Run(tc.Description, func(t *testing.T) {
|
t.Run(tc.Description, func(t *testing.T) {
|
||||||
got := tc.Input.toSQL()
|
got := tc.Input.toSQL()
|
||||||
if diff := helpers.Diff(strings.Split(strings.TrimSpace(got), "\n"),
|
if diff := helpers.Diff(got, tc.Expected); diff != "" {
|
||||||
strings.Split(strings.TrimSpace(tc.Expected), "\n")); diff != "" {
|
|
||||||
t.Errorf("%stoSQL (-got, +want):\n%s", tc.Pos, diff)
|
t.Errorf("%stoSQL (-got, +want):\n%s", tc.Pos, diff)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ type sankeyLink struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sankeyHandlerInputToSQL converts a sankey query to an SQL request
|
// sankeyHandlerInputToSQL converts a sankey query to an SQL request
|
||||||
func (input graphSankeyHandlerInput) toSQL() (string, error) {
|
func (input graphSankeyHandlerInput) toSQL() ([]templateQuery, error) {
|
||||||
where := templateWhere(input.Filter)
|
where := templateWhere(input.Filter)
|
||||||
|
|
||||||
// Select
|
// Select
|
||||||
@@ -61,8 +61,7 @@ func (input graphSankeyHandlerInput) toSQL() (string, error) {
|
|||||||
}
|
}
|
||||||
with = append(with, selectSankeyRowsByLimitType(input, dimensions, where))
|
with = append(with, selectSankeyRowsByLimitType(input, dimensions, where))
|
||||||
|
|
||||||
sqlQuery := fmt.Sprintf(`
|
template := fmt.Sprintf(`
|
||||||
{{ with %s }}
|
|
||||||
WITH
|
WITH
|
||||||
%s
|
%s
|
||||||
SELECT
|
SELECT
|
||||||
@@ -70,17 +69,21 @@ SELECT
|
|||||||
FROM source
|
FROM source
|
||||||
WHERE %s
|
WHERE %s
|
||||||
GROUP BY dimensions
|
GROUP BY dimensions
|
||||||
ORDER BY xps DESC
|
ORDER BY xps DESC`,
|
||||||
{{ end }}`,
|
|
||||||
templateContext(inputContext{
|
|
||||||
Start: input.Start,
|
|
||||||
End: input.End,
|
|
||||||
MainTableRequired: requireMainTable(input.schema, input.Dimensions, input.Filter),
|
|
||||||
Points: 20,
|
|
||||||
Units: input.Units,
|
|
||||||
}),
|
|
||||||
strings.Join(with, ",\n "), strings.Join(fields, ",\n "), where)
|
strings.Join(with, ",\n "), strings.Join(fields, ",\n "), where)
|
||||||
return strings.TrimSpace(sqlQuery), nil
|
|
||||||
|
context := inputContext{
|
||||||
|
Start: input.Start,
|
||||||
|
End: input.End,
|
||||||
|
MainTableRequired: requireMainTable(input.schema, input.Dimensions, input.Filter),
|
||||||
|
Points: 20,
|
||||||
|
Units: input.Units,
|
||||||
|
}
|
||||||
|
|
||||||
|
return []templateQuery{{
|
||||||
|
Template: strings.TrimSpace(template),
|
||||||
|
Context: context,
|
||||||
|
}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Component) graphSankeyHandlerFunc(gc *gin.Context) {
|
func (c *Component) graphSankeyHandlerFunc(gc *gin.Context) {
|
||||||
@@ -105,14 +108,14 @@ func (c *Component) graphSankeyHandlerFunc(gc *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlQuery, err := input.toSQL()
|
queries, err := input.toSQL()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gc.JSON(http.StatusBadRequest, gin.H{"message": helpers.Capitalize(err.Error())})
|
gc.JSON(http.StatusBadRequest, gin.H{"message": helpers.Capitalize(err.Error())})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare and execute query
|
// Prepare and execute query
|
||||||
sqlQuery = c.finalizeQuery(sqlQuery)
|
sqlQuery := c.finalizeTemplateQueries(queries)
|
||||||
gc.Header("X-SQL-Query", strings.ReplaceAll(sqlQuery, "\n", " "))
|
gc.Header("X-SQL-Query", strings.ReplaceAll(sqlQuery, "\n", " "))
|
||||||
results := []struct {
|
results := []struct {
|
||||||
Xps float64 `ch:"xps"`
|
Xps float64 `ch:"xps"`
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
package console
|
package console
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -21,7 +20,7 @@ func TestSankeyQuerySQL(t *testing.T) {
|
|||||||
Description string
|
Description string
|
||||||
Pos helpers.Pos
|
Pos helpers.Pos
|
||||||
Input graphSankeyHandlerInput
|
Input graphSankeyHandlerInput
|
||||||
Expected string
|
Expected []templateQuery
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Description: "two dimensions, no filters, l3 bps",
|
Description: "two dimensions, no filters, l3 bps",
|
||||||
@@ -39,9 +38,15 @@ func TestSankeyQuerySQL(t *testing.T) {
|
|||||||
Units: "l3bps",
|
Units: "l3bps",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":20,"units":"l3bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 20,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
||||||
(SELECT MAX(TimeReceived) - MIN(TimeReceived) FROM source WHERE {{ .Timefilter }}) AS range,
|
(SELECT MAX(TimeReceived) - MIN(TimeReceived) FROM source WHERE {{ .Timefilter }}) AS range,
|
||||||
rows AS (SELECT SrcAS, ExporterName FROM source WHERE {{ .Timefilter }} GROUP BY SrcAS, ExporterName ORDER BY {{ .Units }} DESC LIMIT 5)
|
rows AS (SELECT SrcAS, ExporterName FROM source WHERE {{ .Timefilter }} GROUP BY SrcAS, ExporterName ORDER BY {{ .Units }} DESC LIMIT 5)
|
||||||
@@ -52,8 +57,9 @@ SELECT
|
|||||||
FROM source
|
FROM source
|
||||||
WHERE {{ .Timefilter }}
|
WHERE {{ .Timefilter }}
|
||||||
GROUP BY dimensions
|
GROUP BY dimensions
|
||||||
ORDER BY xps DESC
|
ORDER BY xps DESC`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "two dimensions, no filters, l3 bps, limitType by max",
|
Description: "two dimensions, no filters, l3 bps, limitType by max",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -71,9 +77,15 @@ ORDER BY xps DESC
|
|||||||
Units: "l3bps",
|
Units: "l3bps",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":20,"units":"l3bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 20,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
||||||
(SELECT MAX(TimeReceived) - MIN(TimeReceived) FROM source WHERE {{ .Timefilter }}) AS range,
|
(SELECT MAX(TimeReceived) - MIN(TimeReceived) FROM source WHERE {{ .Timefilter }}) AS range,
|
||||||
rows AS (SELECT SrcAS, ExporterName FROM ( SELECT SrcAS, ExporterName, {{ .Units }} AS sum_at_time FROM source WHERE {{ .Timefilter }} GROUP BY SrcAS, ExporterName ) GROUP BY SrcAS, ExporterName ORDER BY MAX(sum_at_time) DESC LIMIT 5)
|
rows AS (SELECT SrcAS, ExporterName FROM ( SELECT SrcAS, ExporterName, {{ .Units }} AS sum_at_time FROM source WHERE {{ .Timefilter }} GROUP BY SrcAS, ExporterName ) GROUP BY SrcAS, ExporterName ORDER BY MAX(sum_at_time) DESC LIMIT 5)
|
||||||
@@ -84,8 +96,9 @@ SELECT
|
|||||||
FROM source
|
FROM source
|
||||||
WHERE {{ .Timefilter }}
|
WHERE {{ .Timefilter }}
|
||||||
GROUP BY dimensions
|
GROUP BY dimensions
|
||||||
ORDER BY xps DESC
|
ORDER BY xps DESC`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "two dimensions, no filters, l2 bps",
|
Description: "two dimensions, no filters, l2 bps",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -102,9 +115,15 @@ ORDER BY xps DESC
|
|||||||
Units: "l2bps",
|
Units: "l2bps",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":20,"units":"l2bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 20,
|
||||||
|
Units: "l2bps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
||||||
(SELECT MAX(TimeReceived) - MIN(TimeReceived) FROM source WHERE {{ .Timefilter }}) AS range,
|
(SELECT MAX(TimeReceived) - MIN(TimeReceived) FROM source WHERE {{ .Timefilter }}) AS range,
|
||||||
rows AS (SELECT SrcAS, ExporterName FROM source WHERE {{ .Timefilter }} GROUP BY SrcAS, ExporterName ORDER BY {{ .Units }} DESC LIMIT 5)
|
rows AS (SELECT SrcAS, ExporterName FROM source WHERE {{ .Timefilter }} GROUP BY SrcAS, ExporterName ORDER BY {{ .Units }} DESC LIMIT 5)
|
||||||
@@ -115,9 +134,9 @@ SELECT
|
|||||||
FROM source
|
FROM source
|
||||||
WHERE {{ .Timefilter }}
|
WHERE {{ .Timefilter }}
|
||||||
GROUP BY dimensions
|
GROUP BY dimensions
|
||||||
ORDER BY xps DESC
|
ORDER BY xps DESC`,
|
||||||
{{ end }}
|
},
|
||||||
`,
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "two dimensions, no filters, pps",
|
Description: "two dimensions, no filters, pps",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -134,9 +153,15 @@ ORDER BY xps DESC
|
|||||||
Units: "pps",
|
Units: "pps",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":20,"units":"pps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 20,
|
||||||
|
Units: "pps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
||||||
(SELECT MAX(TimeReceived) - MIN(TimeReceived) FROM source WHERE {{ .Timefilter }}) AS range,
|
(SELECT MAX(TimeReceived) - MIN(TimeReceived) FROM source WHERE {{ .Timefilter }}) AS range,
|
||||||
rows AS (SELECT SrcAS, ExporterName FROM source WHERE {{ .Timefilter }} GROUP BY SrcAS, ExporterName ORDER BY {{ .Units }} DESC LIMIT 5)
|
rows AS (SELECT SrcAS, ExporterName FROM source WHERE {{ .Timefilter }} GROUP BY SrcAS, ExporterName ORDER BY {{ .Units }} DESC LIMIT 5)
|
||||||
@@ -147,8 +172,9 @@ SELECT
|
|||||||
FROM source
|
FROM source
|
||||||
WHERE {{ .Timefilter }}
|
WHERE {{ .Timefilter }}
|
||||||
GROUP BY dimensions
|
GROUP BY dimensions
|
||||||
ORDER BY xps DESC
|
ORDER BY xps DESC`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Description: "two dimensions, with filter",
|
Description: "two dimensions, with filter",
|
||||||
Pos: helpers.Mark(),
|
Pos: helpers.Mark(),
|
||||||
@@ -165,9 +191,15 @@ ORDER BY xps DESC
|
|||||||
Units: "l3bps",
|
Units: "l3bps",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Expected: `
|
Expected: []templateQuery{
|
||||||
{{ with context @@{"start":"2022-04-10T15:45:10Z","end":"2022-04-11T15:45:10Z","points":20,"units":"l3bps"}@@ }}
|
{
|
||||||
WITH
|
Context: inputContext{
|
||||||
|
Start: time.Date(2022, 4, 10, 15, 45, 10, 0, time.UTC),
|
||||||
|
End: time.Date(2022, 4, 11, 15, 45, 10, 0, time.UTC),
|
||||||
|
Points: 20,
|
||||||
|
Units: "l3bps",
|
||||||
|
},
|
||||||
|
Template: `WITH
|
||||||
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
source AS (SELECT * FROM {{ .Table }} SETTINGS asterisk_include_alias_columns = 1),
|
||||||
(SELECT MAX(TimeReceived) - MIN(TimeReceived) FROM source WHERE {{ .Timefilter }} AND (DstCountry = 'FR')) AS range,
|
(SELECT MAX(TimeReceived) - MIN(TimeReceived) FROM source WHERE {{ .Timefilter }} AND (DstCountry = 'FR')) AS range,
|
||||||
rows AS (SELECT SrcAS, ExporterName FROM source WHERE {{ .Timefilter }} AND (DstCountry = 'FR') GROUP BY SrcAS, ExporterName ORDER BY {{ .Units }} DESC LIMIT 10)
|
rows AS (SELECT SrcAS, ExporterName FROM source WHERE {{ .Timefilter }} AND (DstCountry = 'FR') GROUP BY SrcAS, ExporterName ORDER BY {{ .Units }} DESC LIMIT 10)
|
||||||
@@ -178,8 +210,9 @@ SELECT
|
|||||||
FROM source
|
FROM source
|
||||||
WHERE {{ .Timefilter }} AND (DstCountry = 'FR')
|
WHERE {{ .Timefilter }} AND (DstCountry = 'FR')
|
||||||
GROUP BY dimensions
|
GROUP BY dimensions
|
||||||
ORDER BY xps DESC
|
ORDER BY xps DESC`,
|
||||||
{{ end }}`,
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
@@ -190,11 +223,9 @@ ORDER BY xps DESC
|
|||||||
if err := tc.Input.Filter.Validate(tc.Input.schema); err != nil {
|
if err := tc.Input.Filter.Validate(tc.Input.schema); err != nil {
|
||||||
t.Fatalf("%sValidate() error:\n%+v", tc.Pos, err)
|
t.Fatalf("%sValidate() error:\n%+v", tc.Pos, err)
|
||||||
}
|
}
|
||||||
tc.Expected = strings.ReplaceAll(tc.Expected, "@@", "`")
|
|
||||||
t.Run(tc.Description, func(t *testing.T) {
|
t.Run(tc.Description, func(t *testing.T) {
|
||||||
got, _ := tc.Input.toSQL()
|
got, _ := tc.Input.toSQL()
|
||||||
if diff := helpers.Diff(strings.Split(strings.TrimSpace(got), "\n"),
|
if diff := helpers.Diff(got, tc.Expected); diff != "" {
|
||||||
strings.Split(strings.TrimSpace(tc.Expected), "\n")); diff != "" {
|
|
||||||
t.Errorf("%stoSQL (-got, +want):\n%s", tc.Pos, diff)
|
t.Errorf("%stoSQL (-got, +want):\n%s", tc.Pos, diff)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -192,8 +192,7 @@ func (c *Component) widgetTopHandlerFunc(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
now := c.d.Clock.Now()
|
now := c.d.Clock.Now()
|
||||||
query := c.finalizeQuery(fmt.Sprintf(`
|
template := fmt.Sprintf(`
|
||||||
{{ with %s }}
|
|
||||||
WITH
|
WITH
|
||||||
(SELECT SUM(Bytes*SamplingRate) FROM {{ .Table }} WHERE {{ .Timefilter }} %s) AS Total
|
(SELECT SUM(Bytes*SamplingRate) FROM {{ .Table }} WHERE {{ .Timefilter }} %s) AS Total
|
||||||
SELECT
|
SELECT
|
||||||
@@ -204,15 +203,18 @@ WHERE {{ .Timefilter }}
|
|||||||
%s
|
%s
|
||||||
GROUP BY %s
|
GROUP BY %s
|
||||||
ORDER BY Percent DESC
|
ORDER BY Percent DESC
|
||||||
LIMIT 5
|
LIMIT 5`,
|
||||||
{{ end }}`,
|
filter, selector, selector, filter, groupby)
|
||||||
templateContext(inputContext{
|
|
||||||
|
query := c.finalizeTemplateQuery(templateQuery{
|
||||||
|
Template: template,
|
||||||
|
Context: inputContext{
|
||||||
Start: now.Add(-5 * time.Minute),
|
Start: now.Add(-5 * time.Minute),
|
||||||
End: now,
|
End: now,
|
||||||
MainTableRequired: mainTableRequired,
|
MainTableRequired: mainTableRequired,
|
||||||
Points: 5,
|
Points: 5,
|
||||||
}),
|
},
|
||||||
filter, selector, selector, filter, groupby))
|
})
|
||||||
gc.Header("X-SQL-Query", query)
|
gc.Header("X-SQL-Query", query)
|
||||||
|
|
||||||
results := []topResult{}
|
results := []topResult{}
|
||||||
@@ -232,8 +234,7 @@ func (c *Component) widgetGraphHandlerFunc(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
ctx := c.t.Context(gc.Request.Context())
|
ctx := c.t.Context(gc.Request.Context())
|
||||||
now := c.d.Clock.Now()
|
now := c.d.Clock.Now()
|
||||||
query := c.finalizeQuery(fmt.Sprintf(`
|
template := fmt.Sprintf(`
|
||||||
{{ with %s }}
|
|
||||||
SELECT
|
SELECT
|
||||||
{{ call .ToStartOfInterval "TimeReceived" }} AS Time,
|
{{ call .ToStartOfInterval "TimeReceived" }} AS Time,
|
||||||
SUM(Bytes*SamplingRate*8/{{ .Interval }})/1000/1000/1000 AS Gbps
|
SUM(Bytes*SamplingRate*8/{{ .Interval }})/1000/1000/1000 AS Gbps
|
||||||
@@ -244,15 +245,18 @@ GROUP BY Time
|
|||||||
ORDER BY Time WITH FILL
|
ORDER BY Time WITH FILL
|
||||||
FROM {{ .TimefilterStart }}
|
FROM {{ .TimefilterStart }}
|
||||||
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
TO {{ .TimefilterEnd }} + INTERVAL 1 second
|
||||||
STEP {{ .Interval }}
|
STEP {{ .Interval }}`,
|
||||||
{{ end }}`,
|
filter)
|
||||||
templateContext(inputContext{
|
|
||||||
|
query := c.finalizeTemplateQuery(templateQuery{
|
||||||
|
Template: template,
|
||||||
|
Context: inputContext{
|
||||||
Start: now.Add(-c.config.HomepageGraphTimeRange),
|
Start: now.Add(-c.config.HomepageGraphTimeRange),
|
||||||
End: now,
|
End: now,
|
||||||
MainTableRequired: false,
|
MainTableRequired: false,
|
||||||
Points: 200,
|
Points: 200,
|
||||||
}),
|
},
|
||||||
filter))
|
})
|
||||||
gc.Header("X-SQL-Query", query)
|
gc.Header("X-SQL-Query", query)
|
||||||
|
|
||||||
results := []struct {
|
results := []struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user