func TestObjectIdValue(t *testing.T) { Convey("When converting JSON with ObjectId values", t, func() { Convey("works for ObjectId constructor", func() { key := "key" jsonMap := map[string]interface{}{ key: json.ObjectId("0123456789abcdef01234567"), } err := ConvertJSONDocumentToBSON(jsonMap) So(err, ShouldBeNil) So(jsonMap[key], ShouldEqual, bson.ObjectIdHex("0123456789abcdef01234567")) }) Convey(`works for ObjectId document ('{ "$oid": "0123456789abcdef01234567" }')`, func() { key := "key" jsonMap := map[string]interface{}{ key: map[string]interface{}{ "$oid": "0123456789abcdef01234567", }, } err := ConvertJSONDocumentToBSON(jsonMap) So(err, ShouldBeNil) So(jsonMap[key], ShouldEqual, bson.ObjectIdHex("0123456789abcdef01234567")) }) }) }
func TestArraysBSONToJSON(t *testing.T) { testutil.VerifyTestType(t, testutil.UnitTestType) Convey("Converting BSON arrays to JSON arrays", t, func() { Convey("should work for empty arrays", func() { jArr, err := ConvertBSONValueToJSON([]interface{}{}) So(err, ShouldBeNil) So(jArr, ShouldResemble, []interface{}{}) }) Convey("should work for one-level deep arrays", func() { objId := bson.NewObjectId() bsonArr := []interface{}{objId, 28, 0.999, "plain"} _jArr, err := ConvertBSONValueToJSON(bsonArr) So(err, ShouldBeNil) jArr, ok := _jArr.([]interface{}) So(ok, ShouldBeTrue) So(len(jArr), ShouldEqual, 4) So(jArr[0], ShouldEqual, json.ObjectId(objId.Hex())) So(jArr[1], ShouldEqual, 28) So(jArr[2], ShouldEqual, 0.999) So(jArr[3], ShouldEqual, "plain") }) Convey("should work for arrays with embedded objects", func() { bsonObj := []interface{}{ 80, bson.M{ "a": int64(20), "b": bson.M{ "c": bson.RegEx{Pattern: "hi", Options: "i"}, }, }, } __jObj, err := ConvertBSONValueToJSON(bsonObj) So(err, ShouldBeNil) _jObj, ok := __jObj.([]interface{}) So(ok, ShouldBeTrue) jObj, ok := _jObj[1].(bson.M) So(ok, ShouldBeTrue) So(len(jObj), ShouldEqual, 2) So(jObj["a"], ShouldEqual, json.NumberLong(20)) jjObj, ok := jObj["b"].(bson.M) So(ok, ShouldBeTrue) So(jjObj["c"], ShouldResemble, json.RegExp{"hi", "i"}) So(jjObj["c"], ShouldNotResemble, json.RegExp{"i", "hi"}) }) }) }
func TestObjectIdBSONToJSON(t *testing.T) { testutil.VerifyTestType(t, testutil.UnitTestType) Convey("Converting a BSON ObjectId", t, func() { Convey("that is valid to JSON should produce a json.ObjectId", func() { bsonObjId := bson.NewObjectId() jsonObjId := json.ObjectId(bsonObjId.Hex()) _jObjId, err := ConvertBSONValueToJSON(bsonObjId) So(err, ShouldBeNil) jObjId, ok := _jObjId.(json.ObjectId) So(ok, ShouldBeTrue) So(jObjId, ShouldNotEqual, bsonObjId) So(jObjId, ShouldEqual, jsonObjId) }) }) }
// 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) }
func (d *LogDoc) ObjectId(value string) mongo_json.ObjectId { return mongo_json.ObjectId(value) }
// 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) }