aboutsummaryrefslogtreecommitdiff
path: root/weed/query/engine/function_helpers.go
blob: 60eccdd37ac013bcbe218ece8ec0996dc6fa7577 (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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package engine

import (
	"fmt"
	"strconv"
	"time"

	"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
)

// Helper function to convert schema_pb.Value to float64
func (e *SQLEngine) valueToFloat64(value *schema_pb.Value) (float64, error) {
	switch v := value.Kind.(type) {
	case *schema_pb.Value_Int32Value:
		return float64(v.Int32Value), nil
	case *schema_pb.Value_Int64Value:
		return float64(v.Int64Value), nil
	case *schema_pb.Value_FloatValue:
		return float64(v.FloatValue), nil
	case *schema_pb.Value_DoubleValue:
		return v.DoubleValue, nil
	case *schema_pb.Value_StringValue:
		// Try to parse string as number
		if f, err := strconv.ParseFloat(v.StringValue, 64); err == nil {
			return f, nil
		}
		return 0, fmt.Errorf("cannot convert string '%s' to number", v.StringValue)
	case *schema_pb.Value_BoolValue:
		if v.BoolValue {
			return 1, nil
		}
		return 0, nil
	default:
		return 0, fmt.Errorf("cannot convert value type to number")
	}
}

// Helper function to check if a value is an integer type
func (e *SQLEngine) isIntegerValue(value *schema_pb.Value) bool {
	switch value.Kind.(type) {
	case *schema_pb.Value_Int32Value, *schema_pb.Value_Int64Value:
		return true
	default:
		return false
	}
}

// Helper function to convert schema_pb.Value to string
func (e *SQLEngine) valueToString(value *schema_pb.Value) (string, error) {
	switch v := value.Kind.(type) {
	case *schema_pb.Value_StringValue:
		return v.StringValue, nil
	case *schema_pb.Value_Int32Value:
		return strconv.FormatInt(int64(v.Int32Value), 10), nil
	case *schema_pb.Value_Int64Value:
		return strconv.FormatInt(v.Int64Value, 10), nil
	case *schema_pb.Value_FloatValue:
		return strconv.FormatFloat(float64(v.FloatValue), 'g', -1, 32), nil
	case *schema_pb.Value_DoubleValue:
		return strconv.FormatFloat(v.DoubleValue, 'g', -1, 64), nil
	case *schema_pb.Value_BoolValue:
		if v.BoolValue {
			return "true", nil
		}
		return "false", nil
	case *schema_pb.Value_BytesValue:
		return string(v.BytesValue), nil
	default:
		return "", fmt.Errorf("cannot convert value type to string")
	}
}

// Helper function to convert schema_pb.Value to int64
func (e *SQLEngine) valueToInt64(value *schema_pb.Value) (int64, error) {
	switch v := value.Kind.(type) {
	case *schema_pb.Value_Int32Value:
		return int64(v.Int32Value), nil
	case *schema_pb.Value_Int64Value:
		return v.Int64Value, nil
	case *schema_pb.Value_FloatValue:
		return int64(v.FloatValue), nil
	case *schema_pb.Value_DoubleValue:
		return int64(v.DoubleValue), nil
	case *schema_pb.Value_StringValue:
		if i, err := strconv.ParseInt(v.StringValue, 10, 64); err == nil {
			return i, nil
		}
		return 0, fmt.Errorf("cannot convert string '%s' to integer", v.StringValue)
	default:
		return 0, fmt.Errorf("cannot convert value type to integer")
	}
}

// Helper function to convert schema_pb.Value to time.Time
func (e *SQLEngine) valueToTime(value *schema_pb.Value) (time.Time, error) {
	switch v := value.Kind.(type) {
	case *schema_pb.Value_TimestampValue:
		if v.TimestampValue == nil {
			return time.Time{}, fmt.Errorf("null timestamp value")
		}
		return time.UnixMicro(v.TimestampValue.TimestampMicros), nil
	case *schema_pb.Value_StringValue:
		// Try to parse various date/time string formats
		dateFormats := []struct {
			format   string
			useLocal bool
		}{
			{"2006-01-02 15:04:05", true},   // Local time assumed for non-timezone formats
			{"2006-01-02T15:04:05Z", false}, // UTC format
			{"2006-01-02T15:04:05", true},   // Local time assumed
			{"2006-01-02", true},            // Local time assumed for date only
			{"15:04:05", true},              // Local time assumed for time only
		}

		for _, formatSpec := range dateFormats {
			if t, err := time.Parse(formatSpec.format, v.StringValue); err == nil {
				if formatSpec.useLocal {
					// Convert to UTC for consistency if no timezone was specified
					return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), time.UTC), nil
				}
				return t, nil
			}
		}
		return time.Time{}, fmt.Errorf("unable to parse date/time string: %s", v.StringValue)
	case *schema_pb.Value_Int64Value:
		// Assume Unix timestamp (seconds)
		return time.Unix(v.Int64Value, 0), nil
	default:
		return time.Time{}, fmt.Errorf("cannot convert value type to date/time")
	}
}