github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/json/json_contains_path_test.go (about) 1 // Copyright 2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package json 16 17 import ( 18 "testing" 19 20 "github.com/pkg/errors" 21 "github.com/stretchr/testify/require" 22 23 "github.com/dolthub/go-mysql-server/sql" 24 "github.com/dolthub/go-mysql-server/sql/expression" 25 "github.com/dolthub/go-mysql-server/sql/types" 26 ) 27 28 func TestJSONContainsPath(t *testing.T) { 29 // Verify arg count 3 or more. 30 _, err := NewJSONContainsPath() 31 require.Error(t, err) 32 33 _, err = NewJSONContainsPath( 34 expression.NewGetField(0, types.JSON, "arg1", false), 35 ) 36 require.Error(t, err) 37 38 _, err = NewJSONContainsPath( 39 expression.NewGetField(0, types.JSON, "arg1", false), 40 expression.NewGetField(1, types.LongText, "arg2", false), 41 ) 42 require.Error(t, err) 43 44 // setup call expressions for calling with 1, 2, and 3 paths. 45 onePath, err := NewJSONContainsPath( 46 expression.NewGetField(0, types.JSON, "arg1", false), 47 expression.NewGetField(1, types.LongText, "arg2", false), 48 expression.NewGetField(2, types.LongText, "arg3", false), 49 ) 50 require.NoError(t, err) 51 52 twoPath, err := NewJSONContainsPath( 53 expression.NewGetField(0, types.JSON, "arg1", false), 54 expression.NewGetField(1, types.LongText, "arg2", false), 55 expression.NewGetField(2, types.LongText, "arg3", false), 56 expression.NewGetField(3, types.LongText, "arg4", false), 57 ) 58 require.NoError(t, err) 59 60 threePath, err := NewJSONContainsPath( 61 expression.NewGetField(0, types.JSON, "arg1", false), 62 expression.NewGetField(1, types.LongText, "arg2", false), 63 expression.NewGetField(2, types.LongText, "arg3", false), 64 expression.NewGetField(3, types.LongText, "arg4", false), 65 expression.NewGetField(4, types.LongText, "arg5", false), 66 ) 67 require.NoError(t, err) 68 69 testCases := []struct { 70 fCall sql.Expression 71 input sql.Row 72 expected interface{} 73 err error 74 }{ 75 {onePath, sql.Row{`{"a": 1, "b": 2, "c": {"d": 4}}`, `oNe`, `$.a`}, true, nil}, 76 {onePath, sql.Row{`{"a": 1, "b": 2, "c": {"d": 4}}`, `one`, `$.e`}, false, nil}, 77 {onePath, sql.Row{`{"a": 1, "b": 2, "c": {"d": 4}}`, `all`, `$.e`}, false, nil}, 78 {onePath, sql.Row{`{"a": 1, "b": 2, "c": {"d": 4}}`, `All`, `$.c.d`}, true, nil}, 79 80 {twoPath, sql.Row{`{"a": 1, "b": 2, "c": {"d": 4}}`, `one`, `$.a`, `$.e`}, true, nil}, 81 {twoPath, sql.Row{`{"a": 1, "b": 2, "c": {"d": 4}}`, `ALL`, `$.a`, `$.e`}, false, nil}, 82 83 {twoPath, sql.Row{`{"a": 1, "b": 2, "c": {"d": {"e" : 42}}}`, `all`, `$.a`, `$.c.d.e`}, true, nil}, 84 {threePath, sql.Row{`{"a": 1, "b": 2, "c": {"d": {"e" : 42}}}`, `all`, `$.a`, `$.c.d.e`, `$.x`}, false, nil}, 85 {threePath, sql.Row{`{"a": 1, "b": 2, "c": {"d": {"e" : 42}}}`, `one`, `$.a`, `$.c.d.e`, `$.x`}, true, nil}, 86 87 // NULL inputs. Any NULL should result in NULL output. 88 {onePath, sql.Row{nil, `one`, `$.a`}, nil, nil}, 89 {onePath, sql.Row{`{"a": 1}`, nil, `$.a`}, nil, nil}, 90 {twoPath, sql.Row{`{"a": 1}`, `one`, `$.a`, nil}, true, nil}, // Match MySQL behavior, not docs. 91 {twoPath, sql.Row{`{"a": 1}`, `one`, nil, `$.a`}, nil, nil}, 92 {twoPath, sql.Row{`{"a": 1}`, "all", `$.x`, nil}, false, nil}, // Match MySQL behavior, not docs. 93 {twoPath, sql.Row{`{"a": 1}`, `all`, `$.a`, nil}, nil, nil}, 94 95 // Error cases 96 {onePath, sql.Row{`{"a": 1}`, `None`, `$.a`}, nil, errors.New("The oneOrAll argument to json_contains_path may take these values: 'one' or 'all'")}, 97 {onePath, sql.Row{`{"a": 1`, `One`, `$.a`}, nil, errors.New(`Invalid JSON text: {"a": 1`)}, 98 {threePath, sql.Row{`{"a": 1, "b": 2, "c": {"d": {"e" : 42}}}`, `one`, 42, `$.c.d.e`, `$.x`}, nil, errors.New(`Invalid JSON path expression. Path must start with '$', but received: '42'`)}, 99 } 100 101 for _, testcase := range testCases { 102 t.Run(testcase.fCall.String(), func(t *testing.T) { 103 require := require.New(t) 104 result, err := testcase.fCall.Eval(sql.NewEmptyContext(), testcase.input) 105 if testcase.err == nil { 106 require.NoError(err) 107 } else { 108 require.Equal(err.Error(), testcase.err.Error()) 109 } 110 111 require.Equal(testcase.expected, result) 112 }) 113 } 114 }