mirror of
https://github.com/chaisql/chai.git
synced 2025-10-14 19:57:25 +08:00

Previously, expressions and params were evaluated during the planning phase. This change builds the query plan without evaluating params and expressions which are then evaluated only during the execution phase.
170 lines
3.5 KiB
Go
170 lines
3.5 KiB
Go
package expr
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/genjidb/genji/document"
|
|
"github.com/genjidb/genji/internal/stringutil"
|
|
)
|
|
|
|
// A LiteralValue represents a litteral value of any type defined by the value package.
|
|
type LiteralValue document.Value
|
|
|
|
// IsEqual compares this expression with the other expression and returns
|
|
// true if they are equal.
|
|
func (v LiteralValue) IsEqual(other Expr) bool {
|
|
o, ok := other.(LiteralValue)
|
|
if !ok {
|
|
return false
|
|
}
|
|
ok, err := document.Value(v).IsEqual(document.Value(o))
|
|
return ok && err == nil
|
|
}
|
|
|
|
// String implements the stringutil.Stringer interface.
|
|
func (v LiteralValue) String() string {
|
|
return document.Value(v).String()
|
|
}
|
|
|
|
// Eval returns l. It implements the Expr interface.
|
|
func (v LiteralValue) Eval(*Environment) (document.Value, error) {
|
|
return document.Value(v), nil
|
|
}
|
|
|
|
// LiteralExprList is a list of expressions.
|
|
type LiteralExprList []Expr
|
|
|
|
// IsEqual compares this expression with the other expression and returns
|
|
// true if they are equal.
|
|
func (l LiteralExprList) IsEqual(other Expr) bool {
|
|
o, ok := other.(LiteralExprList)
|
|
if !ok {
|
|
return false
|
|
}
|
|
if len(l) != len(o) {
|
|
return false
|
|
}
|
|
|
|
for i := range l {
|
|
if !Equal(l[i], o[i]) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// String implements the stringutil.Stringer interface.
|
|
func (l LiteralExprList) String() string {
|
|
var b strings.Builder
|
|
|
|
b.WriteRune('[')
|
|
for i, e := range l {
|
|
if i > 0 {
|
|
b.WriteString(", ")
|
|
}
|
|
b.WriteString(stringutil.Sprintf("%v", e))
|
|
}
|
|
b.WriteRune(']')
|
|
|
|
return b.String()
|
|
}
|
|
|
|
// Eval evaluates all the expressions and returns a litteralValueList. It implements the Expr interface.
|
|
func (l LiteralExprList) Eval(env *Environment) (document.Value, error) {
|
|
var err error
|
|
values := make([]document.Value, len(l))
|
|
for i, e := range l {
|
|
values[i], err = e.Eval(env)
|
|
if err != nil {
|
|
return nullLitteral, err
|
|
}
|
|
}
|
|
|
|
return document.NewArrayValue(document.NewValueBuffer(values...)), nil
|
|
}
|
|
|
|
// KVPair associates an identifier with an expression.
|
|
type KVPair struct {
|
|
K string
|
|
V Expr
|
|
}
|
|
|
|
// String implements the stringutil.Stringer interface.
|
|
func (p KVPair) String() string {
|
|
if stringutil.NeedsQuotes(p.K) {
|
|
return stringutil.Sprintf("%q: %v", p.K, p.V)
|
|
}
|
|
return stringutil.Sprintf("%s: %v", p.K, p.V)
|
|
}
|
|
|
|
// KVPairs is a list of KVPair.
|
|
type KVPairs struct {
|
|
Pairs []KVPair
|
|
SelfReferenced bool
|
|
}
|
|
|
|
// IsEqual compares this expression with the other expression and returns
|
|
// true if they are equal.
|
|
func (kvp *KVPairs) IsEqual(other Expr) bool {
|
|
o, ok := other.(*KVPairs)
|
|
if !ok {
|
|
return false
|
|
}
|
|
if kvp.SelfReferenced != o.SelfReferenced {
|
|
return false
|
|
}
|
|
|
|
if len(kvp.Pairs) != len(o.Pairs) {
|
|
return false
|
|
}
|
|
|
|
for i := range kvp.Pairs {
|
|
if kvp.Pairs[i].K != o.Pairs[i].K {
|
|
return false
|
|
}
|
|
if !Equal(kvp.Pairs[i].V, o.Pairs[i].V) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// Eval turns a list of KVPairs into a document.
|
|
func (kvp *KVPairs) Eval(env *Environment) (document.Value, error) {
|
|
var fb document.FieldBuffer
|
|
if kvp.SelfReferenced {
|
|
if _, ok := env.GetDocument(); !ok {
|
|
env.SetDocument(&fb)
|
|
}
|
|
}
|
|
|
|
for _, kv := range kvp.Pairs {
|
|
v, err := kv.V.Eval(env)
|
|
if err != nil {
|
|
return document.Value{}, err
|
|
}
|
|
|
|
fb.Add(kv.K, v)
|
|
}
|
|
|
|
return document.NewDocumentValue(&fb), nil
|
|
}
|
|
|
|
// String implements the stringutil.Stringer interface.
|
|
func (kvp *KVPairs) String() string {
|
|
var b strings.Builder
|
|
|
|
b.WriteRune('{')
|
|
for i, p := range kvp.Pairs {
|
|
if i > 0 {
|
|
b.WriteString(", ")
|
|
}
|
|
b.WriteString(stringutil.Sprintf("%s", p))
|
|
}
|
|
b.WriteRune('}')
|
|
|
|
return b.String()
|
|
}
|