Fixed query expression so that 'true' and 'false' are now boolean literals

Also describe queries in the log file
This commit is contained in:
Leon Mika 2023-01-26 10:34:43 +11:00
parent 700a1a2253
commit aaf3c17934
5 changed files with 70 additions and 5 deletions

View file

@ -1,8 +1,48 @@
package models package models
import "github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression" import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression"
"github.com/lmika/audax/internal/dynamo-browse/models/itemrender"
)
type QueryExecutionPlan struct { type QueryExecutionPlan struct {
CanQuery bool CanQuery bool
Expression expression.Expression Expression expression.Expression
} }
func (qep QueryExecutionPlan) Describe(dp DescribingPrinter) {
if qep.CanQuery {
dp.Println(" execute as: query")
} else {
dp.Println(" execute as: scan")
}
if keyCond := aws.ToString(qep.Expression.KeyCondition()); keyCond != "" {
dp.Printf(" key condition: %v", keyCond)
}
if cond := aws.ToString(qep.Expression.Condition()); cond != "" {
dp.Printf(" condition: %v", cond)
}
if filter := aws.ToString(qep.Expression.Filter()); filter != "" {
dp.Printf(" filter: %v", filter)
}
if names := qep.Expression.Names(); len(names) > 0 {
dp.Println(" names:")
for k, v := range names {
dp.Printf(" %v = %v", k, v)
}
}
if values := qep.Expression.Values(); len(values) > 0 {
dp.Println(" values:")
for k, v := range values {
r := itemrender.ToRenderer(v)
dp.Printf(" %v (%v) = %v", k, r.TypeName(), r.StringValue())
}
}
}
type DescribingPrinter interface {
Println(v ...any)
Printf(format string, v ...any)
}

View file

@ -81,11 +81,15 @@ type astPlaceholder struct {
} }
type astLiteralValue struct { type astLiteralValue struct {
StringVal *string `parser:"@String"` StringVal *string `parser:"@String"`
IntVal *int64 `parser:"| @Int"` IntVal *int64 `parser:"| @Int"`
TrueBoolValue bool `parser:"| @KwdTrue"`
FalseBoolValue bool `parser:"| @KwdFalse"`
} }
var scanner = lexer.MustSimple([]lexer.SimpleRule{ var scanner = lexer.MustSimple([]lexer.SimpleRule{
{Name: "KwdTrue", Pattern: `true`},
{Name: "KwdFalse", Pattern: `false`},
{Name: "Eq", Pattern: `=|[\\^]=|[!]=`}, {Name: "Eq", Pattern: `=|[\\^]=|[!]=`},
{Name: "Cmp", Pattern: `<[=]?|>[=]?`}, {Name: "Cmp", Pattern: `<[=]?|>[=]?`},
{Name: "String", Pattern: `"(\\"|[^"])*"`}, {Name: "String", Pattern: `"(\\"|[^"])*"`},

View file

@ -158,6 +158,14 @@ func TestModExpr_Query(t *testing.T) {
scanCase("greater or equal to value", `num >= 100`, `#0 >= :0`, scanCase("greater or equal to value", `num >= 100`, `#0 >= :0`,
exprNameIsNumber(0, 0, "num", "100"), exprNameIsNumber(0, 0, "num", "100"),
), ),
scanCase("is true", `bool = true`, `#0 = :0`,
exprName(0, "bool"),
exprValueIsBool(0, true),
),
scanCase("is false", `bool = false`, `#0 = :0`,
exprName(0, "bool"),
exprValueIsBool(0, false),
),
scanCase("with disjunctions", scanCase("with disjunctions",
`pk="prefix" or sk="another"`, `pk="prefix" or sk="another"`,
`(#0 = :0) OR (#1 = :1)`, `(#0 = :0) OR (#1 = :1)`,
@ -846,6 +854,12 @@ func exprValueIsNumber(valIdx int, expected string) func(ss *scanScenario) {
} }
} }
func exprValueIsBool(valIdx int, expected bool) func(ss *scanScenario) {
return func(ss *scanScenario) {
ss.expectedValues[fmt.Sprintf(":%d", valIdx)] = &types.AttributeValueMemberBOOL{Value: expected}
}
}
func exprNameIsString(idx, valIdx int, name string, expected string) func(ss *scanScenario) { func exprNameIsString(idx, valIdx int, name string, expected string) func(ss *scanScenario) {
return func(ss *scanScenario) { return func(ss *scanScenario) {
ss.expectedNames[fmt.Sprintf("#%d", idx)] = name ss.expectedNames[fmt.Sprintf("#%d", idx)] = name

View file

@ -51,6 +51,10 @@ func (a *astLiteralValue) goValue() (any, error) {
return s, nil return s, nil
case a.IntVal != nil: case a.IntVal != nil:
return *a.IntVal, nil return *a.IntVal, nil
case a.TrueBoolValue:
return true, nil
case a.FalseBoolValue:
return false, nil
} }
return nil, errors.New("unrecognised type") return nil, errors.New("unrecognised type")
} }

View file

@ -59,15 +59,18 @@ func (s *Service) doScan(
runAsQuery = plan.CanQuery runAsQuery = plan.CanQuery
filterExpr = &plan.Expression filterExpr = &plan.Expression
log.Printf("Running query over '%v'", tableInfo.Name)
plan.Describe(log.Default())
} else {
log.Printf("Performing scan over '%v'", tableInfo.Name)
} }
var results []models.Item var results []models.Item
var lastEvalKey map[string]types.AttributeValue var lastEvalKey map[string]types.AttributeValue
if runAsQuery { if runAsQuery {
log.Printf("executing query")
results, lastEvalKey, err = s.provider.QueryItems(ctx, tableInfo.Name, filterExpr, exclusiveStartKey, limit) results, lastEvalKey, err = s.provider.QueryItems(ctx, tableInfo.Name, filterExpr, exclusiveStartKey, limit)
} else { } else {
log.Printf("executing scan")
results, lastEvalKey, err = s.provider.ScanItems(ctx, tableInfo.Name, filterExpr, exclusiveStartKey, limit) results, lastEvalKey, err = s.provider.ScanItems(ctx, tableInfo.Name, filterExpr, exclusiveStartKey, limit)
} }