Skip to content
This repository was archived by the owner on Jan 28, 2021. It is now read-only.

Commit d70c6db

Browse files
committed
sql: fix SQL method for arrays of JSON
Signed-off-by: Miguel Molina <[email protected]>
1 parent 9b083fa commit d70c6db

File tree

2 files changed

+87
-2
lines changed

2 files changed

+87
-2
lines changed

sql/type.go

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -897,12 +897,17 @@ func (t arrayT) SQL(v interface{}) (sqltypes.Value, error) {
897897
return sqltypes.NULL, nil
898898
}
899899

900-
v, err := t.Convert(v)
900+
v, err := convertForJSON(t, v)
901901
if err != nil {
902902
return sqltypes.Value{}, err
903903
}
904904

905-
return JSON.SQL(v)
905+
val, err := json.Marshal(v)
906+
if err != nil {
907+
return sqltypes.Value{}, err
908+
}
909+
910+
return sqltypes.MakeTrusted(sqltypes.TypeJSON, val), nil
906911
}
907912

908913
func (t arrayT) Convert(v interface{}) (interface{}, error) {
@@ -1015,6 +1020,7 @@ func IsText(t Type) bool {
10151020
return t == Text || t == Blob || t == JSON || IsVarChar(t)
10161021
}
10171022

1023+
// IsVarChar checks if t is a varchar type.
10181024
func IsVarChar(t Type) bool {
10191025
_, ok := t.(varCharT)
10201026
return ok
@@ -1096,3 +1102,66 @@ func UnderlyingType(t Type) Type {
10961102

10971103
return a.underlying
10981104
}
1105+
1106+
func convertForJSON(t Type, v interface{}) (interface{}, error) {
1107+
switch t := t.(type) {
1108+
case jsonT:
1109+
val, err := t.Convert(v)
1110+
if err != nil {
1111+
return nil, err
1112+
}
1113+
1114+
var doc interface{}
1115+
err = json.Unmarshal(val.([]byte), &doc)
1116+
if err != nil {
1117+
return nil, err
1118+
}
1119+
1120+
return doc, nil
1121+
case arrayT:
1122+
return convertArrayForJSON(t, v)
1123+
default:
1124+
return t.Convert(v)
1125+
}
1126+
}
1127+
1128+
func convertArrayForJSON(t arrayT, v interface{}) (interface{}, error) {
1129+
switch v := v.(type) {
1130+
case []interface{}:
1131+
var result = make([]interface{}, len(v))
1132+
for i, v := range v {
1133+
var err error
1134+
result[i], err = convertForJSON(t.underlying, v)
1135+
if err != nil {
1136+
return nil, err
1137+
}
1138+
}
1139+
return result, nil
1140+
case Generator:
1141+
var values []interface{}
1142+
for {
1143+
val, err := v.Next()
1144+
if err != nil {
1145+
if err == io.EOF {
1146+
break
1147+
}
1148+
return nil, err
1149+
}
1150+
1151+
val, err = convertForJSON(t.underlying, val)
1152+
if err != nil {
1153+
return nil, err
1154+
}
1155+
1156+
values = append(values, val)
1157+
}
1158+
1159+
if err := v.Close(); err != nil {
1160+
return nil, err
1161+
}
1162+
1163+
return values, nil
1164+
default:
1165+
return nil, ErrNotArray.New(v)
1166+
}
1167+
}

sql/type_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,22 @@ func TestUnderlyingType(t *testing.T) {
401401
require.Equal(t, Text, UnderlyingType(Text))
402402
}
403403

404+
type testJSONStruct struct {
405+
A int
406+
B string
407+
}
408+
409+
func TestJSONArraySQL(t *testing.T) {
410+
require := require.New(t)
411+
val, err := Array(JSON).SQL([]interface{}{
412+
testJSONStruct{1, "foo"},
413+
testJSONStruct{2, "bar"},
414+
})
415+
require.NoError(err)
416+
expected := `[{"A":1,"B":"foo"},{"A":2,"B":"bar"}]`
417+
require.Equal(expected, string(val.Raw()))
418+
}
419+
404420
func eq(t *testing.T, typ Type, a, b interface{}) {
405421
t.Helper()
406422
cmp, err := typ.Compare(a, b)

0 commit comments

Comments
 (0)