dynamo-browse/internal/dynamo-browse/models/queryexpr/between.go
Leon Mika f65c5778a9
issue-50: fixed package name (#52)
Changed package name from github.com/lmika/audax to github.com/lmika/dynamo-browse
2023-04-17 08:31:03 +10:00

156 lines
3.8 KiB
Go

package queryexpr
import (
"fmt"
"github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression"
"github.com/lmika/dynamo-browse/internal/dynamo-browse/models"
)
func (a *astBetweenOp) evalToIR(ctx *evalContext, info *models.TableInfo) (irAtom, error) {
leftIR, err := a.Ref.evalToIR(ctx, info)
if err != nil {
return nil, err
}
if a.From == nil {
return leftIR, nil
}
nameIR, isNameIR := leftIR.(nameIRAtom)
if !isNameIR {
return nil, OperandNotANameError(a.Ref.String())
}
fromIR, err := a.From.evalToIR(ctx, info)
if err != nil {
return nil, err
}
toIR, err := a.To.evalToIR(ctx, info)
if err != nil {
return nil, err
}
fromOprIR, isFromOprIR := fromIR.(valueIRAtom)
if !isFromOprIR {
return nil, OperandNotAnOperandError{}
}
toOprIR, isToOprIR := toIR.(valueIRAtom)
if !isToOprIR {
return nil, OperandNotAnOperandError{}
}
return irBetween{name: nameIR, from: fromOprIR, to: toOprIR}, nil
}
func (a *astBetweenOp) evalItem(ctx *evalContext, item models.Item) (exprValue, error) {
val, err := a.Ref.evalItem(ctx, item)
if a.From == nil {
return val, err
}
fromIR, err := a.From.evalItem(ctx, item)
if err != nil {
return nil, err
}
toIR, err := a.To.evalItem(ctx, item)
if err != nil {
return nil, err
}
switch v := val.(type) {
case stringableExprValue:
fromNumVal, isFromNumVal := fromIR.(stringableExprValue)
if !isFromNumVal {
return nil, ValuesNotComparable{Left: val.asAttributeValue(), Right: fromIR.asAttributeValue()}
}
toNumVal, isToNumVal := toIR.(stringableExprValue)
if !isToNumVal {
return nil, ValuesNotComparable{Left: val.asAttributeValue(), Right: toNumVal.asAttributeValue()}
}
return boolExprValue(v.asString() >= fromNumVal.asString() && v.asString() <= toNumVal.asString()), nil
case numberableExprValue:
fromNumVal, isFromNumVal := fromIR.(numberableExprValue)
if !isFromNumVal {
return nil, ValuesNotComparable{Left: val.asAttributeValue(), Right: fromIR.asAttributeValue()}
}
toNumVal, isToNumVal := toIR.(numberableExprValue)
if !isToNumVal {
return nil, ValuesNotComparable{Left: val.asAttributeValue(), Right: toNumVal.asAttributeValue()}
}
fromCmp := v.asBigFloat().Cmp(fromNumVal.asBigFloat())
toCmp := v.asBigFloat().Cmp(toNumVal.asBigFloat())
return boolExprValue(fromCmp >= 0 && toCmp <= 0), nil
}
return nil, InvalidTypeForBetweenError{TypeName: val.typeName()}
}
func (a *astBetweenOp) canModifyItem(ctx *evalContext, item models.Item) bool {
if a.From != nil {
return false
}
return a.Ref.canModifyItem(ctx, item)
}
func (a *astBetweenOp) setEvalItem(ctx *evalContext, item models.Item, value exprValue) error {
if a.From != nil {
return PathNotSettableError{}
}
return a.Ref.setEvalItem(ctx, item, value)
}
func (a *astBetweenOp) deleteAttribute(ctx *evalContext, item models.Item) error {
if a.From != nil {
return PathNotSettableError{}
}
return a.Ref.deleteAttribute(ctx, item)
}
func (a *astBetweenOp) String() string {
name := a.Ref.String()
if a.From != nil {
return fmt.Sprintf("%v between %v and %v", name, a.From.String(), a.To.String())
}
return name
}
type irBetween struct {
name nameIRAtom
from valueIRAtom
to valueIRAtom
}
func (i irBetween) calcQueryForScan(info *models.TableInfo) (expression.ConditionBuilder, error) {
nb := i.name.calcName(info)
fb := i.from.calcOperand(info)
tb := i.to.calcOperand(info)
return nb.Between(fb, tb), nil
}
func (i irBetween) canBeExecutedAsQuery(qci *queryCalcInfo) bool {
keyName := i.name.keyName()
if keyName == "" {
return false
}
if keyName == qci.keysUnderTest.SortKey {
return qci.addKey(keyName)
}
return false
}
func (i irBetween) calcQueryForQuery() (expression.KeyConditionBuilder, error) {
nb := i.name.keyName()
fb := i.from.exprValue()
tb := i.to.exprValue()
return expression.Key(nb).Between(buildExpressionFromValue(fb), buildExpressionFromValue(tb)), nil
}