Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
05d0f9e469
|
|||
ccd03e50c8
|
|||
1c77c2b8e8
|
|||
9f6f967299
|
|||
18c83f0f76
|
|||
a64f336e24
|
|||
14bbd205f8
|
|||
cecfb0d788
|
@@ -167,16 +167,31 @@ func Marshal(v any) ([]byte, error) {
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
type IndentOpt struct {
|
||||
Prefix string
|
||||
Indent string
|
||||
}
|
||||
|
||||
// MarshalSafeCollections is like Marshal except it will marshal nil maps and
|
||||
// slices as '{}' and '[]' respectfully instead of 'null'
|
||||
func MarshalSafeCollections(v interface{}, nilSafeSlices bool, nilSafeMaps bool) ([]byte, error) {
|
||||
func MarshalSafeCollections(v interface{}, nilSafeSlices bool, nilSafeMaps bool, indent *IndentOpt) ([]byte, error) {
|
||||
e := &encodeState{}
|
||||
err := e.marshal(v, encOpts{escapeHTML: true, nilSafeSlices: nilSafeSlices, nilSafeMaps: nilSafeMaps})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := e.Bytes()
|
||||
if indent != nil {
|
||||
var buf bytes.Buffer
|
||||
err = Indent(&buf, b, indent.Prefix, indent.Indent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
} else {
|
||||
return e.Bytes(), nil
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalIndent is like Marshal but applies Indent to format the output.
|
||||
// Each JSON element in the output will begin on a new line beginning with prefix
|
||||
|
@@ -1274,7 +1274,7 @@ func TestMarshalSafeCollections(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
b, err := MarshalSafeCollections(tt.in, true, true)
|
||||
b, err := MarshalSafeCollections(tt.in, true, true, nil)
|
||||
if err != nil {
|
||||
t.Errorf("test %d, unexpected failure: %v", i, err)
|
||||
}
|
||||
|
44
gojson/gionic.go
Normal file
44
gojson/gionic.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Render interface is copied from github.com/gin-gonic/gin@v1.8.1/render/render.go
|
||||
type Render interface {
|
||||
// Render writes data with custom ContentType.
|
||||
Render(http.ResponseWriter) error
|
||||
// WriteContentType writes custom ContentType.
|
||||
WriteContentType(w http.ResponseWriter)
|
||||
}
|
||||
|
||||
type GoJsonRender struct {
|
||||
Data any
|
||||
NilSafeSlices bool
|
||||
NilSafeMaps bool
|
||||
Indent *IndentOpt
|
||||
}
|
||||
|
||||
func (r GoJsonRender) Render(w http.ResponseWriter) error {
|
||||
header := w.Header()
|
||||
if val := header["Content-Type"]; len(val) == 0 {
|
||||
header["Content-Type"] = []string{"application/json; charset=utf-8"}
|
||||
}
|
||||
|
||||
jsonBytes, err := MarshalSafeCollections(r.Data, r.NilSafeSlices, r.NilSafeMaps, r.Indent)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = w.Write(jsonBytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r GoJsonRender) WriteContentType(w http.ResponseWriter) {
|
||||
header := w.Header()
|
||||
if val := header["Content-Type"]; len(val) == 0 {
|
||||
header["Content-Type"] = []string{"application/json; charset=utf-8"}
|
||||
}
|
||||
}
|
25
mongoext/registry.go
Normal file
25
mongoext/registry.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package mongoext
|
||||
|
||||
import (
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/bsoncodec"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/rfctime"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func CreateGoExtBsonRegistry() *bsoncodec.Registry {
|
||||
rb := bsoncodec.NewRegistryBuilder()
|
||||
|
||||
rb.RegisterTypeDecoder(reflect.TypeOf(rfctime.RFC3339Time{}), rfctime.RFC3339Time{})
|
||||
rb.RegisterTypeDecoder(reflect.TypeOf(&rfctime.RFC3339Time{}), rfctime.RFC3339Time{})
|
||||
|
||||
rb.RegisterTypeDecoder(reflect.TypeOf(rfctime.RFC3339NanoTime{}), rfctime.RFC3339NanoTime{})
|
||||
rb.RegisterTypeDecoder(reflect.TypeOf(&rfctime.RFC3339NanoTime{}), rfctime.RFC3339NanoTime{})
|
||||
|
||||
bsoncodec.DefaultValueEncoders{}.RegisterDefaultEncoders(rb)
|
||||
bsoncodec.DefaultValueDecoders{}.RegisterDefaultDecoders(rb)
|
||||
|
||||
bson.PrimitiveCodecs{}.RegisterPrimitiveCodecs(rb)
|
||||
|
||||
return rb.Build()
|
||||
}
|
@@ -5,7 +5,10 @@ import (
|
||||
"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"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -67,6 +70,9 @@ func (t *RFC3339Time) UnmarshalText(data []byte) error {
|
||||
|
||||
func (t *RFC3339Time) UnmarshalBSONValue(bt bsontype.Type, data []byte) error {
|
||||
if bt == bsontype.Null {
|
||||
// we can't set nil in UnmarshalBSONValue (so we use default(struct))
|
||||
// https://stackoverflow.com/questions/75167597
|
||||
// https://jira.mongodb.org/browse/GODRIVER-2252
|
||||
*t = RFC3339Time{}
|
||||
return nil
|
||||
}
|
||||
@@ -86,6 +92,32 @@ func (t RFC3339Time) MarshalBSONValue() (bsontype.Type, []byte, error) {
|
||||
return bson.MarshalValue(time.Time(t))
|
||||
}
|
||||
|
||||
func (t RFC3339Time) 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
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t RFC3339Time) Serialize() string {
|
||||
return t.Time().Format(t.FormatStr())
|
||||
}
|
||||
|
@@ -5,7 +5,10 @@ import (
|
||||
"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"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -67,6 +70,9 @@ func (t *RFC3339NanoTime) UnmarshalText(data []byte) error {
|
||||
|
||||
func (t *RFC3339NanoTime) UnmarshalBSONValue(bt bsontype.Type, data []byte) error {
|
||||
if bt == bsontype.Null {
|
||||
// we can't set nil in UnmarshalBSONValue (so we use default(struct))
|
||||
// https://stackoverflow.com/questions/75167597
|
||||
// https://jira.mongodb.org/browse/GODRIVER-2252
|
||||
*t = RFC3339NanoTime{}
|
||||
return nil
|
||||
}
|
||||
@@ -86,6 +92,38 @@ func (t RFC3339NanoTime) MarshalBSONValue() (bsontype.Type, []byte, error) {
|
||||
return bson.MarshalValue(time.Time(t))
|
||||
}
|
||||
|
||||
func (t RFC3339NanoTime) 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 RFC3339NanoTime) Serialize() string {
|
||||
return t.Time().Format(t.FormatStr())
|
||||
}
|
||||
|
Reference in New Issue
Block a user