func TestNumberIntValue(t *testing.T) { Convey("When converting JSON with NumberInt values", t, func() { Convey("works for NumberInt constructor", func() { key := "key" jsonMap := map[string]interface{}{ key: json.NumberInt(42), } err := ConvertJSONDocumentToBSON(jsonMap) So(err, ShouldBeNil) So(jsonMap[key], ShouldEqual, int64(42)) }) Convey(`fails for NumberInt document ('{ "$numberInt": "42" }')`, func() { key := "key" jsonMap := map[string]interface{}{ key: map[string]interface{}{ "$numberInt": "42", }, } err := ConvertJSONDocumentToBSON(jsonMap) So(err, ShouldBeNil) So(jsonMap[key], ShouldEqual, int64(42)) }) }) }
func Test64BitIntBSONToJSON(t *testing.T) { testutil.VerifyTestType(t, testutil.UnitTestType) Convey("Converting a BSON int64 to JSON", t, func() { Convey("should produce a json.NumberLong", func() { _jObj, err := ConvertBSONValueToJSON(int32(243)) So(err, ShouldBeNil) jObj, ok := _jObj.(json.NumberInt) So(ok, ShouldBeTrue) So(jObj, ShouldEqual, json.NumberInt(243)) }) }) }
// GetBSONValueAsJSON is equivalent to ConvertBSONValueToJSON, but does not mutate its argument. func GetBSONValueAsJSON(x interface{}) (interface{}, error) { switch v := x.(type) { case nil: return nil, nil case bool: return v, nil case *bson.M: // document doc, err := getConvertedKeys(*v) if err != nil { return nil, err } return doc, err case bson.M: // document return getConvertedKeys(v) case map[string]interface{}: return getConvertedKeys(v) case bson.D: out := bson.D{} for _, value := range v { jsonValue, err := GetBSONValueAsJSON(value.Value) if err != nil { return nil, err } out = append(out, bson.DocElem{ Name: value.Name, Value: jsonValue, }) } return MarshalD(out), nil case MarshalD: out, err := GetBSONValueAsJSON(bson.D(v)) if err != nil { return nil, err } return MarshalD(out.(bson.D)), nil case []interface{}: // array out := []interface{}{} for _, value := range v { jsonValue, err := GetBSONValueAsJSON(value) if err != nil { return nil, err } out = append(out, jsonValue) } return out, nil case string: return v, nil // require no conversion case int: return json.NumberInt(v), nil case bson.ObjectId: // ObjectId return json.ObjectId(v.Hex()), nil case bson.Decimal128: return json.Decimal128{v}, nil case time.Time: // Date return json.Date(v.Unix()*1000 + int64(v.Nanosecond()/1e6)), nil case int64: // NumberLong return json.NumberLong(v), nil case int32: // NumberInt return json.NumberInt(v), nil case float64: return json.NumberFloat(v), nil case float32: return json.NumberFloat(float64(v)), nil case []byte: // BinData (with generic type) data := base64.StdEncoding.EncodeToString(v) return json.BinData{0x00, data}, nil case bson.Binary: // BinData data := base64.StdEncoding.EncodeToString(v.Data) return json.BinData{v.Kind, data}, nil case mgo.DBRef: // DBRef return json.DBRef{v.Collection, v.Id, v.Database}, nil case bson.DBPointer: // DBPointer return json.DBPointer{v.Namespace, v.Id}, nil case bson.RegEx: // RegExp return json.RegExp{v.Pattern, v.Options}, nil case bson.MongoTimestamp: // Timestamp timestamp := int64(v) return json.Timestamp{ Seconds: uint32(timestamp >> 32), Increment: uint32(timestamp), }, nil case bson.JavaScript: // JavaScript var scope interface{} var err error if v.Scope != nil { scope, err = GetBSONValueAsJSON(v.Scope) if err != nil { return nil, err } } return json.JavaScript{v.Code, scope}, nil default: switch x { case bson.MinKey: // MinKey return json.MinKey{}, nil case bson.MaxKey: // MaxKey return json.MaxKey{}, nil case bson.Undefined: // undefined return json.Undefined{}, nil } } return nil, fmt.Errorf("conversion of BSON value '%v' of type '%T' not supported", x, x) }
// ConvertBSONValueToJSON walks through a document or an array and // replaces any BSON value with its corresponding extended JSON type. func ConvertBSONValueToJSON(x interface{}) (interface{}, error) { switch v := x.(type) { case nil: return nil, nil case bool: return v, nil case *bson.M: // document doc, err := convertKeys(*v) if err != nil { return nil, err } return doc, err case bson.M: // document return convertKeys(v) case []interface{}: // array for i, value := range v { jsonValue, err := ConvertBSONValueToJSON(value) if err != nil { return nil, err } v[i] = jsonValue } return v, nil case string, float64: return v, nil // require no conversion case int: return json.NumberInt(v), nil case bson.ObjectId: // ObjectId return json.ObjectId(v.Hex()), nil case time.Time: // Date return json.Date(v.Unix()*1000 + int64(v.Nanosecond()/1e6)), nil case int64: // NumberLong return json.NumberLong(v), nil case int32: // NumberInt return json.NumberInt(v), nil case []byte: // BinData (with generic type) data := base64.StdEncoding.EncodeToString(v) return json.BinData{0x00, data}, nil case bson.Binary: // BinData data := base64.StdEncoding.EncodeToString(v.Data) return json.BinData{v.Kind, data}, nil case mgo.DBRef: // DBRef return json.DBRef{v.Collection, v.Id, v.Database}, nil case bson.RegEx: // RegExp return json.RegExp{v.Pattern, v.Options}, nil case bson.MongoTimestamp: // Timestamp inc := uint32(int64(v) & 0xffff) secs := uint32((int64(v) & (0xffff << 32)) >> 32) return json.Timestamp{secs, inc}, nil default: switch x { case bson.MinKey: // MinKey return json.MinKey{}, nil case bson.MaxKey: // MaxKey return json.MaxKey{}, nil case bson.Undefined: // undefined return json.Undefined{}, nil } } return nil, fmt.Errorf("Conversion of BSON type '%v' not supported %v", reflect.TypeOf(x), x) }
// ConvertBSONValueToJSON walks through a document or an array and // converts any BSON value to its corresponding extended JSON type. // It returns the converted JSON document and any error encountered. func ConvertBSONValueToJSON(x interface{}) (interface{}, error) { switch v := x.(type) { case nil: return nil, nil case bool: return v, nil case *bson.M: // document doc, err := convertKeys(*v) if err != nil { return nil, err } return doc, err case bson.M: // document return convertKeys(v) case map[string]interface{}: return convertKeys(v) case bson.D: for i, value := range v { jsonValue, err := ConvertBSONValueToJSON(value.Value) if err != nil { return nil, err } v[i].Value = jsonValue } return MarshalD(v), nil case MarshalD: return v, nil case []interface{}: // array for i, value := range v { jsonValue, err := ConvertBSONValueToJSON(value) if err != nil { return nil, err } v[i] = jsonValue } return v, nil case string: return v, nil // require no conversion case int: return json.NumberInt(v), nil case bson.ObjectId: // ObjectId return json.ObjectId(v.Hex()), nil case time.Time: // Date return json.Date(v.Unix()*1000 + int64(v.Nanosecond()/1e6)), nil case int64: // NumberLong return json.NumberLong(v), nil case int32: // NumberInt return json.NumberInt(v), nil case float64: return json.NumberFloat(v), nil case float32: return json.NumberFloat(float64(v)), nil case []byte: // BinData (with generic type) data := base64.StdEncoding.EncodeToString(v) return json.BinData{0x00, data}, nil case bson.Binary: // BinData data := base64.StdEncoding.EncodeToString(v.Data) return json.BinData{v.Kind, data}, nil case mgo.DBRef: // DBRef return json.DBRef{v.Collection, v.Id, v.Database}, nil case bson.DBPointer: // DBPointer return json.DBPointer{v.Namespace, v.Id}, nil case bson.RegEx: // RegExp return json.RegExp{v.Pattern, v.Options}, nil case bson.MongoTimestamp: // Timestamp timestamp := int64(v) return json.Timestamp{ Seconds: uint32(timestamp >> 32), Increment: uint32(timestamp), }, nil case bson.JavaScript: // JavaScript var scope interface{} var err error if v.Scope != nil { scope, err = ConvertBSONValueToJSON(v.Scope) if err != nil { return nil, err } } return json.JavaScript{v.Code, scope}, nil default: switch x { case bson.MinKey: // MinKey return json.MinKey{}, nil case bson.MaxKey: // MaxKey return json.MaxKey{}, nil case bson.Undefined: // undefined return json.Undefined{}, nil } } return nil, fmt.Errorf("conversion of BSON type '%v' not supported %v", reflect.TypeOf(x), x) }
// ConvertBSONValueToJSON walks through a document or an array and converts any // BSON value to its corresponding extended JSON type. It returns the converted // JSON document and any error encountered. func ConvertBSONValueToJSON(x interface{}) (interface{}, error) { switch v := x.(type) { case nil: return nil, nil case bool: return v, nil case *bson.M: // document doc, err := convertKeys(*v) if err != nil { return nil, err } return doc, err case bson.M: // document return convertKeys(v) case map[string]interface{}: return convertKeys(v) case []bson.Raw: out := make([]interface{}, len(v)) for i, value := range v { out[i] = value } return ConvertBSONValueToJSON(out) case bson.Raw: // Unmarshal the raw into a bson.D, then process that. convertedFromRaw := bson.D{} err := v.Unmarshal(&convertedFromRaw) if err != nil { return nil, err } return ConvertBSONValueToJSON(convertedFromRaw) case (*bson.Raw): return ConvertBSONValueToJSON(*v) case (*bson.D): return ConvertBSONValueToJSON(*v) case bson.D: for i, value := range v { jsonValue, err := ConvertBSONValueToJSON(value.Value) if err != nil { return nil, err } v[i].Value = jsonValue } return v.Map(), nil case []bson.D: out := make([]interface{}, len(v)) for i, value := range v { out[i] = value } return ConvertBSONValueToJSON(out) case []interface{}: // array for i, value := range v { jsonValue, err := ConvertBSONValueToJSON(value) if err != nil { return nil, err } v[i] = jsonValue } return v, nil case string: return v, nil // require no conversion case int: return json.NumberInt(v), nil case bson.ObjectId: // ObjectId return json.ObjectId(v.Hex()), nil case time.Time: // Date return json.Date(v.Unix()*1000 + int64(v.Nanosecond()/1e6)), nil case int64: // NumberLong return json.NumberLong(v), nil case int32: // NumberInt return json.NumberInt(v), nil case float64: return json.NumberFloat(v), nil case float32: return json.NumberFloat(float64(v)), nil case []byte: // BinData (with generic type) data := base64.StdEncoding.EncodeToString(v) return json.BinData{0x00, data}, nil case bson.Binary: // BinData data := base64.StdEncoding.EncodeToString(v.Data) return json.BinData{v.Kind, data}, nil case mgo.DBRef: // DBRef return map[string]interface{}{"$ref": v.Collection, "$id": v.Id}, nil //case bson.DBPointer: // DBPointer //return json.DBPointer{v.Namespace, v.Id}, nil case bson.RegEx: // RegExp return json.RegExp{v.Pattern, v.Options}, nil case bson.MongoTimestamp: // Timestamp timestamp := int64(v) return json.Timestamp{ Seconds: uint32(timestamp >> 32), Increment: uint32(timestamp), }, nil case bson.JavaScript: // JavaScript var scope interface{} var err error if v.Scope != nil { scope, err = ConvertBSONValueToJSON(v.Scope) if err != nil { return nil, err } } return json.JavaScript{v.Code, scope}, nil default: switch x { case bson.MinKey: // MinKey return json.MinKey{}, nil case bson.MaxKey: // MaxKey return json.MaxKey{}, nil case bson.Undefined: // undefined return json.Undefined{}, nil } } if valueOfX := reflect.ValueOf(x); valueOfX.Kind() == reflect.Slice || valueOfX.Kind() == reflect.Array { result := make([]interface{}, 0, valueOfX.Len()) for i := 0; i < (valueOfX.Len()); i++ { v := valueOfX.Index(i).Interface() jsonResult, err := ConvertBSONValueToJSON(v) if err != nil { return nil, err } result = append(result, jsonResult) } return result, nil } return nil, fmt.Errorf("conversion of BSON type '%v' not supported %v", reflect.TypeOf(x), x) }