summaryrefslogtreecommitdiff
path: root/internal/mapr/setcondition.go
blob: 8c5cfc9d672e9f66753a4023b247da45fd152ff7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package mapr

import (
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/mimecast/dtail/internal/mapr/funcs"
)

// Represent a parsed "set" clause, used by mapr.Query
type setCondition struct {
	lString string

	rType   fieldType
	rString string
	rFloat  float64

	// For now only text functions are supported.
	// Maybe in the future we can have typed functions too
	// so that a float input/output is possible.
	functionStack funcs.FunctionStack
}

func (sc *setCondition) String() string {
	return fmt.Sprintf("setCondition(lString:%s,rString:%s,rType:%s,functionStack:%v)",
		sc.lString, sc.rString, sc.rType.String(), sc.functionStack)
}

func makeSetConditions(tokens []token) (set []setCondition, err error) {
	parse := func(tokens []token) (setCondition, []token, error) {
		var sc setCondition
		if len(tokens) < 3 {
			return sc, nil, errors.New(invalidQuery + "Not enough arguments in 'set' clause")
		}

		setOp := strings.ToLower(tokens[1].str)
		switch setOp {
		case "=":
		default:
			return sc, nil, errors.New(invalidQuery + "Unknown operation in 'set' clause: " + setOp)
		}

		if !tokens[0].isBareword {
			return sc, nil, errors.New(invalidQuery + "Expected bareword at 'set' clause's lValue: " + tokens[0].str)
		}

		sc.lString = tokens[0].str
		if !strings.HasPrefix(sc.lString, "$") {
			return sc, nil, errors.New(invalidQuery + "Expected field variable name (starting with $) at 'set' clause's lValue: " + tokens[0].str)
		}
		sc.rType = Field

		rString := tokens[2].str
		// Seems like a function call?
		if strings.HasSuffix(rString, ")") {
			functionStack, functionArg, err := funcs.NewFunctionStack(tokens[2].str)
			if err != nil {
				return sc, nil, err
			}
			sc.functionStack = functionStack
			sc.rType = FunctionStack
			sc.rString = functionArg
			return sc, tokens[3:], nil
		}

		sc.rString = rString
		if f, err := strconv.ParseFloat(sc.rString, 64); err == nil {
			sc.rFloat = f
			sc.rType = Float
		} else {
			sc.rType = Field
		}

		return sc, tokens[3:], nil
	}

	for len(tokens) > 0 {
		var sc setCondition
		var err error

		sc, tokens, err = parse(tokens)
		if err != nil {
			return nil, err
		}

		set = append(set, sc)
		tokens = tokensConsumeOptional(tokens, ",")
	}

	return
}