fix(storage,sqlite): in operator sqlite translation

This commit is contained in:
wpetit 2023-02-17 16:59:05 +01:00
parent 673586c2f7
commit 85f50eb9d5
7 changed files with 102 additions and 13 deletions

View File

@ -0,0 +1,15 @@
package sql
const (
OpIn = "IN"
OpLesserThan = "<"
OpLesserThanEqual = "<="
OpEqual = "="
OpNotEqual = "!="
OpSuperiorThan = ">"
OpSuperiorThanEqual = ">="
OpAnd = "AND"
OpOr = "OR"
OpLike = "LIKE"
OpNot = "NOT"
)

View File

@ -71,6 +71,12 @@ func WithDefaultTransform() OptionFunc {
}
}
func WithTransform(transform TransformFunc) OptionFunc {
return func(opt *Option) {
opt.Transform = transform
}
}
func WithNoOpValueTransform() OptionFunc {
return WithValueTransform(func(value interface{}) interface{} {
return value

View File

@ -60,7 +60,7 @@ func transformAndOperator(op filter.Operator, option *Option) (string, []interfa
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenAnd, op.Token())
}
return aggregatorToSQL("AND", option, andOp.Children()...)
return aggregatorToSQL(OpAnd, option, andOp.Children()...)
}
func transformOrOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
@ -69,7 +69,7 @@ func transformOrOperator(op filter.Operator, option *Option) (string, []interfac
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenOr, op.Token())
}
return aggregatorToSQL("OR", option, orOp.Children()...)
return aggregatorToSQL(OpOr, option, orOp.Children()...)
}
func transformEqOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
@ -78,7 +78,7 @@ func transformEqOperator(op filter.Operator, option *Option) (string, []interfac
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenEq, op.Token())
}
return fieldsToSQL("=", false, eqOp.Fields(), option)
return fieldsToSQL(OpEqual, false, eqOp.Fields(), option)
}
func transformNeqOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
@ -87,7 +87,7 @@ func transformNeqOperator(op filter.Operator, option *Option) (string, []interfa
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenNeq, op.Token())
}
return fieldsToSQL("!=", false, eqOp.Fields(), option)
return fieldsToSQL(OpNotEqual, false, eqOp.Fields(), option)
}
func transformGtOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
@ -96,7 +96,7 @@ func transformGtOperator(op filter.Operator, option *Option) (string, []interfac
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenGt, op.Token())
}
return fieldsToSQL(">", false, gtOp.Fields(), option)
return fieldsToSQL(OpSuperiorThan, false, gtOp.Fields(), option)
}
func transformGteOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
@ -105,7 +105,7 @@ func transformGteOperator(op filter.Operator, option *Option) (string, []interfa
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenGte, op.Token())
}
return fieldsToSQL(">=", false, gteOp.Fields(), option)
return fieldsToSQL(OpSuperiorThanEqual, false, gteOp.Fields(), option)
}
func transformLtOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
@ -114,7 +114,7 @@ func transformLtOperator(op filter.Operator, option *Option) (string, []interfac
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenLt, op.Token())
}
return fieldsToSQL("<", false, ltOp.Fields(), option)
return fieldsToSQL(OpLesserThan, false, ltOp.Fields(), option)
}
func transformLteOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
@ -123,7 +123,7 @@ func transformLteOperator(op filter.Operator, option *Option) (string, []interfa
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenLte, op.Token())
}
return fieldsToSQL("<=", false, lteOp.Fields(), option)
return fieldsToSQL(OpLesserThanEqual, false, lteOp.Fields(), option)
}
func transformInOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
@ -132,7 +132,7 @@ func transformInOperator(op filter.Operator, option *Option) (string, []interfac
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenIn, op.Token())
}
return fieldsToSQL("IN", true, inOp.Fields(), option)
return fieldsToSQL(OpIn, true, inOp.Fields(), option)
}
func transformLikeOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
@ -141,7 +141,7 @@ func transformLikeOperator(op filter.Operator, option *Option) (string, []interf
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenLike, op.Token())
}
return fieldsToSQL("LIKE", false, likeOp.Fields(), option)
return fieldsToSQL(OpLike, false, likeOp.Fields(), option)
}
func transformNotOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
@ -150,10 +150,10 @@ func transformNotOperator(op filter.Operator, option *Option) (string, []interfa
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenNot, op.Token())
}
sql, args, err := aggregatorToSQL("AND", option, notOp.Children()...)
sql, args, err := aggregatorToSQL(OpAnd, option, notOp.Children()...)
if err != nil {
return "", nil, errors.WithStack(err)
}
return "NOT " + sql, args, nil
return OpNot + " " + sql, args, nil
}

View File

@ -32,7 +32,7 @@ func DefaultTransform(operator string, invert bool, key string, value interface{
return "", nil, errors.WithStack(err)
}
if _, err := sb.WriteString(key); err != nil {
if _, err := sb.WriteString(option.KeyTransform(key)); err != nil {
return "", nil, errors.WithStack(err)
}
} else {

View File

@ -102,6 +102,7 @@ func (s *DocumentStore) Query(ctx context.Context, collection string, filter *fi
criteria, args, err = filterSQL.ToSQL(
filter.Root(),
filterSQL.WithPreparedParameter("$", 2),
filterSQL.WithTransform(transformOperator),
filterSQL.WithKeyTransform(func(key string) string {
return fmt.Sprintf("json_extract(data, '$.%s')", key)
}),

View File

@ -0,0 +1,24 @@
package sqlite
import (
"fmt"
"forge.cadoles.com/arcad/edge/pkg/storage/filter/sql"
)
func transformOperator(operator string, invert bool, key string, value any, option *sql.Option) (string, any, error) {
switch operator {
case sql.OpIn:
return transformInOperator(key, value, option)
default:
return sql.DefaultTransform(operator, invert, key, value, option)
}
}
func transformInOperator(key string, value any, option *sql.Option) (string, any, error) {
return fmt.Sprintf(
"EXISTS (SELECT 1 FROM json_each(json_extract(data, \"$.%v\")) WHERE value = %v)",
key,
option.PreparedParameter(),
), option.ValueTransform(value), nil
}

View File

@ -60,6 +60,49 @@ var documentStoreQueryTestCases = []documentStoreQueryTestCase{
}
},
},
{
Name: "IN Operator",
Before: func(ctx context.Context, store storage.DocumentStore) error {
docs := []storage.Document{
{
"counter": 1,
"tags": []string{"foo", "bar"},
},
{
"counter": 1,
"tags": []string{"nope"},
},
}
for _, doc := range docs {
if _, err := store.Upsert(ctx, "in_operator", doc); err != nil {
return errors.WithStack(err)
}
}
return nil
},
Collection: "in_operator",
Filter: filter.New(
filter.NewAndOperator(
filter.NewEqOperator(map[string]any{
"counter": 1,
}),
filter.NewInOperator(map[string]any{
"tags": "foo",
}),
),
),
After: func(t *testing.T, results []storage.Document, err error) {
if err != nil {
t.Fatalf("%+v", errors.WithStack(err))
}
if e, g := 1, len(results); e != g {
t.Errorf("len(results): expected '%v', got '%v'", e, g)
}
},
},
}
func testDocumentStoreQuery(t *testing.T, store storage.DocumentStore) {