Add JSON Path expression evaluation support (#7315)

- Includes support for FROM clause JSON path
This commit is contained in:
Aditya Manthramurthy
2019-03-09 08:13:37 -08:00
committed by Harshavardhana
parent b296b3cf8b
commit e463386921
15 changed files with 488 additions and 59 deletions

View File

@@ -17,7 +17,6 @@
package json
import (
"encoding/json"
"io"
"github.com/minio/minio/pkg/s3select/sql"
@@ -43,24 +42,22 @@ func (r *Reader) Read() (sql.Record, error) {
return nil, io.EOF
}
var data []byte
var err error
var kvs jstream.KVS
if v.ValueType == jstream.Object {
data, err = json.Marshal(v.Value)
// This is a JSON object type (that preserves key
// order)
kvs = v.Value.(jstream.KVS)
} else {
// To be AWS S3 compatible Select for JSON needs to
// output non-object JSON as single column value
// i.e. a map with `_1` as key and value as the
// non-object.
data, err = json.Marshal(jstream.KVS{jstream.KV{Key: "_1", Value: v.Value}})
}
if err != nil {
return nil, errJSONParsingError(err)
kvs = jstream.KVS{jstream.KV{Key: "_1", Value: v.Value}}
}
return &Record{
Data: data,
KVS: kvs,
SelectFormat: sql.SelectFmtJSON,
}, nil
}

View File

@@ -26,7 +26,6 @@ import (
"github.com/bcicen/jstream"
"github.com/minio/minio/pkg/s3select/sql"
"github.com/tidwall/gjson"
)
// RawJSON is a byte-slice that contains valid JSON
@@ -40,34 +39,20 @@ func (b RawJSON) MarshalJSON() ([]byte, error) {
// Record - is JSON record.
type Record struct {
// Used in Get()
Data []byte
// Used in Set(), Marshal*()
kvs jstream.KVS
KVS jstream.KVS
SelectFormat sql.SelectObjectFormat
}
// Get - gets the value for a column name.
func (r *Record) Get(name string) (*sql.Value, error) {
result := gjson.GetBytes(r.Data, name)
switch result.Type {
case gjson.Null:
return sql.FromNull(), nil
case gjson.False:
return sql.FromBool(false), nil
case gjson.Number:
return sql.FromFloat(result.Float()), nil
case gjson.String:
return sql.FromString(result.String()), nil
case gjson.True:
return sql.FromBool(true), nil
}
return nil, fmt.Errorf("unsupported gjson value %v; %v", result, result.Type)
// Get is implemented directly in the sql package.
return nil, errors.New("not implemented here")
}
// Set - sets the value for a column name.
func (r *Record) Set(name string, value *sql.Value) (err error) {
func (r *Record) Set(name string, value *sql.Value) error {
var v interface{}
if b, ok := value.ToBool(); ok {
v = b
@@ -88,14 +73,14 @@ func (r *Record) Set(name string, value *sql.Value) (err error) {
}
name = strings.Replace(name, "*", "__ALL__", -1)
r.kvs = append(r.kvs, jstream.KV{Key: name, Value: v})
return err
r.KVS = append(r.KVS, jstream.KV{Key: name, Value: v})
return nil
}
// MarshalCSV - encodes to CSV data.
func (r *Record) MarshalCSV(fieldDelimiter rune) ([]byte, error) {
var csvRecord []string
for _, kv := range r.kvs {
for _, kv := range r.KVS {
var columnValue string
switch val := kv.Value.(type) {
case bool, float64, int64, string:
@@ -125,14 +110,26 @@ func (r *Record) MarshalCSV(fieldDelimiter rune) ([]byte, error) {
return data[:len(data)-1], nil
}
// Raw - returns the underlying representation.
func (r *Record) Raw() (sql.SelectObjectFormat, interface{}) {
return r.SelectFormat, r.KVS
}
// MarshalJSON - encodes to JSON data.
func (r *Record) MarshalJSON() ([]byte, error) {
return json.Marshal(r.kvs)
return json.Marshal(r.KVS)
}
// Replace the underlying buffer of json data.
func (r *Record) Replace(k jstream.KVS) error {
r.KVS = k
return nil
}
// NewRecord - creates new empty JSON record.
func NewRecord() *Record {
func NewRecord(f sql.SelectObjectFormat) *Record {
return &Record{
Data: []byte("{}"),
KVS: jstream.KVS{},
SelectFormat: f,
}
}