summaryrefslogtreecommitdiff
path: root/internal/mapr/setcondition.go
blob: 9dcd6901df25f63cbcb4cc4eaafe9a1b92e02c93 (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
94
95
96
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 err := initSetConditions(&sc, tokens); err != nil {
			return sc, nil, err
		}

		// Seems like a function call?
		if strings.HasSuffix(sc.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
		}

		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
}

func initSetConditions(sc *setCondition, tokens []token) error {
	if len(tokens) < 3 {
		return errors.New(invalidQuery + "Not enough arguments in 'set' clause")
	}

	sc.lString = tokens[0].str
	sc.rType = Field
	sc.rString = tokens[2].str

	switch {
	case tokens[1].str != "=":
		return errors.New(invalidQuery + "Unknown operation in 'set' clause: " + tokens[1].str)
	case !tokens[0].isBareword:
		return errors.New(invalidQuery + "Expected bareword at 'set' clause's lValue: " +
			tokens[0].str)
	case !strings.HasPrefix(sc.lString, "$"):
		return errors.New(invalidQuery + "Expected field variable name (starting with $) " +
			"at 'set' clause's lValue: " + tokens[0].str)
	}

	return nil
}