github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/json/json_remove_test.go (about)

     1  // Copyright 2023 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  	"fmt"
    19  	"strings"
    20  	"testing"
    21  
    22  	"github.com/stretchr/testify/require"
    23  	"gopkg.in/src-d/go-errors.v1"
    24  
    25  	"github.com/dolthub/go-mysql-server/sql"
    26  	"github.com/dolthub/go-mysql-server/sql/types"
    27  )
    28  
    29  func TestRemove(t *testing.T) {
    30  	_, err := NewJSONRemove()
    31  	require.True(t, errors.Is(err, sql.ErrInvalidArgumentNumber))
    32  
    33  	f1 := buildGetFieldExpressions(t, NewJSONRemove, 2)
    34  
    35  	f2 := buildGetFieldExpressions(t, NewJSONRemove, 3)
    36  
    37  	json := `{"a": 1, "b": [2, 3], "c": {"d": "foo"}}`
    38  
    39  	testCases := []struct {
    40  		f        sql.Expression
    41  		row      sql.Row
    42  		expected interface{}
    43  		err      error
    44  	}{
    45  		{f1, sql.Row{json, "$.a"}, `{"b": [2, 3], "c": {"d": "foo"}}`, nil},                                  // remove existing
    46  		{f1, sql.Row{json, "$.b[0]"}, `{"a": 1, "b": [3], "c": {"d": "foo"}}`, nil},                          // remove existing array element
    47  		{f1, sql.Row{json, "$.c.d"}, `{"a": 1, "b": [2, 3], "c": {}}`, nil},                                  // remove existing nested
    48  		{f1, sql.Row{json, "$.c"}, `{"a": 1, "b": [2, 3]}`, nil},                                             // remove existing object
    49  		{f1, sql.Row{json, "$.a.e"}, json, nil},                                                              // remove nothing when path not found
    50  		{f1, sql.Row{json, "$.c[5]"}, json, nil},                                                             // remove nothing when path not found
    51  		{f1, sql.Row{json, "$.b[last]"}, `{"a": 1, "b": [2], "c": {"d": "foo"}}`, nil},                       // remove last element in array
    52  		{f1, sql.Row{json, "$.b[5]"}, json, nil},                                                             // remove nothing when array index out of bounds
    53  		{f1, sql.Row{json, "$[0]"}, json, nil},                                                               // remove nothing when provided a bogus path.
    54  		{f1, sql.Row{json, "$.[0]"}, nil, ErrInvalidPath},                                                    // improper struct indexing
    55  		{f1, sql.Row{json, "foo", "test"}, nil, ErrInvalidPath},                                              // invalid path
    56  		{f1, sql.Row{json, "$.c.*", "test"}, nil, ErrPathWildcard},                                           // path contains * wildcard
    57  		{f1, sql.Row{json, "$.c.**", "test"}, nil, ErrPathWildcard},                                          // path contains ** wildcard
    58  		{f1, sql.Row{json, "$"}, nil, fmt.Errorf("The path expression '$' is not allowed in this context.")}, // whole document
    59  		{f1, sql.Row{nil, "$"}, nil, nil},                                                                    // null document
    60  		{f2, sql.Row{json, "$.foo", nil}, nil, nil},                                                          // if any path is null, return null
    61  		{f2, sql.Row{json, "$.a", "$.b"}, `{"c": {"d": "foo"}}`, nil},                                        // remove multiple paths
    62  	}
    63  
    64  	for _, tstC := range testCases {
    65  		var paths []string
    66  		for _, path := range tstC.row[1:] {
    67  			if _, ok := path.(string); ok {
    68  				paths = append(paths, path.(string))
    69  			}
    70  		}
    71  
    72  		t.Run(tstC.f.String()+"."+strings.Join(paths, ","), func(t *testing.T) {
    73  			req := require.New(t)
    74  			result, err := tstC.f.Eval(sql.NewEmptyContext(), tstC.row)
    75  			if tstC.err == nil {
    76  				req.NoError(err)
    77  
    78  				var expect interface{}
    79  				if tstC.expected != nil {
    80  					expect, _, err = types.JSON.Convert(tstC.expected)
    81  					if err != nil {
    82  						panic("Bad test string. Can't convert string to JSONDocument: " + tstC.expected.(string))
    83  					}
    84  				}
    85  
    86  				req.Equal(expect, result)
    87  			} else {
    88  				req.Error(tstC.err, err)
    89  			}
    90  		})
    91  	}
    92  }