From 79b05217d14ece98b13c69ba3358b47248ab4bbc Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Fri, 4 Sep 2020 18:41:34 -0500 Subject: [PATCH] Fix JSONBArray to have elements of JSONB --- jsonb_array.go | 50 +++++++++++++++++++++++++++++++++++---------- jsonb_array_test.go | 36 ++++++++++++++++++++++++++++++++ typed_array_gen.sh | 2 +- 3 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 jsonb_array_test.go diff --git a/jsonb_array.go b/jsonb_array.go index 1e82843d..8f51b789 100644 --- a/jsonb_array.go +++ b/jsonb_array.go @@ -12,7 +12,7 @@ import ( ) type JSONBArray struct { - Elements []Text + Elements []JSONB Dimensions []ArrayDimension Status Status } @@ -40,7 +40,7 @@ func (dst *JSONBArray) Set(src interface{}) error { } else if len(value) == 0 { *dst = JSONBArray{Status: Present} } else { - elements := make([]Text, len(value)) + elements := make([]JSONB, len(value)) for i := range value { if err := elements[i].Set(value[i]); err != nil { return err @@ -53,7 +53,26 @@ func (dst *JSONBArray) Set(src interface{}) error { } } - case []Text: + case [][]byte: + if value == nil { + *dst = JSONBArray{Status: Null} + } else if len(value) == 0 { + *dst = JSONBArray{Status: Present} + } else { + elements := make([]JSONB, len(value)) + for i := range value { + if err := elements[i].Set(value[i]); err != nil { + return err + } + } + *dst = JSONBArray{ + Elements: elements, + Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}}, + Status: Present, + } + } + + case []JSONB: if value == nil { *dst = JSONBArray{Status: Null} } else if len(value) == 0 { @@ -91,7 +110,7 @@ func (dst *JSONBArray) Set(src interface{}) error { } *dst = JSONBArray{ - Elements: make([]Text, elementsLength), + Elements: make([]JSONB, elementsLength), Dimensions: dimensions, Status: Present, } @@ -108,7 +127,7 @@ func (dst *JSONBArray) Set(src interface{}) error { elementsLength *= int(dim.Length) } } - dst.Elements = make([]Text, elementsLength) + dst.Elements = make([]JSONB, elementsLength) elementCount, err = dst.setRecursive(reflectedValue, 0, 0) if err != nil { return err @@ -186,6 +205,15 @@ func (src *JSONBArray) AssignTo(dst interface{}) error { } return nil + case *[][]byte: + *v = make([][]byte, len(src.Elements)) + for i := range src.Elements { + if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil { + return err + } + } + return nil + } } @@ -277,13 +305,13 @@ func (dst *JSONBArray) DecodeText(ci *ConnInfo, src []byte) error { return err } - var elements []Text + var elements []JSONB if len(uta.Elements) > 0 { - elements = make([]Text, len(uta.Elements)) + elements = make([]JSONB, len(uta.Elements)) for i, s := range uta.Elements { - var elem Text + var elem JSONB var elemSrc []byte if s != "NULL" { elemSrc = []byte(s) @@ -324,7 +352,7 @@ func (dst *JSONBArray) DecodeBinary(ci *ConnInfo, src []byte) error { elementCount *= d.Length } - elements := make([]Text, elementCount) + elements := make([]JSONB, elementCount) for i := range elements { elemLen := int(int32(binary.BigEndian.Uint32(src[rp:]))) @@ -413,10 +441,10 @@ func (src JSONBArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) { Dimensions: src.Dimensions, } - if dt, ok := ci.DataTypeForName("text"); ok { + if dt, ok := ci.DataTypeForName("jsonb"); ok { arrayHeader.ElementOID = int32(dt.OID) } else { - return nil, errors.Errorf("unable to find oid for type name %v", "text") + return nil, errors.Errorf("unable to find oid for type name %v", "jsonb") } for i := range src.Elements { diff --git a/jsonb_array_test.go b/jsonb_array_test.go new file mode 100644 index 00000000..65f1777a --- /dev/null +++ b/jsonb_array_test.go @@ -0,0 +1,36 @@ +package pgtype_test + +import ( + "testing" + + "github.com/jackc/pgtype" + "github.com/jackc/pgtype/testutil" +) + +func TestJSONBArrayTranscode(t *testing.T) { + testutil.TestSuccessfulTranscode(t, "jsonb[]", []interface{}{ + &pgtype.JSONBArray{ + Elements: nil, + Dimensions: nil, + Status: pgtype.Present, + }, + &pgtype.JSONBArray{ + Elements: []pgtype.JSONB{ + {Bytes: []byte(`"foo"`), Status: pgtype.Present}, + {Status: pgtype.Null}, + }, + Dimensions: []pgtype.ArrayDimension{{Length: 2, LowerBound: 1}}, + Status: pgtype.Present, + }, + &pgtype.JSONBArray{Status: pgtype.Null}, + &pgtype.JSONBArray{ + Elements: []pgtype.JSONB{ + {Bytes: []byte(`"foo"`), Status: pgtype.Present}, + {Bytes: []byte("null"), Status: pgtype.Present}, + {Bytes: []byte("42"), Status: pgtype.Present}, + }, + Dimensions: []pgtype.ArrayDimension{{Length: 3, LowerBound: 1}}, + Status: pgtype.Present, + }, + }) +} diff --git a/typed_array_gen.sh b/typed_array_gen.sh index 607d3bc3..fe9eb62b 100755 --- a/typed_array_gen.sh +++ b/typed_array_gen.sh @@ -19,7 +19,7 @@ erb pgtype_array_type=ACLItemArray pgtype_element_type=ACLItem go_array_types=[] erb pgtype_array_type=HstoreArray pgtype_element_type=Hstore go_array_types=[]map[string]string element_type_name=hstore text_null=NULL binary_format=true typed_array.go.erb > hstore_array.go erb pgtype_array_type=NumericArray pgtype_element_type=Numeric go_array_types=[]float32,[]*float32,[]float64,[]*float64,[]int64,[]*int64,[]uint64,[]*uint64 element_type_name=numeric text_null=NULL binary_format=true typed_array.go.erb > numeric_array.go erb pgtype_array_type=UUIDArray pgtype_element_type=UUID go_array_types=[][16]byte,[][]byte,[]string,[]*string element_type_name=uuid text_null=NULL binary_format=true typed_array.go.erb > uuid_array.go -erb pgtype_array_type=JSONBArray pgtype_element_type=Text go_array_types=[]string element_type_name=text text_null=NULL binary_format=true typed_array.go.erb > jsonb_array.go +erb pgtype_array_type=JSONBArray pgtype_element_type=JSONB go_array_types=[]string,[][]byte element_type_name=jsonb text_null=NULL binary_format=true typed_array.go.erb > jsonb_array.go # While the binary format is theoretically possible it is only practical to use the text format. erb pgtype_array_type=EnumArray pgtype_element_type=GenericText go_array_types=[]string,[]*string text_null=NULL binary_format=false typed_array.go.erb > enum_array.go