Skip to content

Commit 73fdc99

Browse files
author
Grigory Aksentyev
committed
added support for marshalling/unmarshalling maps with non-string keys
1 parent f76e4f9 commit 73fdc99

File tree

3 files changed

+54
-10
lines changed

3 files changed

+54
-10
lines changed

bson/bson_test.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,8 @@ func (s *S) TestMarshalOneWayItems(c *C) {
582582
// --------------------------------------------------------------------------
583583
// One-way unmarshaling tests.
584584

585+
type intAlias int
586+
585587
var unmarshalItems = []testItemType{
586588
// Field is private. Should not attempt to unmarshal it.
587589
{&struct{ priv byte }{},
@@ -636,6 +638,14 @@ var unmarshalItems = []testItemType{
636638
// Decode a doc within a doc in to a slice within a doc; shouldn't error
637639
{&struct{ Foo []string }{},
638640
"\x03\x66\x6f\x6f\x00\x05\x00\x00\x00\x00"},
641+
642+
// int key maps
643+
{map[int]string{10: "s"},
644+
"\x0210\x00\x02\x00\x00\x00s\x00"},
645+
646+
//// event if type is alias to int
647+
{map[intAlias]string{10: "s"},
648+
"\x0210\x00\x02\x00\x00\x00s\x00"},
639649
}
640650

641651
func (s *S) TestUnmarshalOneWayItems(c *C) {
@@ -713,11 +723,6 @@ var unmarshalErrorItems = []unmarshalErrorType{
713723
"\x10name\x00\x08\x00\x00\x00",
714724
"Duplicated key 'name' in struct bson_test.structWithDupKeys"},
715725

716-
// Non-string map key.
717-
{map[int]interface{}{},
718-
"\x10name\x00\x08\x00\x00\x00",
719-
"BSON map must have string keys. Got: map\\[int\\]interface \\{\\}"},
720-
721726
{nil,
722727
"\xEEname\x00",
723728
"Unknown element kind \\(0xEE\\)"},

bson/decode.go

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,6 @@ func (d *decoder) readDocTo(out reflect.Value) {
176176
switch outk {
177177
case reflect.Map:
178178
keyType = outt.Key()
179-
if keyType.Kind() != reflect.String {
180-
panic("BSON map must have string keys. Got: " + outt.String())
181-
}
182179
if keyType != typeString {
183180
convertKey = true
184181
}
@@ -240,7 +237,49 @@ func (d *decoder) readDocTo(out reflect.Value) {
240237
if d.readElemTo(e, kind) {
241238
k := reflect.ValueOf(name)
242239
if convertKey {
243-
k = k.Convert(keyType)
240+
mapKeyType := out.Type().Key()
241+
mapKeyKind := mapKeyType.Kind()
242+
243+
var parsed float64
244+
if mapKeyKind != reflect.String {
245+
var err error
246+
parsed, err = strconv.ParseFloat(k.String(), 64)
247+
if err != nil {
248+
panic("Map key is defined to be a numeric type (" + mapKeyKind.String() + ") but got error " +
249+
err.Error())
250+
}
251+
}
252+
253+
switch mapKeyKind {
254+
case reflect.Int:
255+
k = reflect.ValueOf(int(parsed))
256+
case reflect.Int8:
257+
k = reflect.ValueOf(int8(parsed))
258+
case reflect.Int16:
259+
k = reflect.ValueOf(int16(parsed))
260+
case reflect.Int32:
261+
k = reflect.ValueOf(int32(parsed))
262+
case reflect.Int64:
263+
k = reflect.ValueOf(int64(parsed))
264+
case reflect.Uint:
265+
k = reflect.ValueOf(uint(parsed))
266+
case reflect.Uint8:
267+
k = reflect.ValueOf(uint8(parsed))
268+
case reflect.Uint16:
269+
k = reflect.ValueOf(uint16(parsed))
270+
case reflect.Uint32:
271+
k = reflect.ValueOf(uint32(parsed))
272+
case reflect.Uint64:
273+
k = reflect.ValueOf(uint64(parsed))
274+
case reflect.Float32:
275+
k = reflect.ValueOf(float32(parsed))
276+
case reflect.Float64:
277+
k = reflect.ValueOf(float64(parsed))
278+
case reflect.String:
279+
mapKeyType = keyType
280+
}
281+
282+
k = k.Convert(mapKeyType)
244283
}
245284
out.SetMapIndex(k, e)
246285
}

bson/encode.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ func (e *encoder) addDoc(v reflect.Value) {
194194

195195
func (e *encoder) addMap(v reflect.Value) {
196196
for _, k := range v.MapKeys() {
197-
e.addElem(k.String(), v.MapIndex(k), false)
197+
e.addElem(fmt.Sprint(k), v.MapIndex(k), false)
198198
}
199199
}
200200

0 commit comments

Comments
 (0)