| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938 | /* * EliasDB * * Copyright 2016 Matthias Ladkau. All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */package interpreterimport (	"fmt"	"regexp"	"strconv"	"strings"	"devt.de/krotik/eliasdb/eql/parser"	"devt.de/krotik/eliasdb/graph/data")/*CondRuntime is a component of a condition which can be evaluatedwith a node and an edge.*/type CondRuntime interface {	/*	   CondEval evaluates this condition runtime element.	*/	CondEval(node data.Node, edge data.Edge) (interface{}, error)}/*Abstract runtime for condition components*/type whereItemRuntime struct {	rtp     *eqlRuntimeProvider	astNode *parser.ASTNode}/*Validate this node and all its child nodes.*/func (rt *whereItemRuntime) Validate() error {	return rt.rtp.newRuntimeError(ErrInvalidConstruct, rt.astNode.Name, rt.astNode)}/*Eval evaluate this condition component.*/func (rt *whereItemRuntime) Eval() (interface{}, error) {	return nil, rt.rtp.newRuntimeError(ErrInvalidConstruct, rt.astNode.Name, rt.astNode)}/*valOp executes an operation on two abstract values.*/func (rt *whereItemRuntime) valOp(node data.Node, edge data.Edge, op func(interface{}, interface{}) interface{}) (interface{}, error) {	res1, err := rt.astNode.Children[0].Runtime.(CondRuntime).CondEval(node, edge)	if err != nil {		return nil, err	}	res2, err := rt.astNode.Children[1].Runtime.(CondRuntime).CondEval(node, edge)	if err != nil {		return nil, err	}	return op(res1, res2), nil}/*stringOp executes an operation on two strings.*/func (rt *whereItemRuntime) stringOp(node data.Node, edge data.Edge, op func(string, string) interface{}) (interface{}, error) {	res1, err := rt.astNode.Children[0].Runtime.(CondRuntime).CondEval(node, edge)	if err != nil {		return nil, err	}	res2, err := rt.astNode.Children[1].Runtime.(CondRuntime).CondEval(node, edge)	if err != nil {		return nil, err	}	return op(fmt.Sprint(res1), fmt.Sprint(res2)), nil}/*regexOp executes an operation on a string and a regex.*/func (rt *whereItemRuntime) regexOp(node data.Node, edge data.Edge, op func(string, *regexp.Regexp) interface{}) (interface{}, error) {	res1, err := rt.astNode.Children[0].Runtime.(CondRuntime).CondEval(node, edge)	if err != nil {		return nil, err	}	res2, err := rt.astNode.Children[1].Runtime.(CondRuntime).CondEval(node, edge)	if err != nil {		return nil, err	}	// Try to compile the regex	res2String := fmt.Sprint(res2)	regexp, err := regexp.Compile(res2String)	if err != nil {		return nil, rt.rtp.newRuntimeError(ErrNotARegex,			fmt.Sprintf("%#v - %s", res2String, err.Error()), rt.astNode.Children[1])	}	return op(fmt.Sprint(res1), regexp), nil}/*numOp executes an operation on two number values.*/func (rt *whereItemRuntime) numOp(node data.Node, edge data.Edge, op func(float64, float64) interface{}) (interface{}, error) {	res1, err := rt.astNode.Children[0].Runtime.(CondRuntime).CondEval(node, edge)	if err != nil {		return nil, err	}	res2, err := rt.astNode.Children[1].Runtime.(CondRuntime).CondEval(node, edge)	if err != nil {		return nil, err	}	errDetail := func(tokenVal string, opVal string) string {		if tokenVal == opVal {			return opVal		}		return tokenVal + "=" + opVal	}	// Parse the values to numbers	res1Str := fmt.Sprint(res1)	res1Num, err := strconv.ParseFloat(res1Str, 64)	if err != nil {		return nil, rt.rtp.newRuntimeError(ErrNotANumber, errDetail(rt.astNode.Children[0].Token.Val, res1Str), rt.astNode.Children[0])	}	res2Str := fmt.Sprint(res2)	res2Num, err := strconv.ParseFloat(res2Str, 64)	if err != nil {		return nil, rt.rtp.newRuntimeError(ErrNotANumber, errDetail(rt.astNode.Children[1].Token.Val, res2Str), rt.astNode.Children[1])	}	return op(res1Num, res2Num), nil}/*listOp executes a list operation on a single value and a list.*/func (rt *whereItemRuntime) listOp(node data.Node, edge data.Edge, op func(interface{}, []interface{}) interface{}) (interface{}, error) {	res1, err := rt.astNode.Children[0].Runtime.(CondRuntime).CondEval(node, edge)	if err != nil {		return nil, err	}	res2, err := rt.astNode.Children[1].Runtime.(CondRuntime).CondEval(node, edge)	if err != nil {		return nil, err	}	errDetail := func(tokenVal string, opVal string) string {		if tokenVal == opVal {			return opVal		}		return tokenVal + "=" + opVal	}	// Parse right value to a list	res2List, ok := res2.([]interface{})	if !ok {		return nil, rt.rtp.newRuntimeError(ErrNotAList, errDetail(rt.astNode.Children[1].Token.Val, fmt.Sprint(res2)), rt.astNode.Children[1])	}	return op(res1, res2List), nil}/*boolOp executes an operation on two boolean values. Can optionally try ashort circuit operation.*/func (rt *whereItemRuntime) boolOp(node data.Node, edge data.Edge, op func(bool, bool) interface{},	scop func(bool) interface{}) (interface{}, error) {	res1, err := rt.astNode.Children[0].Runtime.(CondRuntime).CondEval(node, edge)	if err != nil {		return nil, err	}	if len(rt.astNode.Children) == 1 {		// Special case for "not" operation		return op(toBool(res1), false), nil	}	// Try short circuit	res1bool := toBool(res1)	if scop != nil {		if ret := scop(res1bool); ret != nil {			return ret, nil		}	}	res2, err := rt.astNode.Children[1].Runtime.(CondRuntime).CondEval(node, edge)	if err != nil {		return nil, err	}	return op(res1bool, toBool(res2)), nil}/*toBool is a helper function to turn any value into a boolean.*/func toBool(res interface{}) bool {	switch res := res.(type) {	default:		return res != nil	case bool:		return res	case float64:		return res > 0	case string:		// Try to convert the string into a number		num, err := strconv.ParseFloat(res, 64)		if err == nil {			return num > 0		}		return res != ""	}}func equals(res1 interface{}, res2 interface{}) bool {	// Try to convert the string into a number	num1, err := strconv.ParseFloat(fmt.Sprint(res1), 64)	if err == nil {		num2, err := strconv.ParseFloat(fmt.Sprint(res2), 64)		if err == nil {			return num1 == num2		}	}	return fmt.Sprintf("%v", res1) == fmt.Sprintf("%v", res2)}// Where runtime// =============/*Runtime for where*/type whereRuntime struct {	rtp     *eqlRuntimeProvider	astNode *parser.ASTNode	specIndex int // Index of this traversal in the traversals array}/*whereRuntimeInst returns a new runtime component instance.*/func whereRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &whereRuntime{rtp, node, 0}}/*Validate this node and all its child nodes.*/func (rt *whereRuntime) Validate() error {	var visitChildren func(astNode *parser.ASTNode) error	visitChildren = func(astNode *parser.ASTNode) error {		// Determine which values should be interpreted as node attributes		if astNode.Name == parser.NodeVALUE {			val := astNode.Token.Val			lcval := strings.ToLower(val)			valRuntime, ok := astNode.Runtime.(*valueRuntime)			if !ok {				return astNode.Runtime.Validate()			}			if strings.HasPrefix(lcval, "eattr:") {				valRuntime.condVal = val[6:]				valRuntime.isNodeAttrValue = false				valRuntime.isEdgeAttrValue = true			} else if strings.HasPrefix(lcval, "attr:") {				valRuntime.condVal = val[5:]				valRuntime.isNodeAttrValue = true				valRuntime.isEdgeAttrValue = false			} else if strings.HasPrefix(lcval, "val:") {				valRuntime.condVal = val[4:]				valRuntime.isNodeAttrValue = false				valRuntime.isEdgeAttrValue = false			} else {				valRuntime.condVal = val				valRuntime.isNodeAttrValue = rt.rtp.ni.IsValidAttr(val)				valRuntime.isEdgeAttrValue = false				// Check if we have a nested value				if strings.Contains(val, ".") {					nestedValuePath := strings.Split(val, ".")					if rt.rtp.ni.IsValidAttr(nestedValuePath[0]) {						valRuntime.condVal = nestedValuePath[0]						valRuntime.nestedValuePath = nestedValuePath						valRuntime.isNodeAttrValue = true					}				}			}			// Make sure attributes are queried			if valRuntime.isNodeAttrValue {				rt.rtp.attrsNodes[rt.specIndex][valRuntime.condVal] = ""			} else if valRuntime.isEdgeAttrValue {				rt.rtp.attrsEdges[rt.specIndex][valRuntime.condVal] = ""			}		}		for _, child := range astNode.Children {			if err := visitChildren(child); err != nil {				return err			}		}		return nil	}	return visitChildren(rt.astNode)}/*Eval evaluates the where clause a*/func (rt *whereRuntime) Eval() (interface{}, error) {	return nil, rt.rtp.newRuntimeError(ErrInvalidConstruct, rt.astNode.Name, rt.astNode)}/*CondEval evaluates this condition runtime element.*/func (rt *whereRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	res, err := rt.astNode.Children[0].Runtime.(CondRuntime).CondEval(node, edge)	return toBool(res), err}// Where related runtimes// ======================/*Equal runtime*/type equalRuntime struct {	*whereItemRuntime}/*equalRuntimeInst returns a new runtime component instance.*/func equalRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &equalRuntime{&whereItemRuntime{rtp, node}}}/*Evaluate this condition runtime element.*/func (rt *equalRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.valOp(node, edge, func(res1 interface{}, res2 interface{}) interface{} { return equals(res1, res2) })}/*CondEval evaluates this condition runtime element.*/type notEqualRuntime struct {	*whereItemRuntime}/*notEqualRuntimeInst returns a new runtime component instance.*/func notEqualRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return ¬EqualRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *notEqualRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.valOp(node, edge, func(res1 interface{}, res2 interface{}) interface{} { return !equals(res1, res2) })}/*Less than runtime*/type lessThanRuntime struct {	*whereItemRuntime}/*lessThanRuntimeInst returns a new runtime component instance.*/func lessThanRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &lessThanRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *lessThanRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	ret, err := rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 < res2 })	if err != nil {		// Do a simple string ordering		ret, err = rt.valOp(node, edge, func(res1 interface{}, res2 interface{}) interface{} { return fmt.Sprint(res1) < fmt.Sprint(res2) })	}	return ret, err}/*Less than equals runtime*/type lessThanEqualsRuntime struct {	*whereItemRuntime}/*lessThanEqualsRuntimeInst returns a new runtime component instance.*/func lessThanEqualsRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &lessThanEqualsRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *lessThanEqualsRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	ret, err := rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 <= res2 })	if err != nil {		// Do a simple string ordering		ret, err = rt.valOp(node, edge, func(res1 interface{}, res2 interface{}) interface{} { return fmt.Sprint(res1) <= fmt.Sprint(res2) })	}	return ret, err}/*Greater than runtime*/type greaterThanRuntime struct {	*whereItemRuntime}/*greaterThanRuntimeInst returns a new runtime component instance.*/func greaterThanRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &greaterThanRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *greaterThanRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	ret, err := rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 > res2 })	if err != nil {		// Do a simple string ordering		ret, err = rt.valOp(node, edge, func(res1 interface{}, res2 interface{}) interface{} { return fmt.Sprint(res1) > fmt.Sprint(res2) })	}	return ret, err}/*Greater than equals runtime*/type greaterThanEqualsRuntime struct {	*whereItemRuntime}/*greaterThanEqualsRuntimeInst returns a new runtime component instance.*/func greaterThanEqualsRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &greaterThanEqualsRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *greaterThanEqualsRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	ret, err := rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 >= res2 })	if err != nil {		// Do a simple string ordering		ret, err = rt.valOp(node, edge, func(res1 interface{}, res2 interface{}) interface{} { return fmt.Sprint(res1) >= fmt.Sprint(res2) })	}	return ret, err}/*And runtime*/type andRuntime struct {	*whereItemRuntime}/*andRuntimeInst returns a new runtime component instance.*/func andRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &andRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *andRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.boolOp(node, edge, func(res1 bool, res2 bool) interface{} { return res1 && res2 },		func(res1 bool) interface{} {			if !res1 {				return false			}			return nil		})}/*Or runtime*/type orRuntime struct {	*whereItemRuntime}/*orRuntimeInst returns a new runtime component instance.*/func orRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &orRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *orRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.boolOp(node, edge, func(res1 bool, res2 bool) interface{} { return res1 || res2 },		func(res1 bool) interface{} {			if res1 {				return true			}			return nil		})}/*Not runtime*/type notRuntime struct {	*whereItemRuntime}/*notRuntimeInst returns a new runtime component instance.*/func notRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return ¬Runtime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *notRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.boolOp(node, edge, func(res1 bool, res2 bool) interface{} { return !res1 }, nil)}/*Plus runtime*/type plusRuntime struct {	*whereItemRuntime}/*plusRuntimeInst returns a new runtime component instance.*/func plusRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &plusRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *plusRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 + res2 })}/*Minus runtime*/type minusRuntime struct {	*whereItemRuntime}/*minusRuntimeInst returns a new runtime component instance.*/func minusRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &minusRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *minusRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 - res2 })}/*Times runtime*/type timesRuntime struct {	*whereItemRuntime}/*timesRuntimeInst returns a new runtime component instance.*/func timesRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return ×Runtime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *timesRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 * res2 })}/*Div runtime*/type divRuntime struct {	*whereItemRuntime}/*divRuntimeInst returns a new runtime component instance.*/func divRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &divRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *divRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return res1 / res2 })}/*ModInt runtime*/type modIntRuntime struct {	*whereItemRuntime}/*modIntRuntimeInst returns a new runtime component instance.*/func modIntRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &modIntRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *modIntRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return int(int(res1) % int(res2)) })}/*DivInt runtime*/type divIntRuntime struct {	*whereItemRuntime}/*divIntRuntimeInst returns a new runtime component instance.*/func divIntRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &divIntRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *divIntRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.numOp(node, edge, func(res1 float64, res2 float64) interface{} { return int(int(res1) / int(res2)) })}/*In runtime*/type inRuntime struct {	*whereItemRuntime}/*inRuntimeInst returns a new runtime component instance.*/func inRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &inRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *inRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.listOp(node, edge, func(res1 interface{}, res2 []interface{}) interface{} {		for _, item := range res2 {			if equals(res1, item) {				return true			}		}		return false	})}/*Not in runtime*/type notInRuntime struct {	*whereItemRuntime}/*notInRuntimeInst returns a new runtime component instance.*/func notInRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return ¬InRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *notInRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.listOp(node, edge, func(res1 interface{}, res2 []interface{}) interface{} {		for _, item := range res2 {			if equals(res1, item) {				return false			}		}		return true	})}/*Like runtime*/type likeRuntime struct {	compiledRegex *regexp.Regexp // Quick lookup of the compiled regex if it is a constant	*whereItemRuntime}/*likeRuntimeInst returns a new runtime component instance.*/func likeRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &likeRuntime{nil, &whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *likeRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	// Check for constant regexp	if valRT, ok := rt.astNode.Children[1].Runtime.(*valueRuntime); ok {		if !valRT.isNodeAttrValue && !valRT.isEdgeAttrValue {			// Given regex is a constant and only needs to be compiled once			val, _ := valRT.CondEval(node, edge)			valStr := fmt.Sprint(val)			regexp, err := regexp.Compile(valStr)			if err != nil {				return nil, rt.rtp.newRuntimeError(ErrNotARegex,					fmt.Sprintf("%#v - %s", valStr, err.Error()), rt.astNode.Children[1])			}			rt.compiledRegex = regexp		}	}	if rt.compiledRegex == nil {		return rt.regexOp(node, edge, func(res1 string, res2 *regexp.Regexp) interface{} { return res2.MatchString(res1) })	}	return rt.stringOp(node, edge, func(res1 string, res2 string) interface{} { return rt.compiledRegex.MatchString(res1) })}/*Contains runtime*/type containsRuntime struct {	*whereItemRuntime}/*containsRuntimeInst returns a new runtime component instance.*/func containsRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &containsRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *containsRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.stringOp(node, edge, func(res1 string, res2 string) interface{} { return strings.Contains(res1, res2) })}/*Contains not runtime*/type containsNotRuntime struct {	*whereItemRuntime}/*containsNotRuntimeInst returns a new runtime component instance.*/func containsNotRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &containsNotRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *containsNotRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.stringOp(node, edge, func(res1 string, res2 string) interface{} { return !strings.Contains(res1, res2) })}/*Begins with runtime*/type beginsWithRuntime struct {	*whereItemRuntime}/*beginsWithRuntimeInst returns a new runtime component instance.*/func beginsWithRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &beginsWithRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *beginsWithRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.stringOp(node, edge, func(res1 string, res2 string) interface{} { return strings.HasPrefix(res1, res2) })}/*Ends with runtime*/type endsWithRuntime struct {	*whereItemRuntime}/*endsWithRuntimeInst returns a new runtime component instance.*/func endsWithRuntimeInst(rtp *eqlRuntimeProvider, node *parser.ASTNode) parser.Runtime {	return &endsWithRuntime{&whereItemRuntime{rtp, node}}}/*CondEval evaluates this condition runtime element.*/func (rt *endsWithRuntime) CondEval(node data.Node, edge data.Edge) (interface{}, error) {	return rt.stringOp(node, edge, func(res1 string, res2 string) interface{} { return strings.HasSuffix(res1, res2) })}
 |