mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 06:39:03 +08:00
chore: update table response format (#5349)
This commit is contained in:
parent
4f69996b9d
commit
daa5a05677
1
Makefile
1
Makefile
@ -188,3 +188,4 @@ test:
|
|||||||
go test ./pkg/query-service/tests/integration/...
|
go test ./pkg/query-service/tests/integration/...
|
||||||
go test ./pkg/query-service/rules/...
|
go test ./pkg/query-service/rules/...
|
||||||
go test ./pkg/query-service/collectorsimulator/...
|
go test ./pkg/query-service/collectorsimulator/...
|
||||||
|
go test ./pkg/query-service/postprocess/...
|
||||||
|
@ -1993,8 +1993,8 @@ func (r *ClickHouseReader) SearchTraces(ctx context.Context, params *model.Searc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
searchSpansResult[0].StartTimestampMillis = startTime - (durationNano/1000000)
|
searchSpansResult[0].StartTimestampMillis = startTime - (durationNano / 1000000)
|
||||||
searchSpansResult[0].EndTimestampMillis = endTime + (durationNano/1000000)
|
searchSpansResult[0].EndTimestampMillis = endTime + (durationNano / 1000000)
|
||||||
|
|
||||||
return &searchSpansResult, nil
|
return &searchSpansResult, nil
|
||||||
}
|
}
|
||||||
@ -4434,8 +4434,8 @@ func readRow(vars []interface{}, columnNames []string, countOfNumberCols int) ([
|
|||||||
case *time.Time:
|
case *time.Time:
|
||||||
point.Timestamp = v.UnixMilli()
|
point.Timestamp = v.UnixMilli()
|
||||||
case *float64, *float32:
|
case *float64, *float32:
|
||||||
isValidPoint = true
|
|
||||||
if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
|
if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
|
||||||
|
isValidPoint = true
|
||||||
point.Value = float64(reflect.ValueOf(v).Elem().Float())
|
point.Value = float64(reflect.ValueOf(v).Elem().Float())
|
||||||
} else {
|
} else {
|
||||||
groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Float()))
|
groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Float()))
|
||||||
@ -4447,9 +4447,9 @@ func readRow(vars []interface{}, columnNames []string, countOfNumberCols int) ([
|
|||||||
case **float64, **float32:
|
case **float64, **float32:
|
||||||
val := reflect.ValueOf(v)
|
val := reflect.ValueOf(v)
|
||||||
if val.IsValid() && !val.IsNil() && !val.Elem().IsNil() {
|
if val.IsValid() && !val.IsNil() && !val.Elem().IsNil() {
|
||||||
isValidPoint = true
|
|
||||||
value := reflect.ValueOf(v).Elem().Elem().Float()
|
value := reflect.ValueOf(v).Elem().Elem().Float()
|
||||||
if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
|
if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
|
||||||
|
isValidPoint = true
|
||||||
point.Value = value
|
point.Value = value
|
||||||
} else {
|
} else {
|
||||||
groupBy = append(groupBy, fmt.Sprintf("%v", value))
|
groupBy = append(groupBy, fmt.Sprintf("%v", value))
|
||||||
@ -4460,8 +4460,8 @@ func readRow(vars []interface{}, columnNames []string, countOfNumberCols int) ([
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *uint, *uint8, *uint64, *uint16, *uint32:
|
case *uint, *uint8, *uint64, *uint16, *uint32:
|
||||||
isValidPoint = true
|
|
||||||
if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
|
if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
|
||||||
|
isValidPoint = true
|
||||||
point.Value = float64(reflect.ValueOf(v).Elem().Uint())
|
point.Value = float64(reflect.ValueOf(v).Elem().Uint())
|
||||||
} else {
|
} else {
|
||||||
groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Uint()))
|
groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Uint()))
|
||||||
@ -4473,9 +4473,9 @@ func readRow(vars []interface{}, columnNames []string, countOfNumberCols int) ([
|
|||||||
case **uint, **uint8, **uint64, **uint16, **uint32:
|
case **uint, **uint8, **uint64, **uint16, **uint32:
|
||||||
val := reflect.ValueOf(v)
|
val := reflect.ValueOf(v)
|
||||||
if val.IsValid() && !val.IsNil() && !val.Elem().IsNil() {
|
if val.IsValid() && !val.IsNil() && !val.Elem().IsNil() {
|
||||||
isValidPoint = true
|
|
||||||
value := reflect.ValueOf(v).Elem().Elem().Uint()
|
value := reflect.ValueOf(v).Elem().Elem().Uint()
|
||||||
if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
|
if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
|
||||||
|
isValidPoint = true
|
||||||
point.Value = float64(value)
|
point.Value = float64(value)
|
||||||
} else {
|
} else {
|
||||||
groupBy = append(groupBy, fmt.Sprintf("%v", value))
|
groupBy = append(groupBy, fmt.Sprintf("%v", value))
|
||||||
@ -4486,8 +4486,8 @@ func readRow(vars []interface{}, columnNames []string, countOfNumberCols int) ([
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *int, *int8, *int16, *int32, *int64:
|
case *int, *int8, *int16, *int32, *int64:
|
||||||
isValidPoint = true
|
|
||||||
if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
|
if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
|
||||||
|
isValidPoint = true
|
||||||
point.Value = float64(reflect.ValueOf(v).Elem().Int())
|
point.Value = float64(reflect.ValueOf(v).Elem().Int())
|
||||||
} else {
|
} else {
|
||||||
groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Int()))
|
groupBy = append(groupBy, fmt.Sprintf("%v", reflect.ValueOf(v).Elem().Int()))
|
||||||
@ -4499,9 +4499,9 @@ func readRow(vars []interface{}, columnNames []string, countOfNumberCols int) ([
|
|||||||
case **int, **int8, **int16, **int32, **int64:
|
case **int, **int8, **int16, **int32, **int64:
|
||||||
val := reflect.ValueOf(v)
|
val := reflect.ValueOf(v)
|
||||||
if val.IsValid() && !val.IsNil() && !val.Elem().IsNil() {
|
if val.IsValid() && !val.IsNil() && !val.Elem().IsNil() {
|
||||||
isValidPoint = true
|
|
||||||
value := reflect.ValueOf(v).Elem().Elem().Int()
|
value := reflect.ValueOf(v).Elem().Elem().Int()
|
||||||
if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
|
if _, ok := constants.ReservedColumnTargetAliases[colName]; ok || countOfNumberCols == 1 {
|
||||||
|
isValidPoint = true
|
||||||
point.Value = float64(value)
|
point.Value = float64(value)
|
||||||
} else {
|
} else {
|
||||||
groupBy = append(groupBy, fmt.Sprintf("%v", value))
|
groupBy = append(groupBy, fmt.Sprintf("%v", value))
|
||||||
|
@ -990,10 +990,16 @@ type QueryRangeResponse struct {
|
|||||||
|
|
||||||
type TableColumn struct {
|
type TableColumn struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
// QueryName is the name of the query that this column belongs to
|
||||||
|
QueryName string `json:"queryName"`
|
||||||
|
// IsValueColumn is true if this column is a value column
|
||||||
|
// i.e it is the column that contains the actual value that is being plotted
|
||||||
|
IsValueColumn bool `json:"isValueColumn"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TableRow struct {
|
type TableRow struct {
|
||||||
Data []interface{} `json:"data"`
|
Data map[string]interface{} `json:"data"`
|
||||||
|
QueryName string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Table struct {
|
type Table struct {
|
||||||
|
@ -2,6 +2,7 @@ package postprocess
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -9,20 +10,21 @@ import (
|
|||||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getAutoColNameForQuery(queryName string, params *v3.QueryRangeParamsV3) string {
|
func roundToTwoDecimal(number float64) float64 {
|
||||||
q := params.CompositeQuery.BuilderQueries[queryName]
|
// Handle very small numbers
|
||||||
if q.DataSource == v3.DataSourceTraces || q.DataSource == v3.DataSourceLogs {
|
if math.Abs(number) < 0.000001 {
|
||||||
if q.AggregateAttribute.Key != "" {
|
return 0
|
||||||
return fmt.Sprintf("%s(%s)", q.AggregateOperator, q.AggregateAttribute.Key)
|
|
||||||
}
|
}
|
||||||
return string(q.AggregateOperator)
|
|
||||||
} else if q.DataSource == v3.DataSourceMetrics {
|
// Determine the number of decimal places to round to
|
||||||
if q.SpaceAggregation != "" && params.Version == "v4" {
|
decimalPlaces := 2
|
||||||
return fmt.Sprintf("%s(%s)", q.SpaceAggregation, q.AggregateAttribute.Key)
|
if math.Abs(number) < 0.01 {
|
||||||
|
decimalPlaces = int(math.Ceil(-math.Log10(math.Abs(number)))) + 1
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s(%s)", q.AggregateOperator, q.AggregateAttribute.Key)
|
|
||||||
}
|
// Round to the determined number of decimal places
|
||||||
return queryName
|
scale := math.Pow(10, float64(decimalPlaces))
|
||||||
|
return math.Round(number*scale) / scale
|
||||||
}
|
}
|
||||||
|
|
||||||
func TransformToTableForBuilderQueries(results []*v3.Result, params *v3.QueryRangeParamsV3) []*v3.Result {
|
func TransformToTableForBuilderQueries(results []*v3.Result, params *v3.QueryRangeParamsV3) []*v3.Result {
|
||||||
@ -55,10 +57,10 @@ func TransformToTableForBuilderQueries(results []*v3.Result, params *v3.QueryRan
|
|||||||
// There will be one column for each label key and one column for each query name
|
// There will be one column for each label key and one column for each query name
|
||||||
columns := make([]*v3.TableColumn, 0, len(labelKeys)+len(results))
|
columns := make([]*v3.TableColumn, 0, len(labelKeys)+len(results))
|
||||||
for _, key := range labelKeys {
|
for _, key := range labelKeys {
|
||||||
columns = append(columns, &v3.TableColumn{Name: key})
|
columns = append(columns, &v3.TableColumn{Name: key, IsValueColumn: false})
|
||||||
}
|
}
|
||||||
for _, result := range results {
|
for _, result := range results {
|
||||||
columns = append(columns, &v3.TableColumn{Name: result.QueryName})
|
columns = append(columns, &v3.TableColumn{Name: result.QueryName, QueryName: result.QueryName, IsValueColumn: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a map to store unique rows
|
// Create a map to store unique rows
|
||||||
@ -72,8 +74,8 @@ func TransformToTableForBuilderQueries(results []*v3.Result, params *v3.QueryRan
|
|||||||
|
|
||||||
// Create a key for the row based on labels
|
// Create a key for the row based on labels
|
||||||
var keyParts []string
|
var keyParts []string
|
||||||
rowData := make([]interface{}, len(columns))
|
rowData := make(map[string]interface{}, len(columns))
|
||||||
for i, key := range labelKeys {
|
for _, key := range labelKeys {
|
||||||
value := "n/a"
|
value := "n/a"
|
||||||
for _, labels := range series.LabelsArray {
|
for _, labels := range series.LabelsArray {
|
||||||
if v, ok := labels[key]; ok {
|
if v, ok := labels[key]; ok {
|
||||||
@ -82,21 +84,21 @@ func TransformToTableForBuilderQueries(results []*v3.Result, params *v3.QueryRan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
keyParts = append(keyParts, fmt.Sprintf("%s=%s", key, value))
|
keyParts = append(keyParts, fmt.Sprintf("%s=%s", key, value))
|
||||||
rowData[i] = value
|
rowData[key] = value
|
||||||
}
|
}
|
||||||
rowKey := strings.Join(keyParts, ",")
|
rowKey := strings.Join(keyParts, ",")
|
||||||
|
|
||||||
// Get or create the row
|
// Get or create the row
|
||||||
row, ok := rowMap[rowKey]
|
row, ok := rowMap[rowKey]
|
||||||
if !ok {
|
if !ok {
|
||||||
row = &v3.TableRow{Data: rowData}
|
row = &v3.TableRow{Data: rowData, QueryName: result.QueryName}
|
||||||
rowMap[rowKey] = row
|
rowMap[rowKey] = row
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the value for this query
|
// Add the value for this query
|
||||||
for i, col := range columns {
|
for _, col := range columns {
|
||||||
if col.Name == result.QueryName {
|
if col.Name == result.QueryName {
|
||||||
row.Data[i] = series.Points[0].Value
|
row.Data[col.Name] = roundToTwoDecimal(series.Points[0].Value)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,11 +108,6 @@ func TransformToTableForBuilderQueries(results []*v3.Result, params *v3.QueryRan
|
|||||||
// Convert rowMap to a slice of TableRows
|
// Convert rowMap to a slice of TableRows
|
||||||
rows := make([]*v3.TableRow, 0, len(rowMap))
|
rows := make([]*v3.TableRow, 0, len(rowMap))
|
||||||
for _, row := range rowMap {
|
for _, row := range rowMap {
|
||||||
for i, value := range row.Data {
|
|
||||||
if value == nil {
|
|
||||||
row.Data[i] = "n/a"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rows = append(rows, row)
|
rows = append(rows, row)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,11 +119,15 @@ func TransformToTableForBuilderQueries(results []*v3.Result, params *v3.QueryRan
|
|||||||
sort.Strings(queryNames)
|
sort.Strings(queryNames)
|
||||||
|
|
||||||
// Sort rows based on OrderBy from BuilderQueries
|
// Sort rows based on OrderBy from BuilderQueries
|
||||||
sortRows(rows, columns, params.CompositeQuery.BuilderQueries, queryNames)
|
sortRows(rows, params.CompositeQuery.BuilderQueries, queryNames)
|
||||||
|
|
||||||
for _, column := range columns {
|
for _, row := range rows {
|
||||||
if _, exists := params.CompositeQuery.BuilderQueries[column.Name]; exists {
|
for _, col := range columns {
|
||||||
column.Name = getAutoColNameForQuery(column.Name, params)
|
if col.IsValueColumn {
|
||||||
|
if row.Data[col.Name] == nil {
|
||||||
|
row.Data[col.Name] = "n/a"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,9 +142,11 @@ func TransformToTableForBuilderQueries(results []*v3.Result, params *v3.QueryRan
|
|||||||
return []*v3.Result{&tableResult}
|
return []*v3.Result{&tableResult}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sortRows(rows []*v3.TableRow, columns []*v3.TableColumn, builderQueries map[string]*v3.BuilderQuery, queryNames []string) {
|
func sortRows(rows []*v3.TableRow, builderQueries map[string]*v3.BuilderQuery, queryNames []string) {
|
||||||
|
// use reverse order of queryNames
|
||||||
|
for i := len(queryNames) - 1; i >= 0; i-- {
|
||||||
|
queryName := queryNames[i]
|
||||||
sort.SliceStable(rows, func(i, j int) bool {
|
sort.SliceStable(rows, func(i, j int) bool {
|
||||||
for _, queryName := range queryNames {
|
|
||||||
query := builderQueries[queryName]
|
query := builderQueries[queryName]
|
||||||
orderByList := query.OrderBy
|
orderByList := query.OrderBy
|
||||||
if len(orderByList) == 0 {
|
if len(orderByList) == 0 {
|
||||||
@ -155,23 +158,12 @@ func sortRows(rows []*v3.TableRow, columns []*v3.TableColumn, builderQueries map
|
|||||||
if name == constants.SigNozOrderByValue {
|
if name == constants.SigNozOrderByValue {
|
||||||
name = queryName
|
name = queryName
|
||||||
}
|
}
|
||||||
colIndex := -1
|
|
||||||
for k, col := range columns {
|
|
||||||
if col.Name == name {
|
|
||||||
colIndex = k
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if colIndex == -1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
valI := rows[i].Data[colIndex]
|
valI := rows[i].Data[name]
|
||||||
valJ := rows[j].Data[colIndex]
|
valJ := rows[j].Data[name]
|
||||||
|
|
||||||
// Handle "n/a" values
|
if valI == nil || valJ == nil {
|
||||||
if valI == "n/a" && valJ == "n/a" {
|
return rows[i].QueryName < rows[j].QueryName
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare based on the data type
|
// Compare based on the data type
|
||||||
@ -211,9 +203,9 @@ func sortRows(rows []*v3.TableRow, columns []*v3.TableColumn, builderQueries map
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TransformToTableForClickHouseQueries(results []*v3.Result) []*v3.Result {
|
func TransformToTableForClickHouseQueries(results []*v3.Result) []*v3.Result {
|
||||||
@ -248,11 +240,11 @@ func TransformToTableForClickHouseQueries(results []*v3.Result) []*v3.Result {
|
|||||||
// So we create a column for each query name that has at least one point
|
// So we create a column for each query name that has at least one point
|
||||||
columns := make([]*v3.TableColumn, 0)
|
columns := make([]*v3.TableColumn, 0)
|
||||||
for _, key := range labelKeys {
|
for _, key := range labelKeys {
|
||||||
columns = append(columns, &v3.TableColumn{Name: key})
|
columns = append(columns, &v3.TableColumn{Name: key, IsValueColumn: false})
|
||||||
}
|
}
|
||||||
for _, result := range results {
|
for _, result := range results {
|
||||||
if len(result.Series) > 0 && len(result.Series[0].Points) > 0 {
|
if len(result.Series) > 0 && len(result.Series[0].Points) > 0 {
|
||||||
columns = append(columns, &v3.TableColumn{Name: result.QueryName})
|
columns = append(columns, &v3.TableColumn{Name: result.QueryName, QueryName: result.QueryName, IsValueColumn: true})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,8 +253,8 @@ func TransformToTableForClickHouseQueries(results []*v3.Result) []*v3.Result {
|
|||||||
for _, series := range result.Series {
|
for _, series := range result.Series {
|
||||||
|
|
||||||
// Create a key for the row based on labels
|
// Create a key for the row based on labels
|
||||||
rowData := make([]interface{}, len(columns))
|
rowData := make(map[string]interface{}, len(columns))
|
||||||
for i, key := range labelKeys {
|
for _, key := range labelKeys {
|
||||||
value := "n/a"
|
value := "n/a"
|
||||||
for _, labels := range series.LabelsArray {
|
for _, labels := range series.LabelsArray {
|
||||||
if v, ok := labels[key]; ok {
|
if v, ok := labels[key]; ok {
|
||||||
@ -270,16 +262,16 @@ func TransformToTableForClickHouseQueries(results []*v3.Result) []*v3.Result {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rowData[i] = value
|
rowData[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get or create the row
|
// Get or create the row
|
||||||
row := &v3.TableRow{Data: rowData}
|
row := &v3.TableRow{Data: rowData, QueryName: result.QueryName}
|
||||||
|
|
||||||
// Add the value for this query
|
// Add the value for this query
|
||||||
for i, col := range columns {
|
for _, col := range columns {
|
||||||
if col.Name == result.QueryName && len(series.Points) > 0 {
|
if col.Name == result.QueryName && len(series.Points) > 0 {
|
||||||
row.Data[i] = series.Points[0].Value
|
row.Data[col.Name] = roundToTwoDecimal(series.Points[0].Value)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -287,6 +279,16 @@ func TransformToTableForClickHouseQueries(results []*v3.Result) []*v3.Result {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, row := range rows {
|
||||||
|
for _, col := range columns {
|
||||||
|
if col.IsValueColumn {
|
||||||
|
if row.Data[col.Name] == nil {
|
||||||
|
row.Data[col.Name] = "n/a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the final result
|
// Create the final result
|
||||||
tableResult := v3.Result{
|
tableResult := v3.Result{
|
||||||
Table: &v3.Table{
|
Table: &v3.Table{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package postprocess
|
package postprocess
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
@ -21,9 +22,9 @@ func TestSortRows(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Sort by single numeric query, ascending order",
|
name: "Sort by single numeric query, ascending order",
|
||||||
rows: []*v3.TableRow{
|
rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service2", 20.0}},
|
{Data: map[string]interface{}{"service": "service2", "A": 20.0}},
|
||||||
{Data: []interface{}{"service1", 10.0}},
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0}},
|
||||||
{Data: []interface{}{"service3", 30.0}},
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||||||
},
|
},
|
||||||
columns: []*v3.TableColumn{
|
columns: []*v3.TableColumn{
|
||||||
{Name: "service_name"},
|
{Name: "service_name"},
|
||||||
@ -34,17 +35,17 @@ func TestSortRows(t *testing.T) {
|
|||||||
},
|
},
|
||||||
queryNames: []string{"A"},
|
queryNames: []string{"A"},
|
||||||
expected: []*v3.TableRow{
|
expected: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", 10.0}},
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0}},
|
||||||
{Data: []interface{}{"service2", 20.0}},
|
{Data: map[string]interface{}{"service": "service2", "A": 20.0}},
|
||||||
{Data: []interface{}{"service3", 30.0}},
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Sort by single numeric query, descending order",
|
name: "Sort by single numeric query, descending order",
|
||||||
rows: []*v3.TableRow{
|
rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service2", 20.0}},
|
{Data: map[string]interface{}{"service": "service2", "A": 20.0}},
|
||||||
{Data: []interface{}{"service1", 10.0}},
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0}},
|
||||||
{Data: []interface{}{"service3", 30.0}},
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||||||
},
|
},
|
||||||
columns: []*v3.TableColumn{
|
columns: []*v3.TableColumn{
|
||||||
{Name: "service_name"},
|
{Name: "service_name"},
|
||||||
@ -55,17 +56,17 @@ func TestSortRows(t *testing.T) {
|
|||||||
},
|
},
|
||||||
queryNames: []string{"A"},
|
queryNames: []string{"A"},
|
||||||
expected: []*v3.TableRow{
|
expected: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service3", 30.0}},
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||||||
{Data: []interface{}{"service2", 20.0}},
|
{Data: map[string]interface{}{"service": "service2", "A": 20.0}},
|
||||||
{Data: []interface{}{"service1", 10.0}},
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Sort by single string query, ascending order",
|
name: "Sort by single string query, ascending order",
|
||||||
rows: []*v3.TableRow{
|
rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service2", "b"}},
|
{Data: map[string]interface{}{"service": "service2", "A": "b"}},
|
||||||
{Data: []interface{}{"service1", "c"}},
|
{Data: map[string]interface{}{"service": "service1", "A": "c"}},
|
||||||
{Data: []interface{}{"service3", "a"}},
|
{Data: map[string]interface{}{"service": "service3", "A": "a"}},
|
||||||
},
|
},
|
||||||
columns: []*v3.TableColumn{
|
columns: []*v3.TableColumn{
|
||||||
{Name: "service_name"},
|
{Name: "service_name"},
|
||||||
@ -76,18 +77,18 @@ func TestSortRows(t *testing.T) {
|
|||||||
},
|
},
|
||||||
queryNames: []string{"A"},
|
queryNames: []string{"A"},
|
||||||
expected: []*v3.TableRow{
|
expected: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service3", "a"}},
|
{Data: map[string]interface{}{"service": "service3", "A": "a"}},
|
||||||
{Data: []interface{}{"service2", "b"}},
|
{Data: map[string]interface{}{"service": "service2", "A": "b"}},
|
||||||
{Data: []interface{}{"service1", "c"}},
|
{Data: map[string]interface{}{"service": "service1", "A": "c"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Sort with n/a values",
|
name: "Sort with n/a values",
|
||||||
rows: []*v3.TableRow{
|
rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", 10.0, "n/a"}},
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0}},
|
||||||
{Data: []interface{}{"service2", "n/a", 15.0}},
|
{Data: map[string]interface{}{"service": "service2", "B": 15.0}},
|
||||||
{Data: []interface{}{"service3", 30.0, 25.0}},
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0, "B": 25.0}},
|
||||||
{Data: []interface{}{"service4", "n/a", "n/a"}},
|
{Data: map[string]interface{}{"service": "service4"}},
|
||||||
},
|
},
|
||||||
columns: []*v3.TableColumn{
|
columns: []*v3.TableColumn{
|
||||||
{Name: "service_name"},
|
{Name: "service_name"},
|
||||||
@ -100,43 +101,18 @@ func TestSortRows(t *testing.T) {
|
|||||||
},
|
},
|
||||||
queryNames: []string{"A", "B"},
|
queryNames: []string{"A", "B"},
|
||||||
expected: []*v3.TableRow{
|
expected: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", 10.0, "n/a"}},
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0}},
|
||||||
{Data: []interface{}{"service3", 30.0, 25.0}},
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0, "B": 25.0}},
|
||||||
{Data: []interface{}{"service4", "n/a", "n/a"}},
|
{Data: map[string]interface{}{"service": "service2", "B": 15.0}},
|
||||||
{Data: []interface{}{"service2", "n/a", 15.0}},
|
{Data: map[string]interface{}{"service": "service4"}},
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Sort with different data types",
|
|
||||||
rows: []*v3.TableRow{
|
|
||||||
{Data: []interface{}{"service1", "string", 10.0, true}},
|
|
||||||
{Data: []interface{}{"service2", 20.0, "string", false}},
|
|
||||||
{Data: []interface{}{"service3", true, 30.0, "string"}},
|
|
||||||
},
|
|
||||||
columns: []*v3.TableColumn{
|
|
||||||
{Name: "service_name"},
|
|
||||||
{Name: "A"},
|
|
||||||
{Name: "B"},
|
|
||||||
{Name: "C"},
|
|
||||||
},
|
|
||||||
builderQueries: map[string]*v3.BuilderQuery{
|
|
||||||
"A": {OrderBy: []v3.OrderBy{{ColumnName: constants.SigNozOrderByValue, Order: "asc"}}},
|
|
||||||
"B": {OrderBy: []v3.OrderBy{{ColumnName: constants.SigNozOrderByValue, Order: "desc"}}},
|
|
||||||
"C": {OrderBy: []v3.OrderBy{{ColumnName: constants.SigNozOrderByValue, Order: "asc"}}},
|
|
||||||
},
|
|
||||||
queryNames: []string{"A", "B", "C"},
|
|
||||||
expected: []*v3.TableRow{
|
|
||||||
{Data: []interface{}{"service2", 20.0, "string", false}},
|
|
||||||
{Data: []interface{}{"service1", "string", 10.0, true}},
|
|
||||||
{Data: []interface{}{"service3", true, 30.0, "string"}},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Sort with SigNozOrderByValue",
|
name: "Sort with SigNozOrderByValue",
|
||||||
rows: []*v3.TableRow{
|
rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", 20.0}},
|
{Data: map[string]interface{}{"service": "service1", "A": 20.0}},
|
||||||
{Data: []interface{}{"service2", 10.0}},
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0}},
|
||||||
{Data: []interface{}{"service3", 30.0}},
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||||||
},
|
},
|
||||||
columns: []*v3.TableColumn{
|
columns: []*v3.TableColumn{
|
||||||
{Name: "service_name"},
|
{Name: "service_name"},
|
||||||
@ -147,44 +123,17 @@ func TestSortRows(t *testing.T) {
|
|||||||
},
|
},
|
||||||
queryNames: []string{"A"},
|
queryNames: []string{"A"},
|
||||||
expected: []*v3.TableRow{
|
expected: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service3", 30.0}},
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||||||
{Data: []interface{}{"service1", 20.0}},
|
{Data: map[string]interface{}{"service": "service1", "A": 20.0}},
|
||||||
{Data: []interface{}{"service2", 10.0}},
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0}},
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Sort by multiple queries with mixed types",
|
|
||||||
rows: []*v3.TableRow{
|
|
||||||
{Data: []interface{}{"service1", 10.0, "b", true}},
|
|
||||||
{Data: []interface{}{"service2", 20.0, "a", false}},
|
|
||||||
{Data: []interface{}{"service3", 10.0, "c", true}},
|
|
||||||
{Data: []interface{}{"service4", 20.0, "b", false}},
|
|
||||||
},
|
|
||||||
columns: []*v3.TableColumn{
|
|
||||||
{Name: "service_name"},
|
|
||||||
{Name: "A"},
|
|
||||||
{Name: "B"},
|
|
||||||
{Name: "C"},
|
|
||||||
},
|
|
||||||
builderQueries: map[string]*v3.BuilderQuery{
|
|
||||||
"A": {OrderBy: []v3.OrderBy{{ColumnName: "A", Order: "asc"}}},
|
|
||||||
"B": {OrderBy: []v3.OrderBy{{ColumnName: "B", Order: "desc"}}},
|
|
||||||
"C": {OrderBy: []v3.OrderBy{{ColumnName: "C", Order: "asc"}}},
|
|
||||||
},
|
|
||||||
queryNames: []string{"A", "B", "C"},
|
|
||||||
expected: []*v3.TableRow{
|
|
||||||
{Data: []interface{}{"service3", 10.0, "c", true}},
|
|
||||||
{Data: []interface{}{"service1", 10.0, "b", true}},
|
|
||||||
{Data: []interface{}{"service4", 20.0, "b", false}},
|
|
||||||
{Data: []interface{}{"service2", 20.0, "a", false}},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Sort with all n/a values",
|
name: "Sort with all n/a values",
|
||||||
rows: []*v3.TableRow{
|
rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", "n/a", "n/a"}},
|
{Data: map[string]interface{}{"service": "service1", "A": "n/a", "B": "n/a"}},
|
||||||
{Data: []interface{}{"service2", "n/a", "n/a"}},
|
{Data: map[string]interface{}{"service": "service2", "A": "n/a", "B": "n/a"}},
|
||||||
{Data: []interface{}{"service3", "n/a", "n/a"}},
|
{Data: map[string]interface{}{"service": "service3", "A": "n/a", "B": "n/a"}},
|
||||||
},
|
},
|
||||||
columns: []*v3.TableColumn{
|
columns: []*v3.TableColumn{
|
||||||
{Name: "service_name"},
|
{Name: "service_name"},
|
||||||
@ -197,18 +146,18 @@ func TestSortRows(t *testing.T) {
|
|||||||
},
|
},
|
||||||
queryNames: []string{"A", "B"},
|
queryNames: []string{"A", "B"},
|
||||||
expected: []*v3.TableRow{
|
expected: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", "n/a", "n/a"}},
|
{Data: map[string]interface{}{"service": "service1", "A": "n/a", "B": "n/a"}},
|
||||||
{Data: []interface{}{"service2", "n/a", "n/a"}},
|
{Data: map[string]interface{}{"service": "service2", "A": "n/a", "B": "n/a"}},
|
||||||
{Data: []interface{}{"service3", "n/a", "n/a"}},
|
{Data: map[string]interface{}{"service": "service3", "A": "n/a", "B": "n/a"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Sort with negative numbers",
|
name: "Sort with negative numbers",
|
||||||
rows: []*v3.TableRow{
|
rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", -10.0}},
|
{Data: map[string]interface{}{"service": "service1", "A": -10.0}},
|
||||||
{Data: []interface{}{"service2", 20.0}},
|
{Data: map[string]interface{}{"service": "service2", "A": 20.0}},
|
||||||
{Data: []interface{}{"service3", -30.0}},
|
{Data: map[string]interface{}{"service": "service3", "A": -30.0}},
|
||||||
{Data: []interface{}{"service4", 0.0}},
|
{Data: map[string]interface{}{"service": "service4", "A": 0.0}},
|
||||||
},
|
},
|
||||||
columns: []*v3.TableColumn{
|
columns: []*v3.TableColumn{
|
||||||
{Name: "service_name"},
|
{Name: "service_name"},
|
||||||
@ -219,19 +168,19 @@ func TestSortRows(t *testing.T) {
|
|||||||
},
|
},
|
||||||
queryNames: []string{"A"},
|
queryNames: []string{"A"},
|
||||||
expected: []*v3.TableRow{
|
expected: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service3", -30.0}},
|
{Data: map[string]interface{}{"service": "service3", "A": -30.0}},
|
||||||
{Data: []interface{}{"service1", -10.0}},
|
{Data: map[string]interface{}{"service": "service1", "A": -10.0}},
|
||||||
{Data: []interface{}{"service4", 0.0}},
|
{Data: map[string]interface{}{"service": "service4", "A": 0.0}},
|
||||||
{Data: []interface{}{"service2", 20.0}},
|
{Data: map[string]interface{}{"service": "service2", "A": 20.0}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Sort with mixed case strings",
|
name: "Sort with mixed case strings",
|
||||||
rows: []*v3.TableRow{
|
rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", "Apple"}},
|
{Data: map[string]interface{}{"service": "service1", "A": "Apple"}},
|
||||||
{Data: []interface{}{"service2", "banana"}},
|
{Data: map[string]interface{}{"service": "service2", "A": "banana"}},
|
||||||
{Data: []interface{}{"service3", "Cherry"}},
|
{Data: map[string]interface{}{"service": "service3", "A": "Cherry"}},
|
||||||
{Data: []interface{}{"service4", "date"}},
|
{Data: map[string]interface{}{"service": "service4", "A": "date"}},
|
||||||
},
|
},
|
||||||
columns: []*v3.TableColumn{
|
columns: []*v3.TableColumn{
|
||||||
{Name: "service_name"},
|
{Name: "service_name"},
|
||||||
@ -242,19 +191,19 @@ func TestSortRows(t *testing.T) {
|
|||||||
},
|
},
|
||||||
queryNames: []string{"A"},
|
queryNames: []string{"A"},
|
||||||
expected: []*v3.TableRow{
|
expected: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", "Apple"}},
|
{Data: map[string]interface{}{"service": "service1", "A": "Apple"}},
|
||||||
{Data: []interface{}{"service3", "Cherry"}},
|
{Data: map[string]interface{}{"service": "service3", "A": "Cherry"}},
|
||||||
{Data: []interface{}{"service2", "banana"}},
|
{Data: map[string]interface{}{"service": "service2", "A": "banana"}},
|
||||||
{Data: []interface{}{"service4", "date"}},
|
{Data: map[string]interface{}{"service": "service4", "A": "date"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Sort with empty strings",
|
name: "Sort with empty strings",
|
||||||
rows: []*v3.TableRow{
|
rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", ""}},
|
{Data: map[string]interface{}{"service": "service1", "A": ""}},
|
||||||
{Data: []interface{}{"service2", "b"}},
|
{Data: map[string]interface{}{"service": "service2", "A": "b"}},
|
||||||
{Data: []interface{}{"service3", ""}},
|
{Data: map[string]interface{}{"service": "service3", "A": ""}},
|
||||||
{Data: []interface{}{"service4", "a"}},
|
{Data: map[string]interface{}{"service": "service4", "A": "a"}},
|
||||||
},
|
},
|
||||||
columns: []*v3.TableColumn{
|
columns: []*v3.TableColumn{
|
||||||
{Name: "service_name"},
|
{Name: "service_name"},
|
||||||
@ -265,17 +214,17 @@ func TestSortRows(t *testing.T) {
|
|||||||
},
|
},
|
||||||
queryNames: []string{"A"},
|
queryNames: []string{"A"},
|
||||||
expected: []*v3.TableRow{
|
expected: []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", ""}},
|
{Data: map[string]interface{}{"service": "service1", "A": ""}},
|
||||||
{Data: []interface{}{"service3", ""}},
|
{Data: map[string]interface{}{"service": "service3", "A": ""}},
|
||||||
{Data: []interface{}{"service4", "a"}},
|
{Data: map[string]interface{}{"service": "service4", "A": "a"}},
|
||||||
{Data: []interface{}{"service2", "b"}},
|
{Data: map[string]interface{}{"service": "service2", "A": "b"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
sortRows(tt.rows, tt.columns, tt.builderQueries, tt.queryNames)
|
sortRows(tt.rows, tt.builderQueries, tt.queryNames)
|
||||||
if !reflect.DeepEqual(tt.rows, tt.expected) {
|
if !reflect.DeepEqual(tt.rows, tt.expected) {
|
||||||
exp, _ := json.Marshal(tt.expected)
|
exp, _ := json.Marshal(tt.expected)
|
||||||
got, _ := json.Marshal(tt.rows)
|
got, _ := json.Marshal(tt.rows)
|
||||||
@ -287,24 +236,20 @@ func TestSortRows(t *testing.T) {
|
|||||||
|
|
||||||
func TestSortRowsWithEmptyQueries(t *testing.T) {
|
func TestSortRowsWithEmptyQueries(t *testing.T) {
|
||||||
rows := []*v3.TableRow{
|
rows := []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", 20.0}},
|
{Data: map[string]interface{}{"service": "service1", "A": 20.0}},
|
||||||
{Data: []interface{}{"service2", 10.0}},
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0}},
|
||||||
{Data: []interface{}{"service3", 30.0}},
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||||||
}
|
|
||||||
columns := []*v3.TableColumn{
|
|
||||||
{Name: "service_name"},
|
|
||||||
{Name: "A"},
|
|
||||||
}
|
}
|
||||||
builderQueries := map[string]*v3.BuilderQuery{}
|
builderQueries := map[string]*v3.BuilderQuery{}
|
||||||
queryNames := []string{}
|
queryNames := []string{}
|
||||||
|
|
||||||
sortRows(rows, columns, builderQueries, queryNames)
|
sortRows(rows, builderQueries, queryNames)
|
||||||
|
|
||||||
// Expect the original order to be maintained
|
// Expect the original order to be maintained
|
||||||
expected := []*v3.TableRow{
|
expected := []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", 20.0}},
|
{Data: map[string]interface{}{"service": "service1", "A": 20.0}},
|
||||||
{Data: []interface{}{"service2", 10.0}},
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0}},
|
||||||
{Data: []interface{}{"service3", 30.0}},
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(rows, expected) {
|
if !reflect.DeepEqual(rows, expected) {
|
||||||
@ -314,26 +259,22 @@ func TestSortRowsWithEmptyQueries(t *testing.T) {
|
|||||||
|
|
||||||
func TestSortRowsWithInvalidColumnName(t *testing.T) {
|
func TestSortRowsWithInvalidColumnName(t *testing.T) {
|
||||||
rows := []*v3.TableRow{
|
rows := []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", 20.0}},
|
{Data: map[string]interface{}{"service": "service1", "A": 20.0}},
|
||||||
{Data: []interface{}{"service2", 10.0}},
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0}},
|
||||||
{Data: []interface{}{"service3", 30.0}},
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||||||
}
|
|
||||||
columns := []*v3.TableColumn{
|
|
||||||
{Name: "service_name"},
|
|
||||||
{Name: "A"},
|
|
||||||
}
|
}
|
||||||
builderQueries := map[string]*v3.BuilderQuery{
|
builderQueries := map[string]*v3.BuilderQuery{
|
||||||
"A": {OrderBy: []v3.OrderBy{{ColumnName: "InvalidColumn", Order: "asc"}}},
|
"A": {OrderBy: []v3.OrderBy{{ColumnName: "InvalidColumn", Order: "asc"}}},
|
||||||
}
|
}
|
||||||
queryNames := []string{"A"}
|
queryNames := []string{"A"}
|
||||||
|
|
||||||
sortRows(rows, columns, builderQueries, queryNames)
|
sortRows(rows, builderQueries, queryNames)
|
||||||
|
|
||||||
// Expect the original order to be maintained
|
// Expect the original order to be maintained
|
||||||
expected := []*v3.TableRow{
|
expected := []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", 20.0}},
|
{Data: map[string]interface{}{"service": "service1", "A": 20.0}},
|
||||||
{Data: []interface{}{"service2", 10.0}},
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0}},
|
||||||
{Data: []interface{}{"service3", 30.0}},
|
{Data: map[string]interface{}{"service": "service3", "A": 30.0}},
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(rows, expected) {
|
if !reflect.DeepEqual(rows, expected) {
|
||||||
@ -343,27 +284,22 @@ func TestSortRowsWithInvalidColumnName(t *testing.T) {
|
|||||||
|
|
||||||
func TestSortRowsStability(t *testing.T) {
|
func TestSortRowsStability(t *testing.T) {
|
||||||
rows := []*v3.TableRow{
|
rows := []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", 10.0, "a"}},
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0, "B": "a"}},
|
||||||
{Data: []interface{}{"service2", 10.0, "b"}},
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0, "B": "b"}},
|
||||||
{Data: []interface{}{"service3", 10.0, "c"}},
|
{Data: map[string]interface{}{"service": "service3", "A": 10.0, "B": "c"}},
|
||||||
}
|
|
||||||
columns := []*v3.TableColumn{
|
|
||||||
{Name: "service_name"},
|
|
||||||
{Name: "A"},
|
|
||||||
{Name: "B"},
|
|
||||||
}
|
}
|
||||||
builderQueries := map[string]*v3.BuilderQuery{
|
builderQueries := map[string]*v3.BuilderQuery{
|
||||||
"A": {OrderBy: []v3.OrderBy{{ColumnName: "A", Order: "asc"}}},
|
"A": {OrderBy: []v3.OrderBy{{ColumnName: "A", Order: "asc"}}},
|
||||||
}
|
}
|
||||||
queryNames := []string{"A"}
|
queryNames := []string{"A"}
|
||||||
|
|
||||||
sortRows(rows, columns, builderQueries, queryNames)
|
sortRows(rows, builderQueries, queryNames)
|
||||||
|
|
||||||
// Expect the original order to be maintained for equal values
|
// Expect the original order to be maintained for equal values
|
||||||
expected := []*v3.TableRow{
|
expected := []*v3.TableRow{
|
||||||
{Data: []interface{}{"service1", 10.0, "a"}},
|
{Data: map[string]interface{}{"service": "service1", "A": 10.0, "B": "a"}},
|
||||||
{Data: []interface{}{"service2", 10.0, "b"}},
|
{Data: map[string]interface{}{"service": "service2", "A": 10.0, "B": "b"}},
|
||||||
{Data: []interface{}{"service3", 10.0, "c"}},
|
{Data: map[string]interface{}{"service": "service3", "A": 10.0, "B": "c"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(rows, expected) {
|
if !reflect.DeepEqual(rows, expected) {
|
||||||
@ -404,10 +340,10 @@ func TestTransformToTableForClickHouseQueries(t *testing.T) {
|
|||||||
Table: &v3.Table{
|
Table: &v3.Table{
|
||||||
Columns: []*v3.TableColumn{
|
Columns: []*v3.TableColumn{
|
||||||
{Name: "service"},
|
{Name: "service"},
|
||||||
{Name: "A"},
|
{Name: "A", QueryName: "A", IsValueColumn: true},
|
||||||
},
|
},
|
||||||
Rows: []*v3.TableRow{
|
Rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"frontend", 10.0}},
|
{Data: map[string]interface{}{"service": "frontend", "A": 10.0}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -465,14 +401,14 @@ func TestTransformToTableForClickHouseQueries(t *testing.T) {
|
|||||||
Columns: []*v3.TableColumn{
|
Columns: []*v3.TableColumn{
|
||||||
{Name: "service"},
|
{Name: "service"},
|
||||||
{Name: "env"},
|
{Name: "env"},
|
||||||
{Name: "A"},
|
{Name: "A", QueryName: "A", IsValueColumn: true},
|
||||||
{Name: "B"},
|
{Name: "B", QueryName: "B", IsValueColumn: true},
|
||||||
},
|
},
|
||||||
Rows: []*v3.TableRow{
|
Rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"frontend", "prod", 10.0, nil}},
|
{Data: map[string]interface{}{"service": "frontend", "env": "prod", "A": 10.0, "B": "n/a"}},
|
||||||
{Data: []interface{}{"backend", "prod", 20.0, nil}},
|
{Data: map[string]interface{}{"service": "backend", "env": "prod", "A": 20.0, "B": "n/a"}},
|
||||||
{Data: []interface{}{"frontend", "prod", nil, 15.0}},
|
{Data: map[string]interface{}{"service": "frontend", "env": "prod", "A": "n/a", "B": 15.0}},
|
||||||
{Data: []interface{}{"backend", "prod", nil, 25.0}},
|
{Data: map[string]interface{}{"service": "backend", "env": "prod", "A": "n/a", "B": 25.0}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -514,12 +450,12 @@ func TestTransformToTableForClickHouseQueries(t *testing.T) {
|
|||||||
Columns: []*v3.TableColumn{
|
Columns: []*v3.TableColumn{
|
||||||
{Name: "service"},
|
{Name: "service"},
|
||||||
{Name: "env"},
|
{Name: "env"},
|
||||||
{Name: "A"},
|
{Name: "A", QueryName: "A", IsValueColumn: true},
|
||||||
{Name: "B"},
|
{Name: "B", QueryName: "B", IsValueColumn: true},
|
||||||
},
|
},
|
||||||
Rows: []*v3.TableRow{
|
Rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"frontend", "n/a", 10.0, nil}},
|
{Data: map[string]interface{}{"service": "frontend", "env": "n/a", "A": 10.0, "B": "n/a"}},
|
||||||
{Data: []interface{}{"n/a", "prod", nil, 20.0}},
|
{Data: map[string]interface{}{"service": "n/a", "env": "prod", "A": "n/a", "B": 20.0}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -551,10 +487,10 @@ func TestTransformToTableForClickHouseQueries(t *testing.T) {
|
|||||||
Table: &v3.Table{
|
Table: &v3.Table{
|
||||||
Columns: []*v3.TableColumn{
|
Columns: []*v3.TableColumn{
|
||||||
{Name: "service"},
|
{Name: "service"},
|
||||||
{Name: "A"},
|
{Name: "A", QueryName: "A", IsValueColumn: true},
|
||||||
},
|
},
|
||||||
Rows: []*v3.TableRow{
|
Rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"frontend", 10.0}},
|
{Data: map[string]interface{}{"service": "frontend", "A": 10.0}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -593,11 +529,11 @@ func TestTransformToTableForClickHouseQueries(t *testing.T) {
|
|||||||
Table: &v3.Table{
|
Table: &v3.Table{
|
||||||
Columns: []*v3.TableColumn{
|
Columns: []*v3.TableColumn{
|
||||||
{Name: "service"},
|
{Name: "service"},
|
||||||
{Name: "B"},
|
{Name: "B", QueryName: "B", IsValueColumn: true},
|
||||||
},
|
},
|
||||||
Rows: []*v3.TableRow{
|
Rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"frontend", nil}},
|
{Data: map[string]interface{}{"service": "frontend", "B": "n/a"}},
|
||||||
{Data: []interface{}{"backend", 20.0}},
|
{Data: map[string]interface{}{"service": "backend", "B": 20.0}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -608,8 +544,10 @@ func TestTransformToTableForClickHouseQueries(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
result := TransformToTableForClickHouseQueries(tt.input)
|
result := TransformToTableForClickHouseQueries(tt.input)
|
||||||
if !reflect.DeepEqual(result, tt.expected) {
|
exp, _ := json.Marshal(tt.expected)
|
||||||
t.Errorf("TransformToTableForClickHouseQueries() = %v, want %v", result, tt.expected)
|
got, _ := json.Marshal(result)
|
||||||
|
if !bytes.Equal(got, exp) {
|
||||||
|
t.Errorf("TransformToTableForClickHouseQueries() = %v, want %v", string(got), string(exp))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -650,19 +588,21 @@ func TestTransformToTableForClickHouseQueriesSorting(t *testing.T) {
|
|||||||
Table: &v3.Table{
|
Table: &v3.Table{
|
||||||
Columns: []*v3.TableColumn{
|
Columns: []*v3.TableColumn{
|
||||||
{Name: "service"},
|
{Name: "service"},
|
||||||
{Name: "A"},
|
{Name: "A", QueryName: "A", IsValueColumn: true},
|
||||||
{Name: "B"},
|
{Name: "B", QueryName: "B", IsValueColumn: true},
|
||||||
},
|
},
|
||||||
Rows: []*v3.TableRow{
|
Rows: []*v3.TableRow{
|
||||||
{Data: []interface{}{"backend", 20.0, nil}},
|
{Data: map[string]interface{}{"service": "backend", "A": 20.0, "B": "n/a"}},
|
||||||
{Data: []interface{}{"frontend", nil, 10.0}},
|
{Data: map[string]interface{}{"service": "frontend", "A": "n/a", "B": 10.0}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
result := TransformToTableForClickHouseQueries(input)
|
result := TransformToTableForClickHouseQueries(input)
|
||||||
if !reflect.DeepEqual(result, expected) {
|
exp, _ := json.Marshal(expected)
|
||||||
t.Errorf("TransformToTableForClickHouseQueries() sorting test failed. Got %v, want %v", result, expected)
|
got, _ := json.Marshal(result)
|
||||||
|
if !bytes.Equal(got, exp) {
|
||||||
|
t.Errorf("TransformToTableForClickHouseQueries() sorting test failed. Got %v, want %v", string(got), string(exp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user