storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/s3select/sql/jsonpath_test.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2019 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package sql
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"os"
    24  	"path/filepath"
    25  	"reflect"
    26  	"testing"
    27  
    28  	"github.com/alecthomas/participle"
    29  	"github.com/bcicen/jstream"
    30  )
    31  
    32  func getJSONStructs(b []byte) ([]interface{}, error) {
    33  	dec := jstream.NewDecoder(bytes.NewBuffer(b), 0).ObjectAsKVS()
    34  	var result []interface{}
    35  	for parsedVal := range dec.Stream() {
    36  		result = append(result, parsedVal.Value)
    37  	}
    38  	if err := dec.Err(); err != nil {
    39  		return nil, err
    40  	}
    41  	return result, nil
    42  }
    43  
    44  func TestJsonpathEval(t *testing.T) {
    45  	f, err := os.Open(filepath.Join("jsondata", "books.json"))
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  
    50  	b, err := ioutil.ReadAll(f)
    51  	if err != nil {
    52  		t.Fatal(err)
    53  	}
    54  
    55  	p := participle.MustBuild(
    56  		&JSONPath{},
    57  		participle.Lexer(sqlLexer),
    58  		participle.CaseInsensitive("Keyword"),
    59  	)
    60  	cases := []struct {
    61  		str string
    62  		res []interface{}
    63  	}{
    64  		{"s.title", []interface{}{"Murder on the Orient Express", "The Robots of Dawn", "Pigs Have Wings"}},
    65  		{"s.authorInfo.yearRange", []interface{}{[]interface{}{1890.0, 1976.0}, []interface{}{1920.0, 1992.0}, []interface{}{1881.0, 1975.0}}},
    66  		{"s.authorInfo.name", []interface{}{"Agatha Christie", "Isaac Asimov", "P. G. Wodehouse"}},
    67  		{"s.authorInfo.yearRange[0]", []interface{}{1890.0, 1920.0, 1881.0}},
    68  		{"s.publicationHistory[0].pages", []interface{}{256.0, 336.0, nil}},
    69  	}
    70  	for i, tc := range cases {
    71  		jp := JSONPath{}
    72  		err := p.ParseString(tc.str, &jp)
    73  		// fmt.Println(jp)
    74  		if err != nil {
    75  			t.Fatalf("parse failed!: %d %v %s", i, err, tc)
    76  		}
    77  
    78  		// Read only the first json object from the file
    79  		recs, err := getJSONStructs(b)
    80  		if err != nil || len(recs) != 3 {
    81  			t.Fatalf("%v or length was not 3", err)
    82  		}
    83  
    84  		for j, rec := range recs {
    85  			// fmt.Println(rec)
    86  			r, _, err := jsonpathEval(jp.PathExpr, rec)
    87  			if err != nil {
    88  				t.Errorf("Error: %d %d %v", i, j, err)
    89  			}
    90  			if !reflect.DeepEqual(r, tc.res[j]) {
    91  				fmt.Printf("%#v (%v) != %v (%v)\n", r, reflect.TypeOf(r), tc.res[j], reflect.TypeOf(tc.res[j]))
    92  				t.Errorf("case: %d %d failed", i, j)
    93  			}
    94  		}
    95  	}
    96  }