diff --git a/goextVersion.go b/goextVersion.go index b01b244..97d072d 100644 --- a/goextVersion.go +++ b/goextVersion.go @@ -1,5 +1,5 @@ package goext -const GoextVersion = "0.0.312" +const GoextVersion = "0.0.313" -const GoextVersionTimestamp = "2023-11-10T10:16:31+0100" +const GoextVersionTimestamp = "2023-11-10T13:26:30+0100" diff --git a/mongoext/registry.go b/mongoext/registry.go index 9b67579..9548cee 100644 --- a/mongoext/registry.go +++ b/mongoext/registry.go @@ -18,6 +18,15 @@ func CreateGoExtBsonRegistry() *bsoncodec.Registry { rb.RegisterTypeDecoder(reflect.TypeOf(rfctime.RFC3339NanoTime{}), rfctime.RFC3339NanoTime{}) rb.RegisterTypeDecoder(reflect.TypeOf(&rfctime.RFC3339NanoTime{}), rfctime.RFC3339NanoTime{}) + rb.RegisterTypeDecoder(reflect.TypeOf(rfctime.RFC3339NanoTime{}), rfctime.UnixTime{}) + rb.RegisterTypeDecoder(reflect.TypeOf(&rfctime.RFC3339NanoTime{}), rfctime.UnixTime{}) + + rb.RegisterTypeDecoder(reflect.TypeOf(rfctime.RFC3339NanoTime{}), rfctime.UnixMilliTime{}) + rb.RegisterTypeDecoder(reflect.TypeOf(&rfctime.RFC3339NanoTime{}), rfctime.UnixMilliTime{}) + + rb.RegisterTypeDecoder(reflect.TypeOf(rfctime.RFC3339NanoTime{}), rfctime.UnixNanoTime{}) + rb.RegisterTypeDecoder(reflect.TypeOf(&rfctime.RFC3339NanoTime{}), rfctime.UnixNanoTime{}) + rb.RegisterTypeDecoder(reflect.TypeOf(rfctime.Date{}), rfctime.Date{}) rb.RegisterTypeDecoder(reflect.TypeOf(&rfctime.Date{}), rfctime.Date{}) diff --git a/rfctime/unix.go b/rfctime/unix.go index bcbcfea..91529b1 100644 --- a/rfctime/unix.go +++ b/rfctime/unix.go @@ -2,6 +2,13 @@ package rfctime import ( "encoding/json" + "errors" + "fmt" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/bsoncodec" + "go.mongodb.org/mongo-driver/bson/bsonrw" + "go.mongodb.org/mongo-driver/bson/bsontype" + "reflect" "strconv" "time" ) @@ -59,6 +66,63 @@ func (t *UnixTime) UnmarshalText(data []byte) error { return nil } +func (t *UnixTime) UnmarshalBSONValue(bt bsontype.Type, data []byte) error { + if bt == bson.TypeNull { + // we can't set nil in UnmarshalBSONValue (so we use default(struct)) + // Use mongoext.CreateGoExtBsonRegistry if you need to unmarsh pointer values + // https://stackoverflow.com/questions/75167597 + // https://jira.mongodb.org/browse/GODRIVER-2252 + *t = UnixTime{} + return nil + } + if bt != bson.TypeDateTime { + return errors.New(fmt.Sprintf("cannot unmarshal %v into RFC3339NanoTime", bt)) + } + var tt time.Time + err := bson.RawValue{Type: bt, Value: data}.Unmarshal(&tt) + if err != nil { + return err + } + *t = UnixTime(tt) + return nil +} + +func (t UnixTime) MarshalBSONValue() (bsontype.Type, []byte, error) { + return bson.MarshalValue(time.Time(t)) +} + +func (t UnixTime) DecodeValue(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { + if val.Kind() == reflect.Ptr && val.IsNil() { + if !val.CanSet() { + return errors.New("ValueUnmarshalerDecodeValue") + } + val.Set(reflect.New(val.Type().Elem())) + } + + tp, src, err := bsonrw.Copier{}.CopyValueToBytes(vr) + if err != nil { + return err + } + + if val.Kind() == reflect.Ptr && len(src) == 0 { + val.Set(reflect.Zero(val.Type())) + return nil + } + + err = t.UnmarshalBSONValue(tp, src) + if err != nil { + return err + } + + if val.Kind() == reflect.Ptr { + val.Set(reflect.ValueOf(&t)) + } else { + val.Set(reflect.ValueOf(t)) + } + + return nil +} + func (t UnixTime) Serialize() string { return strconv.FormatInt(t.Time().Unix(), 10) } diff --git a/rfctime/unixMilli.go b/rfctime/unixMilli.go index 1f5b766..44e6956 100644 --- a/rfctime/unixMilli.go +++ b/rfctime/unixMilli.go @@ -2,6 +2,13 @@ package rfctime import ( "encoding/json" + "errors" + "fmt" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/bsoncodec" + "go.mongodb.org/mongo-driver/bson/bsonrw" + "go.mongodb.org/mongo-driver/bson/bsontype" + "reflect" "strconv" "time" ) @@ -59,6 +66,63 @@ func (t *UnixMilliTime) UnmarshalText(data []byte) error { return nil } +func (t *UnixMilliTime) UnmarshalBSONValue(bt bsontype.Type, data []byte) error { + if bt == bson.TypeNull { + // we can't set nil in UnmarshalBSONValue (so we use default(struct)) + // Use mongoext.CreateGoExtBsonRegistry if you need to unmarsh pointer values + // https://stackoverflow.com/questions/75167597 + // https://jira.mongodb.org/browse/GODRIVER-2252 + *t = UnixMilliTime{} + return nil + } + if bt != bson.TypeDateTime { + return errors.New(fmt.Sprintf("cannot unmarshal %v into RFC3339NanoTime", bt)) + } + var tt time.Time + err := bson.RawValue{Type: bt, Value: data}.Unmarshal(&tt) + if err != nil { + return err + } + *t = UnixMilliTime(tt) + return nil +} + +func (t UnixMilliTime) MarshalBSONValue() (bsontype.Type, []byte, error) { + return bson.MarshalValue(time.Time(t)) +} + +func (t UnixMilliTime) DecodeValue(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { + if val.Kind() == reflect.Ptr && val.IsNil() { + if !val.CanSet() { + return errors.New("ValueUnmarshalerDecodeValue") + } + val.Set(reflect.New(val.Type().Elem())) + } + + tp, src, err := bsonrw.Copier{}.CopyValueToBytes(vr) + if err != nil { + return err + } + + if val.Kind() == reflect.Ptr && len(src) == 0 { + val.Set(reflect.Zero(val.Type())) + return nil + } + + err = t.UnmarshalBSONValue(tp, src) + if err != nil { + return err + } + + if val.Kind() == reflect.Ptr { + val.Set(reflect.ValueOf(&t)) + } else { + val.Set(reflect.ValueOf(t)) + } + + return nil +} + func (t UnixMilliTime) Serialize() string { return strconv.FormatInt(t.Time().UnixMilli(), 10) } diff --git a/rfctime/unixNano.go b/rfctime/unixNano.go index ce039f9..5bf5a09 100644 --- a/rfctime/unixNano.go +++ b/rfctime/unixNano.go @@ -2,6 +2,13 @@ package rfctime import ( "encoding/json" + "errors" + "fmt" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/bsoncodec" + "go.mongodb.org/mongo-driver/bson/bsonrw" + "go.mongodb.org/mongo-driver/bson/bsontype" + "reflect" "strconv" "time" ) @@ -59,6 +66,63 @@ func (t *UnixNanoTime) UnmarshalText(data []byte) error { return nil } +func (t *UnixNanoTime) UnmarshalBSONValue(bt bsontype.Type, data []byte) error { + if bt == bson.TypeNull { + // we can't set nil in UnmarshalBSONValue (so we use default(struct)) + // Use mongoext.CreateGoExtBsonRegistry if you need to unmarsh pointer values + // https://stackoverflow.com/questions/75167597 + // https://jira.mongodb.org/browse/GODRIVER-2252 + *t = UnixNanoTime{} + return nil + } + if bt != bson.TypeDateTime { + return errors.New(fmt.Sprintf("cannot unmarshal %v into RFC3339NanoTime", bt)) + } + var tt time.Time + err := bson.RawValue{Type: bt, Value: data}.Unmarshal(&tt) + if err != nil { + return err + } + *t = UnixNanoTime(tt) + return nil +} + +func (t UnixNanoTime) MarshalBSONValue() (bsontype.Type, []byte, error) { + return bson.MarshalValue(time.Time(t)) +} + +func (t UnixNanoTime) DecodeValue(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error { + if val.Kind() == reflect.Ptr && val.IsNil() { + if !val.CanSet() { + return errors.New("ValueUnmarshalerDecodeValue") + } + val.Set(reflect.New(val.Type().Elem())) + } + + tp, src, err := bsonrw.Copier{}.CopyValueToBytes(vr) + if err != nil { + return err + } + + if val.Kind() == reflect.Ptr && len(src) == 0 { + val.Set(reflect.Zero(val.Type())) + return nil + } + + err = t.UnmarshalBSONValue(tp, src) + if err != nil { + return err + } + + if val.Kind() == reflect.Ptr { + val.Set(reflect.ValueOf(&t)) + } else { + val.Set(reflect.ValueOf(t)) + } + + return nil +} + func (t UnixNanoTime) Serialize() string { return strconv.FormatInt(t.Time().UnixNano(), 10) }