mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-31 15:06:26 +00:00
wip
This commit is contained in:
parent
3888356bf6
commit
1a8fbdbb06
6 changed files with 749 additions and 18 deletions
|
@ -42,8 +42,7 @@ func TestStatsCountEmpty(t *testing.T) {
|
|||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
},
|
||||
{},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
|
@ -64,8 +63,7 @@ func TestStatsCountEmpty(t *testing.T) {
|
|||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
},
|
||||
{},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
|
@ -86,8 +84,7 @@ func TestStatsCountEmpty(t *testing.T) {
|
|||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
},
|
||||
{},
|
||||
{
|
||||
{"aa", `3`},
|
||||
{"bb", `54`},
|
||||
|
@ -207,8 +204,7 @@ func TestStatsCountEmpty(t *testing.T) {
|
|||
{"a", `1`},
|
||||
{"c", "3"},
|
||||
},
|
||||
{
|
||||
},
|
||||
{},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `5`},
|
||||
|
|
|
@ -42,8 +42,7 @@ func TestStatsCount(t *testing.T) {
|
|||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
},
|
||||
{},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
|
@ -64,8 +63,7 @@ func TestStatsCount(t *testing.T) {
|
|||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
},
|
||||
{},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
|
@ -86,8 +84,7 @@ func TestStatsCount(t *testing.T) {
|
|||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
},
|
||||
{},
|
||||
{
|
||||
{"aa", `3`},
|
||||
{"bb", `54`},
|
||||
|
@ -208,8 +205,7 @@ func TestStatsCount(t *testing.T) {
|
|||
{"a", `1`},
|
||||
{"c", "3"},
|
||||
},
|
||||
{
|
||||
},
|
||||
{},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `5`},
|
||||
|
|
|
@ -154,6 +154,9 @@ func (smp *statsMaxProcessor) updateStateBytes(b []byte) {
|
|||
}
|
||||
|
||||
func (smp *statsMaxProcessor) updateStateString(v string) {
|
||||
if v == "" {
|
||||
// Skip empty strings
|
||||
}
|
||||
if smp.hasMax && !lessString(smp.max, v) {
|
||||
return
|
||||
}
|
||||
|
@ -163,7 +166,7 @@ func (smp *statsMaxProcessor) updateStateString(v string) {
|
|||
|
||||
func (smp *statsMaxProcessor) finalizeStats() string {
|
||||
if !smp.hasMax {
|
||||
return "NaN"
|
||||
return ""
|
||||
}
|
||||
return smp.max
|
||||
}
|
||||
|
|
366
lib/logstorage/stats_max_test.go
Normal file
366
lib/logstorage/stats_max_test.go
Normal file
|
@ -0,0 +1,366 @@
|
|||
package logstorage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseStatsMaxSuccess(t *testing.T) {
|
||||
f := func(pipeStr string) {
|
||||
t.Helper()
|
||||
expectParseStatsFuncSuccess(t, pipeStr)
|
||||
}
|
||||
|
||||
f(`max(*)`)
|
||||
f(`max(a)`)
|
||||
f(`max(a, b)`)
|
||||
}
|
||||
|
||||
func TestParseStatsMaxFailure(t *testing.T) {
|
||||
f := func(pipeStr string) {
|
||||
t.Helper()
|
||||
expectParseStatsFuncFailure(t, pipeStr)
|
||||
}
|
||||
|
||||
f(`max`)
|
||||
f(`max(a b)`)
|
||||
f(`max(x) y`)
|
||||
}
|
||||
|
||||
func TestStatsMax(t *testing.T) {
|
||||
f := func(pipeStr string, rows, rowsExpected [][]Field) {
|
||||
t.Helper()
|
||||
expectPipeResults(t, pipeStr, rows, rowsExpected)
|
||||
}
|
||||
|
||||
f("stats max(*) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `2`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"x", "def"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats max(a) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `2`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"x", "3"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats max(a, b) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `2`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
{"c", "1232"},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"x", "54"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats max(b) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `2`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"x", "54"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats max(c) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `2`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"x", ""},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats max(a) if (b:*) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `2`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `3432`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"x", "3"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats by (b) max(a) if (b:*) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `2`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
{"b", "3"},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"c", `54`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"b", "3"},
|
||||
{"x", "2"},
|
||||
},
|
||||
{
|
||||
{"b", ""},
|
||||
{"x", ""},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats by (a) max(b) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `1`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `5`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `7`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"a", "1"},
|
||||
{"x", "3"},
|
||||
},
|
||||
{
|
||||
{"a", "3"},
|
||||
{"x", "7"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats by (a) max(*) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `1`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
{"c", "10"},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `5`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `7`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"a", "1"},
|
||||
{"x", "def"},
|
||||
},
|
||||
{
|
||||
{"a", "3"},
|
||||
{"x", "7"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats by (a) max(c) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `1`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"c", `foo`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `7`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"a", "1"},
|
||||
{"x", ""},
|
||||
},
|
||||
{
|
||||
{"a", "3"},
|
||||
{"x", "foo"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats by (a) max(a, b, c) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `1`},
|
||||
{"b", `34`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
{"c", "3"},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `5`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `7`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"a", "1"},
|
||||
{"x", "34"},
|
||||
},
|
||||
{
|
||||
{"a", "3"},
|
||||
{"x", "7"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats by (a, b) max(a) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `1`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
{"c", "3"},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `5`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"a", "1"},
|
||||
{"b", "3"},
|
||||
{"x", "1"},
|
||||
},
|
||||
{
|
||||
{"a", "1"},
|
||||
{"b", ""},
|
||||
{"x", "1"},
|
||||
},
|
||||
{
|
||||
{"a", "3"},
|
||||
{"b", "5"},
|
||||
{"x", "3"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats by (a, b) max(c) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `1`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
{"c", "foo"},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `5`},
|
||||
{"c", "4"},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"a", "1"},
|
||||
{"b", "3"},
|
||||
{"x", ""},
|
||||
},
|
||||
{
|
||||
{"a", "1"},
|
||||
{"b", ""},
|
||||
{"x", "foo"},
|
||||
},
|
||||
{
|
||||
{"a", "3"},
|
||||
{"b", "5"},
|
||||
{"x", "4"},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -154,6 +154,10 @@ func (smp *statsMinProcessor) updateStateBytes(b []byte) {
|
|||
}
|
||||
|
||||
func (smp *statsMinProcessor) updateStateString(v string) {
|
||||
if v == "" {
|
||||
// Skip empty strings
|
||||
return
|
||||
}
|
||||
if smp.hasMin && !lessString(v, smp.min) {
|
||||
return
|
||||
}
|
||||
|
@ -163,7 +167,7 @@ func (smp *statsMinProcessor) updateStateString(v string) {
|
|||
|
||||
func (smp *statsMinProcessor) finalizeStats() string {
|
||||
if !smp.hasMin {
|
||||
return "NaN"
|
||||
return ""
|
||||
}
|
||||
return smp.min
|
||||
}
|
||||
|
|
366
lib/logstorage/stats_min_test.go
Normal file
366
lib/logstorage/stats_min_test.go
Normal file
|
@ -0,0 +1,366 @@
|
|||
package logstorage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseStatsMinSuccess(t *testing.T) {
|
||||
f := func(pipeStr string) {
|
||||
t.Helper()
|
||||
expectParseStatsFuncSuccess(t, pipeStr)
|
||||
}
|
||||
|
||||
f(`min(*)`)
|
||||
f(`min(a)`)
|
||||
f(`min(a, b)`)
|
||||
}
|
||||
|
||||
func TestParseStatsMinFailure(t *testing.T) {
|
||||
f := func(pipeStr string) {
|
||||
t.Helper()
|
||||
expectParseStatsFuncFailure(t, pipeStr)
|
||||
}
|
||||
|
||||
f(`min`)
|
||||
f(`min(a b)`)
|
||||
f(`min(x) y`)
|
||||
}
|
||||
|
||||
func TestStatsMin(t *testing.T) {
|
||||
f := func(pipeStr string, rows, rowsExpected [][]Field) {
|
||||
t.Helper()
|
||||
expectPipeResults(t, pipeStr, rows, rowsExpected)
|
||||
}
|
||||
|
||||
f("stats min(*) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `2`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"x", "1"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats min(a) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `2`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"x", "1"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats min(a, b) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `2`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
{"c", "1232"},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"x", "1"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats min(b) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `2`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"x", "3"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats min(c) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `2`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"x", ""},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats min(a) if (b:*) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `2`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `54`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"x", "2"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats by (b) min(a) if (b:*) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `2`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `-12.34`},
|
||||
{"b", "3"},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"c", `54`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"b", "3"},
|
||||
{"x", "-12.34"},
|
||||
},
|
||||
{
|
||||
{"b", ""},
|
||||
{"x", ""},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats by (a) min(b) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `1`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `5`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `7`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"a", "1"},
|
||||
{"x", "3"},
|
||||
},
|
||||
{
|
||||
{"a", "3"},
|
||||
{"x", "5"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats by (a) min(*) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `1`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
{"c", "-34"},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `5`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `7`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"a", "1"},
|
||||
{"x", "-34"},
|
||||
},
|
||||
{
|
||||
{"a", "3"},
|
||||
{"x", "3"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats by (a) min(c) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `1`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"c", `foo`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `7`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"a", "1"},
|
||||
{"x", ""},
|
||||
},
|
||||
{
|
||||
{"a", "3"},
|
||||
{"x", "foo"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats by (a) min(a, b, c) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `1`},
|
||||
{"b", `34`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
{"c", "3"},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `5`},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `7`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"a", "1"},
|
||||
{"x", "1"},
|
||||
},
|
||||
{
|
||||
{"a", "3"},
|
||||
{"x", "3"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats by (a, b) min(a) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `1`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
{"c", "3"},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `5`},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"a", "1"},
|
||||
{"b", "3"},
|
||||
{"x", "1"},
|
||||
},
|
||||
{
|
||||
{"a", "1"},
|
||||
{"b", ""},
|
||||
{"x", "1"},
|
||||
},
|
||||
{
|
||||
{"a", "3"},
|
||||
{"b", "5"},
|
||||
{"x", "3"},
|
||||
},
|
||||
})
|
||||
|
||||
f("stats by (a, b) min(c) as x", [][]Field{
|
||||
{
|
||||
{"_msg", `abc`},
|
||||
{"a", `1`},
|
||||
{"b", `3`},
|
||||
},
|
||||
{
|
||||
{"_msg", `def`},
|
||||
{"a", `1`},
|
||||
{"c", "foo"},
|
||||
},
|
||||
{
|
||||
{"a", `3`},
|
||||
{"b", `5`},
|
||||
{"c", "4"},
|
||||
},
|
||||
}, [][]Field{
|
||||
{
|
||||
{"a", "1"},
|
||||
{"b", "3"},
|
||||
{"x", ""},
|
||||
},
|
||||
{
|
||||
{"a", "1"},
|
||||
{"b", ""},
|
||||
{"x", "foo"},
|
||||
},
|
||||
{
|
||||
{"a", "3"},
|
||||
{"b", "5"},
|
||||
{"x", "4"},
|
||||
},
|
||||
})
|
||||
}
|
Loading…
Reference in a new issue