Skip to content

Commit 2685027

Browse files
committed
fix Map parsing for nested key types
1 parent aee0e94 commit 2685027

2 files changed

Lines changed: 84 additions & 4 deletions

File tree

lib/column/map.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,7 @@ func (col *Map) parse(t Type, sc *ServerContext) (_ Interface, err error) {
5151
col.chType = t
5252
types := make([]string, 2)
5353
typeParams := t.params()
54-
idx := strings.Index(typeParams, ",")
55-
if strings.HasPrefix(typeParams, "Enum") {
56-
idx = strings.Index(typeParams, "),") + 1
57-
}
54+
idx := topLevelComma(typeParams)
5855
if idx > 0 {
5956
types[0] = typeParams[:idx]
6057
types[1] = typeParams[idx+1:]
@@ -80,6 +77,23 @@ func (col *Map) parse(t Type, sc *ServerContext) (_ Interface, err error) {
8077
}
8178
}
8279

80+
func topLevelComma(s string) int {
81+
depth := 0
82+
for i, r := range s {
83+
switch r {
84+
case '(':
85+
depth++
86+
case ')':
87+
depth--
88+
case ',':
89+
if depth == 0 {
90+
return i
91+
}
92+
}
93+
}
94+
return -1
95+
}
96+
8397
func (col *Map) Type() Type {
8498
return col.chType
8599
}

lib/column/map_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package column
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
func TestMapParse(t *testing.T) {
11+
tests := []struct {
12+
name string
13+
columnType Type
14+
keyType Type
15+
valueType Type
16+
}{
17+
{
18+
name: "simple types",
19+
columnType: "Map(String, UInt64)",
20+
keyType: "String",
21+
valueType: "UInt64",
22+
},
23+
{
24+
name: "enum key",
25+
columnType: "Map(Enum16('one' = 1, 'two' = 2), UInt64)",
26+
keyType: "Enum16('one' = 1, 'two' = 2)",
27+
valueType: "UInt64",
28+
},
29+
{
30+
name: "parameterized key containing comma",
31+
columnType: "Map(DateTime64(3, 'UTC'), String)",
32+
keyType: "DateTime64(3, 'UTC')",
33+
valueType: "String",
34+
},
35+
{
36+
name: "nested value containing comma",
37+
columnType: "Map(String, Tuple(UInt8, UInt16))",
38+
keyType: "String",
39+
valueType: "Tuple(UInt8, UInt16)",
40+
},
41+
}
42+
43+
for _, tt := range tests {
44+
t.Run(tt.name, func(t *testing.T) {
45+
column, err := tt.columnType.Column("test", &ServerContext{})
46+
require.NoError(t, err)
47+
48+
m := requireMap(t, column)
49+
assert.Equal(t, tt.keyType, m.keys.Type())
50+
assert.Equal(t, tt.valueType, m.values.Type())
51+
})
52+
}
53+
}
54+
55+
func TestMapParseInvalid(t *testing.T) {
56+
_, err := Type("Map(String)").Column("test", &ServerContext{})
57+
require.Error(t, err)
58+
assert.IsType(t, &UnsupportedColumnTypeError{}, err)
59+
}
60+
61+
func requireMap(t *testing.T, column Interface) *Map {
62+
t.Helper()
63+
m, ok := column.(*Map)
64+
require.True(t, ok)
65+
return m
66+
}

0 commit comments

Comments
 (0)