dynamo-browse/internal/dynamo-browse/models/queryexpr/disj.go
Leon Mika 4b4d515ade
Added a few changes to query expressions (#51)
- Added the between operator to query expressions.
- Added the using query expression suffix to specify which index to query (or force a scan). This is required if query planning has found multiple indices that can potentially be used.
- Rewrote the types of the query expressions to allow for functions to be defined once, and be useful in queries that result in DynamoDB queries, and evaluation.
- Added some test functions around time and summing numbers.
- Fixed a bug in the del-attr which was not honouring marked rows in a similar way to set-attr: it was only deleting attributes from the first row.
- Added the -to type flag to set-attr which will set the attribute to the value of a query expression.
2023-04-14 15:35:43 +10:00

107 lines
2.4 KiB
Go

package queryexpr
import (
"github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression"
"github.com/lmika/audax/internal/dynamo-browse/models"
"strings"
)
func (a *astDisjunction) evalToIR(ctx *evalContext, tableInfo *models.TableInfo) (irAtom, error) {
if len(a.Operands) == 1 {
return a.Operands[0].evalToIR(ctx, tableInfo)
}
conj := make([]irAtom, len(a.Operands))
for i, op := range a.Operands {
var err error
conj[i], err = op.evalToIR(ctx, tableInfo)
if err != nil {
return nil, err
}
}
return &irDisjunction{conj: conj}, nil
}
func (a *astDisjunction) evalItem(ctx *evalContext, item models.Item) (exprValue, error) {
val, err := a.Operands[0].evalItem(ctx, item)
if err != nil {
return nil, err
}
if len(a.Operands) == 1 {
return val, nil
}
for _, opr := range a.Operands[1:] {
if isAttributeTrue(val) {
return boolExprValue(true), nil
}
val, err = opr.evalItem(ctx, item)
if err != nil {
return nil, err
}
}
return boolExprValue(isAttributeTrue(val)), nil
}
func (a *astDisjunction) canModifyItem(ctx *evalContext, item models.Item) bool {
if len(a.Operands) == 1 {
return a.Operands[0].canModifyItem(ctx, item)
}
return false
}
func (a *astDisjunction) setEvalItem(ctx *evalContext, item models.Item, value exprValue) error {
if len(a.Operands) == 1 {
return a.Operands[0].setEvalItem(ctx, item, value)
}
return PathNotSettableError{}
}
func (a *astDisjunction) deleteAttribute(ctx *evalContext, item models.Item) error {
if len(a.Operands) == 1 {
return a.Operands[0].deleteAttribute(ctx, item)
}
return PathNotSettableError{}
}
func (d *astDisjunction) String() string {
sb := new(strings.Builder)
for i, operand := range d.Operands {
if i > 0 {
sb.WriteString(" or ")
}
sb.WriteString(operand.String())
}
return sb.String()
}
type irDisjunction struct {
conj []irAtom
}
func (d *irDisjunction) calcQueryForScan(info *models.TableInfo) (expression.ConditionBuilder, error) {
if len(d.conj) == 1 {
return d.conj[0].calcQueryForScan(info)
}
// TODO: check if can be query
conds := make([]expression.ConditionBuilder, len(d.conj))
for i, operand := range d.conj {
cond, err := operand.calcQueryForScan(info)
if err != nil {
return expression.ConditionBuilder{}, err
}
conds[i] = cond
}
// Build disjunction
disjExpr := expression.Or(conds[0], conds[1], conds[2:]...)
return disjExpr, nil
}