mirror of
https://gitee.com/rulego/streamsql.git
synced 2025-07-05 15:49:14 +00:00
init
This commit is contained in:
48
.gitignore
vendored
Normal file
48
.gitignore
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
# JetBrains template
|
||||
.idea
|
||||
*.iml
|
||||
out/
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
### Go template
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
vendor/
|
||||
|
||||
### macOS template
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# VSCode
|
||||
.vscode
|
||||
|
||||
# log
|
||||
*.log
|
||||
|
||||
# coverage file
|
||||
coverage.html
|
||||
|
||||
examples/server/rules/
|
||||
examples/server/js/
|
||||
examples/server/plugins/
|
111
builtin/builtin.go
Normal file
111
builtin/builtin.go
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package builtin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/montanaflynn/stats"
|
||||
)
|
||||
|
||||
var AggregateBuiltins = map[string]*AggregateFunction{}
|
||||
|
||||
func init() {
|
||||
for _, item := range aggregateBuiltins {
|
||||
AggregateBuiltins[item.Name] = item
|
||||
for _, name := range item.Alias {
|
||||
AggregateBuiltins[name] = item
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var aggregateBuiltins = []*AggregateFunction{
|
||||
{
|
||||
Name: "avg",
|
||||
Func: func(input []float64, args ...any) (any, error) {
|
||||
return stats.Mean(input)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "count",
|
||||
Func: func(input []float64, args ...any) (any, error) {
|
||||
return len(input), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "sum",
|
||||
Func: func(input []float64, args ...any) (any, error) {
|
||||
return stats.Sum(input)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "min",
|
||||
Func: func(input []float64, args ...any) (any, error) {
|
||||
return stats.Min(input)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "max",
|
||||
Func: func(input []float64, args ...any) (any, error) {
|
||||
return stats.Max(input)
|
||||
},
|
||||
},
|
||||
//返回组中所有值的标准差。空值不参与计算。
|
||||
{
|
||||
Name: "stddev",
|
||||
Func: func(input []float64, args ...any) (any, error) {
|
||||
return stats.StandardDeviation(input)
|
||||
},
|
||||
},
|
||||
//返回组中所有值的样本标准差。空值不参与计算。
|
||||
{
|
||||
Name: "stddevs",
|
||||
Func: func(input []float64, args ...any) (any, error) {
|
||||
return stats.StandardDeviationSample(input)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "var",
|
||||
Func: func(input []float64, args ...any) (any, error) {
|
||||
return stats.Variance(input)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "vars",
|
||||
Func: func(input []float64, args ...any) (any, error) {
|
||||
return stats.VarS(input)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "median",
|
||||
Func: func(input []float64, args ...any) (any, error) {
|
||||
return stats.Median(input)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "percentile",
|
||||
Func: func(input []float64, args ...any) (any, error) {
|
||||
if len(args) < 1 {
|
||||
return 0, fmt.Errorf("invalid number of arguments for percentile (expected 1, got %d)", len(args))
|
||||
}
|
||||
if percent, ok := args[0].(float64); !ok {
|
||||
return 0, fmt.Errorf("percent need float64 type (got %d)", len(args))
|
||||
} else {
|
||||
return stats.Percentile(input, percent)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
38
builtin/function.go
Normal file
38
builtin/function.go
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package builtin
|
||||
|
||||
//type Function struct {
|
||||
// AuthorName string
|
||||
// Func func(args ...any) (any, error)
|
||||
// Fast func(arg any) any
|
||||
// ValidateArgs func(args ...any) (any, error)
|
||||
// Types []reflect.Type
|
||||
// Validate func(args []reflect.Type) (reflect.Type, error)
|
||||
// Predicate bool
|
||||
//}
|
||||
|
||||
type AggregateFunction struct {
|
||||
//函数名
|
||||
Name string
|
||||
//别名
|
||||
Alias []string
|
||||
//函数
|
||||
Func func(input []float64, args ...any) (any, error)
|
||||
//验证参数
|
||||
ValidateArgs func(input []float64, args ...any) (any, error)
|
||||
}
|
26
collector/aggregate_collector.go
Normal file
26
collector/aggregate_collector.go
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package collector
|
||||
|
||||
import (
|
||||
"github.com/rulego/streamsql/types"
|
||||
)
|
||||
|
||||
type aggregateCollector struct {
|
||||
groupBy []string
|
||||
window types.Window
|
||||
}
|
263
collector/collector.go
Normal file
263
collector/collector.go
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package collector
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/rulego/streamsql/dataset"
|
||||
"github.com/rulego/streamsql/types"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// DefaultSelectStreamSqlContext sql执行生命周期上下文
|
||||
type DefaultSelectStreamSqlContext struct {
|
||||
context.Context
|
||||
Collector *StreamCollector
|
||||
// 当前传入已经转成map的流数据
|
||||
msgAsMap map[string]interface{}
|
||||
msg types.Msg
|
||||
locker sync.RWMutex
|
||||
groupValues types.GroupValues
|
||||
}
|
||||
|
||||
func NewDefaultSelectStreamSqlContext(ctx context.Context, collector *StreamCollector, msg types.Msg) *DefaultSelectStreamSqlContext {
|
||||
return &DefaultSelectStreamSqlContext{
|
||||
Context: ctx,
|
||||
Collector: collector,
|
||||
msg: msg,
|
||||
}
|
||||
}
|
||||
func (c *DefaultSelectStreamSqlContext) Decode() error {
|
||||
if c.msg.Data == nil {
|
||||
return errors.New("data can not nil")
|
||||
}
|
||||
//已经解码
|
||||
if c.msgAsMap != nil {
|
||||
return nil
|
||||
}
|
||||
if mapData, err := c.msg.Data.DecodeAsMap(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
c.msgAsMap = mapData
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *DefaultSelectStreamSqlContext) InputAsMap() map[string]interface{} {
|
||||
c.locker.RLock()
|
||||
defer c.locker.RUnlock()
|
||||
return c.msgAsMap
|
||||
}
|
||||
|
||||
func (c *DefaultSelectStreamSqlContext) RawInput() types.Msg {
|
||||
return c.msg
|
||||
}
|
||||
|
||||
func (c *DefaultSelectStreamSqlContext) SetGroupByKey(groupByKey types.GroupFields) {
|
||||
c.Collector.SetGroupByKey(groupByKey)
|
||||
}
|
||||
func (c *DefaultSelectStreamSqlContext) GetGroupByKey() types.GroupFields {
|
||||
return c.Collector.GetGroupByKey()
|
||||
}
|
||||
func (c *DefaultSelectStreamSqlContext) IsInitWindow(groupValues types.GroupValues) bool {
|
||||
return c.Collector.IsInitWindow(groupValues)
|
||||
}
|
||||
|
||||
func (c *DefaultSelectStreamSqlContext) AddWindow(groupByKey types.GroupValues, window types.Window) {
|
||||
c.Collector.AddWindow(groupByKey, window)
|
||||
}
|
||||
|
||||
func (c *DefaultSelectStreamSqlContext) CreteWindowObserver() types.WindowObserver {
|
||||
return c.Collector.CreteWindowObserver()
|
||||
}
|
||||
|
||||
func (c *DefaultSelectStreamSqlContext) GetWindow(groupByKey types.GroupValues) types.Window {
|
||||
return c.Collector.GetWindow(groupByKey)
|
||||
}
|
||||
|
||||
func (c *DefaultSelectStreamSqlContext) GetRow(groupValues types.GroupValues) (*dataset.Row, bool) {
|
||||
return c.Collector.GetRow(groupValues)
|
||||
}
|
||||
|
||||
func (c *DefaultSelectStreamSqlContext) AddColumn(groupValues types.GroupValues, kv dataset.KeyValue) {
|
||||
c.Collector.AddColumn(groupValues, kv)
|
||||
}
|
||||
|
||||
func (c *DefaultSelectStreamSqlContext) GetColumn(groupValues types.GroupValues, key dataset.Key) (dataset.KeyValue, bool) {
|
||||
return c.Collector.GetColumn(groupValues, key)
|
||||
}
|
||||
|
||||
//func (c *DefaultSelectStreamSqlContext) AddField(fieldId string, value any) {
|
||||
// c.locker.Lock()
|
||||
// defer c.locker.Unlock()
|
||||
// c.msgAsMap[fieldId] = value
|
||||
//
|
||||
//}
|
||||
//
|
||||
//func (c *DefaultSelectStreamSqlContext) GetField(fieldId string) (any, bool) {
|
||||
// c.locker.RLock()
|
||||
// defer c.locker.RUnlock()
|
||||
// v, ok := c.msgAsMap[fieldId]
|
||||
// return v, ok
|
||||
//}
|
||||
|
||||
func (c *DefaultSelectStreamSqlContext) SetCurrentGroupValues(groupValues types.GroupValues) {
|
||||
c.groupValues = groupValues
|
||||
}
|
||||
|
||||
func (c *DefaultSelectStreamSqlContext) GetCurrentGroupValues() types.GroupValues {
|
||||
return c.groupValues
|
||||
}
|
||||
|
||||
func (c *DefaultSelectStreamSqlContext) AddFieldAggregateValue(groupValues types.GroupValues, fieldId string, value float64) {
|
||||
c.Collector.AddFieldAggregateValue(groupValues, fieldId, value)
|
||||
}
|
||||
|
||||
func (c *DefaultSelectStreamSqlContext) GetFieldAggregateValue(groupValues types.GroupValues, fieldId string) []float64 {
|
||||
return c.Collector.GetFieldAggregateValue(groupValues, fieldId)
|
||||
}
|
||||
|
||||
type aggregateFieldValue struct {
|
||||
GroupFields types.GroupFields
|
||||
FieldWindows map[string]types.Window
|
||||
}
|
||||
|
||||
func (afv *aggregateFieldValue) AddFieldValue(fieldId string, data float64) {
|
||||
if w, ok := afv.FieldWindows[fieldId]; !ok {
|
||||
//afv.FieldWindows[fieldId] = newQueue
|
||||
} else {
|
||||
w.Add(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (afv *aggregateFieldValue) GetFieldValues(fieldId string) []float64 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// StreamCollector 收集器
|
||||
type StreamCollector struct {
|
||||
context.Context
|
||||
keyedWindow map[types.GroupValues]types.Window
|
||||
planner types.LogicalPlan
|
||||
aggregateOperators []types.AggregateOperator
|
||||
groupByKey types.GroupFields
|
||||
aggregateFieldValues map[types.GroupValues]*aggregateFieldValue
|
||||
rows *dataset.Rows
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func (c *StreamCollector) SetGroupByKey(groupByKey types.GroupFields) {
|
||||
c.groupByKey = groupByKey
|
||||
}
|
||||
func (c *StreamCollector) GetGroupByKey() types.GroupFields {
|
||||
return c.groupByKey
|
||||
}
|
||||
|
||||
func (c *StreamCollector) IsInitWindow(groupValues types.GroupValues) bool {
|
||||
_, ok := c.keyedWindow[groupValues]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (c *StreamCollector) AddWindow(groupByKey types.GroupValues, window types.Window) {
|
||||
c.keyedWindow[groupByKey] = window
|
||||
}
|
||||
|
||||
func (c *StreamCollector) GetWindow(groupByKey types.GroupValues) types.Window {
|
||||
return c.keyedWindow[groupByKey]
|
||||
}
|
||||
|
||||
func (c *StreamCollector) CreteWindowObserver() types.WindowObserver {
|
||||
return types.WindowObserver{
|
||||
AddHandler: func(context types.StreamSqlOperatorContext, data float64) {
|
||||
for _, op := range c.aggregateOperators {
|
||||
op.AddHandler(context, data)
|
||||
}
|
||||
},
|
||||
ArchiveHandler: func(context types.StreamSqlOperatorContext, dataList []float64) {
|
||||
for _, op := range c.aggregateOperators {
|
||||
op.ArchiveHandler(context, dataList)
|
||||
}
|
||||
},
|
||||
StartHandler: func(context types.StreamSqlOperatorContext) {
|
||||
},
|
||||
EndHandler: func(context types.StreamSqlOperatorContext, dataList []float64) {
|
||||
for _, op := range c.aggregateOperators {
|
||||
op.EndHandler(context, dataList)
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
func (c *StreamCollector) AddFieldAggregateValue(groupValues types.GroupValues, fieldId string, data float64) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
if w, ok := c.keyedWindow[groupValues]; ok {
|
||||
w.Add(data)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *StreamCollector) GetFieldAggregateValue(groupValues types.GroupValues, fieldId string) []float64 {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
if _, ok := c.keyedWindow[groupValues]; ok {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *StreamCollector) GetRow(groupValues types.GroupValues) (*dataset.Row, bool) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
return c.rows.GetRow(groupValues)
|
||||
}
|
||||
|
||||
func (c *StreamCollector) AddColumn(groupValues types.GroupValues, kv dataset.KeyValue) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
c.rows.AddColumn(groupValues, kv)
|
||||
}
|
||||
|
||||
func (c *StreamCollector) GetColumn(groupValues types.GroupValues, key dataset.Key) (dataset.KeyValue, bool) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
return c.rows.GetColumn(groupValues, key)
|
||||
}
|
||||
|
||||
func NewStreamCollector(planner types.LogicalPlan) *StreamCollector {
|
||||
c := &StreamCollector{
|
||||
planner: planner,
|
||||
aggregateOperators: planner.AggregateOperators(),
|
||||
keyedWindow: make(map[types.GroupValues]types.Window),
|
||||
aggregateFieldValues: make(map[types.GroupValues]*aggregateFieldValue),
|
||||
rows: dataset.NewRows(),
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Init 初始化
|
||||
func (c *StreamCollector) Init() error {
|
||||
return c.planner.Init(c)
|
||||
}
|
||||
|
||||
func (c *StreamCollector) Collect(ctx context.Context, msg types.Msg) error {
|
||||
selectStreamSqlContext := NewDefaultSelectStreamSqlContext(ctx, c, msg)
|
||||
if err := selectStreamSqlContext.Decode(); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.planner.Apply(selectStreamSqlContext)
|
||||
}
|
41
collector/collector_test.go
Normal file
41
collector/collector_test.go
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2023 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package collector
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/rulego/streamsql/rsql"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCollector(t *testing.T) {
|
||||
sql := "select deviceId,avg(temperature+20/20,aa)/2 as aa from Input where deviceId='aa' OR deviceId='bb' group by deviceId,TumblingWindow(10m) ;"
|
||||
newParser := rsql.NewParser(rsql.NewLexer(sql))
|
||||
statement := newParser.ParseStatement()
|
||||
buf := new(bytes.Buffer)
|
||||
statement.Format(buf)
|
||||
buf.WriteTo(os.Stdout)
|
||||
fmt.Println(statement)
|
||||
//collector, err := planner.CreateSelectPlanner(statement.(*rsql.Select))
|
||||
//fmt.Println(err)
|
||||
//msg := types.NewJsonMsg(0, types.NewMetadata(), `{"temperature":50}`)
|
||||
//err = collector.Collect(context.TODO(), msg)
|
||||
//fmt.Println(err)
|
||||
//time.Sleep(time.Second * 10)
|
||||
}
|
17
conf/config.go
Normal file
17
conf/config.go
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package conf
|
134
dataset/key.go
Normal file
134
dataset/key.go
Normal file
@ -0,0 +1,134 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dataset // import "go.opentelemetry.io/otel/attribute"
|
||||
|
||||
// Key represents the key part in key-value pairs. It's a string. The
|
||||
// allowed character set in the key depends on the use of the key.
|
||||
type Key string
|
||||
|
||||
// Bool creates a KeyValue instance with a BOOL Value.
|
||||
//
|
||||
// If creating both a key and value at the same time, use the provided
|
||||
// convenience function instead -- Bool(name, value).
|
||||
func (k Key) Bool(v bool) KeyValue {
|
||||
return KeyValue{
|
||||
Key: k,
|
||||
Value: BoolValue(v),
|
||||
}
|
||||
}
|
||||
|
||||
// BoolSlice creates a KeyValue instance with a BOOLSLICE Value.
|
||||
//
|
||||
// If creating both a key and value at the same time, use the provided
|
||||
// convenience function instead -- BoolSlice(name, value).
|
||||
func (k Key) BoolSlice(v []bool) KeyValue {
|
||||
return KeyValue{
|
||||
Key: k,
|
||||
Value: BoolSliceValue(v),
|
||||
}
|
||||
}
|
||||
|
||||
// Int creates a KeyValue instance with an INT64 Value.
|
||||
//
|
||||
// If creating both a key and value at the same time, use the provided
|
||||
// convenience function instead -- Int(name, value).
|
||||
func (k Key) Int(v int) KeyValue {
|
||||
return KeyValue{
|
||||
Key: k,
|
||||
Value: IntValue(v),
|
||||
}
|
||||
}
|
||||
|
||||
// IntSlice creates a KeyValue instance with an INT64SLICE Value.
|
||||
//
|
||||
// If creating both a key and value at the same time, use the provided
|
||||
// convenience function instead -- IntSlice(name, value).
|
||||
func (k Key) IntSlice(v []int) KeyValue {
|
||||
return KeyValue{
|
||||
Key: k,
|
||||
Value: IntSliceValue(v),
|
||||
}
|
||||
}
|
||||
|
||||
// Int64 creates a KeyValue instance with an INT64 Value.
|
||||
//
|
||||
// If creating both a key and value at the same time, use the provided
|
||||
// convenience function instead -- Int64(name, value).
|
||||
func (k Key) Int64(v int64) KeyValue {
|
||||
return KeyValue{
|
||||
Key: k,
|
||||
Value: Int64Value(v),
|
||||
}
|
||||
}
|
||||
|
||||
// Int64Slice creates a KeyValue instance with an INT64SLICE Value.
|
||||
//
|
||||
// If creating both a key and value at the same time, use the provided
|
||||
// convenience function instead -- Int64Slice(name, value).
|
||||
func (k Key) Int64Slice(v []int64) KeyValue {
|
||||
return KeyValue{
|
||||
Key: k,
|
||||
Value: Int64SliceValue(v),
|
||||
}
|
||||
}
|
||||
|
||||
// Float64 creates a KeyValue instance with a FLOAT64 Value.
|
||||
//
|
||||
// If creating both a key and value at the same time, use the provided
|
||||
// convenience function instead -- Float64(name, value).
|
||||
func (k Key) Float64(v float64) KeyValue {
|
||||
return KeyValue{
|
||||
Key: k,
|
||||
Value: Float64Value(v),
|
||||
}
|
||||
}
|
||||
|
||||
// Float64Slice creates a KeyValue instance with a FLOAT64SLICE Value.
|
||||
//
|
||||
// If creating both a key and value at the same time, use the provided
|
||||
// convenience function instead -- Float64(name, value).
|
||||
func (k Key) Float64Slice(v []float64) KeyValue {
|
||||
return KeyValue{
|
||||
Key: k,
|
||||
Value: Float64SliceValue(v),
|
||||
}
|
||||
}
|
||||
|
||||
// String creates a KeyValue instance with a STRING Value.
|
||||
//
|
||||
// If creating both a key and value at the same time, use the provided
|
||||
// convenience function instead -- String(name, value).
|
||||
func (k Key) String(v string) KeyValue {
|
||||
return KeyValue{
|
||||
Key: k,
|
||||
Value: StringValue(v),
|
||||
}
|
||||
}
|
||||
|
||||
// StringSlice creates a KeyValue instance with a STRINGSLICE Value.
|
||||
//
|
||||
// If creating both a key and value at the same time, use the provided
|
||||
// convenience function instead -- StringSlice(name, value).
|
||||
func (k Key) StringSlice(v []string) KeyValue {
|
||||
return KeyValue{
|
||||
Key: k,
|
||||
Value: StringSliceValue(v),
|
||||
}
|
||||
}
|
||||
|
||||
// Defined returns true for non-empty keys.
|
||||
func (k Key) Defined() bool {
|
||||
return len(k) != 0
|
||||
}
|
86
dataset/kv.go
Normal file
86
dataset/kv.go
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dataset
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// KeyValue holds a key and value pair.
|
||||
type KeyValue struct {
|
||||
Key Key
|
||||
Value Value
|
||||
}
|
||||
|
||||
// Valid returns if kv is a valid OpenTelemetry attribute.
|
||||
func (kv KeyValue) Valid() bool {
|
||||
return kv.Key.Defined() && kv.Value.Type() != INVALID
|
||||
}
|
||||
|
||||
// Bool creates a KeyValue with a BOOL Value type.
|
||||
func Bool(k string, v bool) KeyValue {
|
||||
return Key(k).Bool(v)
|
||||
}
|
||||
|
||||
// BoolSlice creates a KeyValue with a BOOLSLICE Value type.
|
||||
func BoolSlice(k string, v []bool) KeyValue {
|
||||
return Key(k).BoolSlice(v)
|
||||
}
|
||||
|
||||
// Int creates a KeyValue with an INT64 Value type.
|
||||
func Int(k string, v int) KeyValue {
|
||||
return Key(k).Int(v)
|
||||
}
|
||||
|
||||
// IntSlice creates a KeyValue with an INT64SLICE Value type.
|
||||
func IntSlice(k string, v []int) KeyValue {
|
||||
return Key(k).IntSlice(v)
|
||||
}
|
||||
|
||||
// Int64 creates a KeyValue with an INT64 Value type.
|
||||
func Int64(k string, v int64) KeyValue {
|
||||
return Key(k).Int64(v)
|
||||
}
|
||||
|
||||
// Int64Slice creates a KeyValue with an INT64SLICE Value type.
|
||||
func Int64Slice(k string, v []int64) KeyValue {
|
||||
return Key(k).Int64Slice(v)
|
||||
}
|
||||
|
||||
// Float64 creates a KeyValue with a FLOAT64 Value type.
|
||||
func Float64(k string, v float64) KeyValue {
|
||||
return Key(k).Float64(v)
|
||||
}
|
||||
|
||||
// Float64Slice creates a KeyValue with a FLOAT64SLICE Value type.
|
||||
func Float64Slice(k string, v []float64) KeyValue {
|
||||
return Key(k).Float64Slice(v)
|
||||
}
|
||||
|
||||
// String creates a KeyValue with a STRING Value type.
|
||||
func String(k, v string) KeyValue {
|
||||
return Key(k).String(v)
|
||||
}
|
||||
|
||||
// StringSlice creates a KeyValue with a STRINGSLICE Value type.
|
||||
func StringSlice(k string, v []string) KeyValue {
|
||||
return Key(k).StringSlice(v)
|
||||
}
|
||||
|
||||
// Stringer creates a new key-value pair with a passed name and a string
|
||||
// value generated by the passed Stringer interface.
|
||||
func Stringer(k string, v fmt.Stringer) KeyValue {
|
||||
return Key(k).String(v.String())
|
||||
}
|
99
dataset/row.go
Normal file
99
dataset/row.go
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dataset
|
||||
|
||||
import "github.com/rulego/streamsql/types"
|
||||
|
||||
type Row struct {
|
||||
GroupValues types.GroupValues
|
||||
Columns map[Key]KeyValue
|
||||
}
|
||||
|
||||
func NewRow(groupValues types.GroupValues) *Row {
|
||||
r := &Row{
|
||||
GroupValues: groupValues,
|
||||
Columns: make(map[Key]KeyValue),
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Row) AddColumn(kv KeyValue) {
|
||||
if r.Columns == nil {
|
||||
r.Columns = make(map[Key]KeyValue)
|
||||
}
|
||||
r.Columns[kv.Key] = kv
|
||||
}
|
||||
|
||||
func (r *Row) GetColumn(key Key) (KeyValue, bool) {
|
||||
if r.Columns == nil {
|
||||
return KeyValue{}, false
|
||||
}
|
||||
v, ok := r.Columns[key]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
type Rows struct {
|
||||
Rows map[types.GroupValues]*Row
|
||||
}
|
||||
|
||||
func NewRows() *Rows {
|
||||
r := &Rows{
|
||||
Rows: make(map[types.GroupValues]*Row),
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Rows) AddColumn(groupValues types.GroupValues, kv KeyValue) {
|
||||
if r.Rows == nil {
|
||||
r.Rows = make(map[types.GroupValues]*Row)
|
||||
}
|
||||
row, ok := r.Rows[groupValues]
|
||||
if !ok {
|
||||
row = NewRow(groupValues)
|
||||
r.Rows[groupValues] = row
|
||||
}
|
||||
row.AddColumn(kv)
|
||||
}
|
||||
|
||||
func (r *Rows) GetColumn(groupValues types.GroupValues, key Key) (KeyValue, bool) {
|
||||
if r.Rows == nil {
|
||||
return KeyValue{}, false
|
||||
}
|
||||
row, ok := r.Rows[groupValues]
|
||||
if !ok {
|
||||
return KeyValue{}, false
|
||||
}
|
||||
return row.GetColumn(key)
|
||||
}
|
||||
|
||||
func (r *Rows) GetRow(groupValues types.GroupValues) (*Row, bool) {
|
||||
if r.Rows == nil {
|
||||
return nil, false
|
||||
}
|
||||
v, ok := r.Rows[groupValues]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
func (r *Rows) AddRow(row *Row) {
|
||||
if row == nil {
|
||||
return
|
||||
}
|
||||
if r.Rows == nil {
|
||||
r.Rows = make(map[types.GroupValues]*Row)
|
||||
}
|
||||
r.Rows[row.GroupValues] = row
|
||||
}
|
269
dataset/value.go
Normal file
269
dataset/value.go
Normal file
@ -0,0 +1,269 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dataset
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/rulego/streamsql/utils/attribute"
|
||||
"github.com/rulego/streamsql/utils/compress"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
//go:generate stringer -type=Type
|
||||
|
||||
// Type describes the type of the data Value holds.
|
||||
type Type int // nolint: revive // redefines builtin Type.
|
||||
|
||||
// Value represents the value part in key-value pairs.
|
||||
type Value struct {
|
||||
vtype Type
|
||||
numeric uint64
|
||||
stringly string
|
||||
slice interface{}
|
||||
}
|
||||
|
||||
const (
|
||||
// INVALID is used for a Value with no value set.
|
||||
INVALID Type = iota
|
||||
// BOOL is a boolean Type Value.
|
||||
BOOL
|
||||
// INT64 is a 64-bit signed integral Type Value.
|
||||
INT64
|
||||
// FLOAT64 is a 64-bit floating point Type Value.
|
||||
FLOAT64
|
||||
// STRING is a string Type Value.
|
||||
STRING
|
||||
// BOOLSLICE is a slice of booleans Type Value.
|
||||
BOOLSLICE
|
||||
// INT64SLICE is a slice of 64-bit signed integral numbers Type Value.
|
||||
INT64SLICE
|
||||
// FLOAT64SLICE is a slice of 64-bit floating point numbers Type Value.
|
||||
FLOAT64SLICE
|
||||
// STRINGSLICE is a slice of strings Type Value.
|
||||
STRINGSLICE
|
||||
)
|
||||
|
||||
// BoolValue creates a BOOL Value.
|
||||
func BoolValue(v bool) Value {
|
||||
return Value{
|
||||
vtype: BOOL,
|
||||
numeric: compress.BoolToRaw(v),
|
||||
}
|
||||
}
|
||||
|
||||
// BoolSliceValue creates a BOOLSLICE Value.
|
||||
func BoolSliceValue(v []bool) Value {
|
||||
return Value{vtype: BOOLSLICE, slice: attribute.BoolSliceValue(v)}
|
||||
}
|
||||
|
||||
// IntValue creates an INT64 Value.
|
||||
func IntValue(v int) Value {
|
||||
return Int64Value(int64(v))
|
||||
}
|
||||
|
||||
// IntSliceValue creates an INTSLICE Value.
|
||||
func IntSliceValue(v []int) Value {
|
||||
var int64Val int64
|
||||
cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(int64Val)))
|
||||
for i, val := range v {
|
||||
cp.Elem().Index(i).SetInt(int64(val))
|
||||
}
|
||||
return Value{
|
||||
vtype: INT64SLICE,
|
||||
slice: cp.Elem().Interface(),
|
||||
}
|
||||
}
|
||||
|
||||
// Int64Value creates an INT64 Value.
|
||||
func Int64Value(v int64) Value {
|
||||
return Value{
|
||||
vtype: INT64,
|
||||
numeric: compress.Int64ToRaw(v),
|
||||
}
|
||||
}
|
||||
|
||||
// Int64SliceValue creates an INT64SLICE Value.
|
||||
func Int64SliceValue(v []int64) Value {
|
||||
return Value{vtype: INT64SLICE, slice: attribute.Int64SliceValue(v)}
|
||||
}
|
||||
|
||||
// Float64Value creates a FLOAT64 Value.
|
||||
func Float64Value(v float64) Value {
|
||||
return Value{
|
||||
vtype: FLOAT64,
|
||||
numeric: compress.Float64ToRaw(v),
|
||||
}
|
||||
}
|
||||
|
||||
// Float64SliceValue creates a FLOAT64SLICE Value.
|
||||
func Float64SliceValue(v []float64) Value {
|
||||
return Value{vtype: FLOAT64SLICE, slice: attribute.Float64SliceValue(v)}
|
||||
}
|
||||
|
||||
// StringValue creates a STRING Value.
|
||||
func StringValue(v string) Value {
|
||||
return Value{
|
||||
vtype: STRING,
|
||||
stringly: v,
|
||||
}
|
||||
}
|
||||
|
||||
// StringSliceValue creates a STRINGSLICE Value.
|
||||
func StringSliceValue(v []string) Value {
|
||||
return Value{vtype: STRINGSLICE, slice: attribute.StringSliceValue(v)}
|
||||
}
|
||||
|
||||
// Type returns a type of the Value.
|
||||
func (v Value) Type() Type {
|
||||
return v.vtype
|
||||
}
|
||||
|
||||
// AsBool returns the bool value. Make sure that the Value's type is
|
||||
// BOOL.
|
||||
func (v Value) AsBool() bool {
|
||||
return compress.RawToBool(v.numeric)
|
||||
}
|
||||
|
||||
// AsBoolSlice returns the []bool value. Make sure that the Value's type is
|
||||
// BOOLSLICE.
|
||||
func (v Value) AsBoolSlice() []bool {
|
||||
if v.vtype != BOOLSLICE {
|
||||
return nil
|
||||
}
|
||||
return v.asBoolSlice()
|
||||
}
|
||||
|
||||
func (v Value) asBoolSlice() []bool {
|
||||
return attribute.AsBoolSlice(v.slice)
|
||||
}
|
||||
|
||||
// AsInt64 returns the int64 value. Make sure that the Value's type is
|
||||
// INT64.
|
||||
func (v Value) AsInt64() int64 {
|
||||
return compress.RawToInt64(v.numeric)
|
||||
}
|
||||
|
||||
// AsInt64Slice returns the []int64 value. Make sure that the Value's type is
|
||||
// INT64SLICE.
|
||||
func (v Value) AsInt64Slice() []int64 {
|
||||
if v.vtype != INT64SLICE {
|
||||
return nil
|
||||
}
|
||||
return v.asInt64Slice()
|
||||
}
|
||||
|
||||
func (v Value) asInt64Slice() []int64 {
|
||||
return attribute.AsInt64Slice(v.slice)
|
||||
}
|
||||
|
||||
// AsFloat64 returns the float64 value. Make sure that the Value's
|
||||
// type is FLOAT64.
|
||||
func (v Value) AsFloat64() float64 {
|
||||
return compress.RawToFloat64(v.numeric)
|
||||
}
|
||||
|
||||
// AsFloat64Slice returns the []float64 value. Make sure that the Value's type is
|
||||
// FLOAT64SLICE.
|
||||
func (v Value) AsFloat64Slice() []float64 {
|
||||
if v.vtype != FLOAT64SLICE {
|
||||
return nil
|
||||
}
|
||||
return v.asFloat64Slice()
|
||||
}
|
||||
|
||||
func (v Value) asFloat64Slice() []float64 {
|
||||
return attribute.AsFloat64Slice(v.slice)
|
||||
}
|
||||
|
||||
// AsString returns the string value. Make sure that the Value's type
|
||||
// is STRING.
|
||||
func (v Value) AsString() string {
|
||||
return v.stringly
|
||||
}
|
||||
|
||||
// AsStringSlice returns the []string value. Make sure that the Value's type is
|
||||
// STRINGSLICE.
|
||||
func (v Value) AsStringSlice() []string {
|
||||
if v.vtype != STRINGSLICE {
|
||||
return nil
|
||||
}
|
||||
return v.asStringSlice()
|
||||
}
|
||||
|
||||
func (v Value) asStringSlice() []string {
|
||||
return attribute.AsStringSlice(v.slice)
|
||||
}
|
||||
|
||||
type unknownValueType struct{}
|
||||
|
||||
// AsInterface returns Value's data as interface{}.
|
||||
func (v Value) AsInterface() interface{} {
|
||||
switch v.Type() {
|
||||
case BOOL:
|
||||
return v.AsBool()
|
||||
case BOOLSLICE:
|
||||
return v.asBoolSlice()
|
||||
case INT64:
|
||||
return v.AsInt64()
|
||||
case INT64SLICE:
|
||||
return v.asInt64Slice()
|
||||
case FLOAT64:
|
||||
return v.AsFloat64()
|
||||
case FLOAT64SLICE:
|
||||
return v.asFloat64Slice()
|
||||
case STRING:
|
||||
return v.stringly
|
||||
case STRINGSLICE:
|
||||
return v.asStringSlice()
|
||||
}
|
||||
return unknownValueType{}
|
||||
}
|
||||
|
||||
// Emit returns a string representation of Value's data.
|
||||
func (v Value) Emit() string {
|
||||
switch v.Type() {
|
||||
case BOOLSLICE:
|
||||
return fmt.Sprint(v.asBoolSlice())
|
||||
case BOOL:
|
||||
return strconv.FormatBool(v.AsBool())
|
||||
case INT64SLICE:
|
||||
return fmt.Sprint(v.asInt64Slice())
|
||||
case INT64:
|
||||
return strconv.FormatInt(v.AsInt64(), 10)
|
||||
case FLOAT64SLICE:
|
||||
return fmt.Sprint(v.asFloat64Slice())
|
||||
case FLOAT64:
|
||||
return fmt.Sprint(v.AsFloat64())
|
||||
case STRINGSLICE:
|
||||
return fmt.Sprint(v.asStringSlice())
|
||||
case STRING:
|
||||
return v.stringly
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of the Value.
|
||||
func (v Value) MarshalJSON() ([]byte, error) {
|
||||
var jsonVal struct {
|
||||
Type string
|
||||
Value interface{}
|
||||
}
|
||||
jsonVal.Type = v.Type()
|
||||
jsonVal.Value = v.AsInterface()
|
||||
return json.Marshal(jsonVal)
|
||||
}
|
9
go.mod
Normal file
9
go.mod
Normal file
@ -0,0 +1,9 @@
|
||||
module github.com/rulego/streamsql
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/expr-lang/expr v1.16.0
|
||||
github.com/golang/snappy v0.0.4
|
||||
github.com/montanaflynn/stats v0.7.1
|
||||
)
|
10
go.sum
Normal file
10
go.sum
Normal file
@ -0,0 +1,10 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/expr-lang/expr v1.16.0 h1:BQabx+PbjsL2PEQwkJ4GIn3CcuUh8flduHhJ0lHjWwE=
|
||||
github.com/expr-lang/expr v1.16.0/go.mod h1:uCkhfG+x7fcZ5A5sXHKuQ07jGZRl6J0FCAaf2k4PtVQ=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
89
operator/aggregate_op.go
Normal file
89
operator/aggregate_op.go
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/expr-lang/expr/vm"
|
||||
"github.com/rulego/streamsql/builtin"
|
||||
"github.com/rulego/streamsql/dataset"
|
||||
"github.com/rulego/streamsql/rsql"
|
||||
"github.com/rulego/streamsql/types"
|
||||
"github.com/rulego/streamsql/utils/cast"
|
||||
)
|
||||
|
||||
type AggregateOp struct {
|
||||
BaseOp
|
||||
//WindowType rsql.WindowType
|
||||
AggregateFunc *rsql.FunctionCall
|
||||
//dataList *queue.Queue
|
||||
//groupDataList map[types.GroupFields]*queue.Queue
|
||||
ArgsProgram []*vm.Program
|
||||
}
|
||||
|
||||
func (o *AggregateOp) Init(context types.StreamSqlContext) error {
|
||||
//o.groupDataList = make(map[types.GroupFields]*queue.Queue)
|
||||
|
||||
//o.dataList = queue.NewCircleQueue(10000)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *AggregateOp) Apply(context types.StreamSqlContext) error {
|
||||
if ctx, ok := context.(types.SelectStreamSqlContext); ok {
|
||||
for index, arg := range o.AggregateFunc.Args {
|
||||
fieldId := arg.(*rsql.ExpressionLang).Val
|
||||
if v, ok := ctx.GetColumn(ctx.GetCurrentGroupValues(), dataset.Key(fieldId)); ok {
|
||||
ctx.AddFieldAggregateValue(ctx.GetCurrentGroupValues(), fieldId, cast.ToFloat(v))
|
||||
} else {
|
||||
if result, err := o.eval(o.ArgsProgram[index], ctx.InputAsMap()); err != nil {
|
||||
return err
|
||||
} else {
|
||||
ctx.AddColumn(ctx.GetCurrentGroupValues(), dataset.Float64(fieldId, cast.ToFloat(result)))
|
||||
ctx.AddFieldAggregateValue(ctx.GetCurrentGroupValues(), fieldId, cast.ToFloat(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddHandler 窗口添加数据事件
|
||||
func (o *AggregateOp) AddHandler(context types.StreamSqlOperatorContext, data float64) {
|
||||
fmt.Println(data)
|
||||
}
|
||||
|
||||
// ArchiveHandler 清除原始数据,观察者需要保存中间过程
|
||||
func (o *AggregateOp) ArchiveHandler(context types.StreamSqlOperatorContext, dataList []float64) {
|
||||
|
||||
}
|
||||
|
||||
// StartHandler 窗口开始事件
|
||||
func (o *AggregateOp) StartHandler(context types.StreamSqlOperatorContext) {
|
||||
|
||||
}
|
||||
|
||||
// EndHandler 窗口结束事件
|
||||
func (o *AggregateOp) EndHandler(context types.StreamSqlOperatorContext, dataList []float64) {
|
||||
if f, ok := builtin.AggregateBuiltins[o.AggregateFunc.Name]; ok {
|
||||
|
||||
fieldId := o.AggregateFunc.Args[0].(*rsql.ExpressionLang).Val
|
||||
values := context.GetFieldAggregateValue(fieldId)
|
||||
result, err := f.Func(values)
|
||||
fmt.Println(result, err)
|
||||
//o.dataList.Reset()
|
||||
}
|
||||
}
|
17
operator/alias_op.go
Normal file
17
operator/alias_op.go
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
42
operator/filter_op.go
Normal file
42
operator/filter_op.go
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
import (
|
||||
"github.com/expr-lang/expr/vm"
|
||||
types2 "github.com/rulego/streamsql/types"
|
||||
)
|
||||
|
||||
type FilterOp struct {
|
||||
BaseOp
|
||||
Program *vm.Program
|
||||
}
|
||||
|
||||
func (o *FilterOp) Init(context types2.StreamSqlContext) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *FilterOp) Apply(context types2.StreamSqlContext) error {
|
||||
if ctx, ok := context.(types2.SelectStreamSqlContext); ok {
|
||||
if result, err := o.eval(o.Program, ctx.InputAsMap()); err != nil {
|
||||
return err
|
||||
} else if !AsBool(result) {
|
||||
return types2.ErrNotMatch
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
21
operator/function_op.go
Normal file
21
operator/function_op.go
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
type FunctionOp struct {
|
||||
*BaseOp
|
||||
}
|
77
operator/group_by_op.go
Normal file
77
operator/group_by_op.go
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
import (
|
||||
"github.com/rulego/streamsql/types"
|
||||
"github.com/rulego/streamsql/utils/cast"
|
||||
)
|
||||
|
||||
//// CreateGroupByKey 创建GroupByKey
|
||||
//func CreateGroupByKey(fields ...string) GroupFields {
|
||||
// return fields
|
||||
//}
|
||||
|
||||
type GroupByOp struct {
|
||||
*BaseOp
|
||||
GroupByKey types.GroupFields
|
||||
keys []string
|
||||
}
|
||||
|
||||
func (o *GroupByOp) Init(context types.StreamSqlContext) error {
|
||||
o.keys = o.GroupByKey.ToList()
|
||||
//if selectStreamSqlContext, ok := context.(types.StreamSqlOperatorContext); ok {
|
||||
// selectStreamSqlContext.SetGroupByKey(o.GroupByKey)
|
||||
//}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *GroupByOp) Apply(context types.StreamSqlContext) error {
|
||||
if selectStreamSqlContext, ok := context.(types.SelectStreamSqlContext); ok {
|
||||
if groupValues, ok := o.getGroupValues(selectStreamSqlContext.InputAsMap()); ok {
|
||||
selectStreamSqlContext.SetCurrentGroupValues(groupValues)
|
||||
} else {
|
||||
selectStreamSqlContext.SetCurrentGroupValues(types.EmptyGroupValues)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *GroupByOp) getGroupValues(data map[string]interface{}) (types.GroupValues, bool) {
|
||||
var list []string
|
||||
for _, key := range o.keys {
|
||||
if v, ok := data[key]; ok {
|
||||
list = append(list, cast.ToString(v))
|
||||
} else {
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
return types.NewGroupValues(list...), true
|
||||
}
|
||||
|
||||
//// 检查是否是当前分组数据
|
||||
//func (o *GroupByOp) checkIsGroup(data map[string]interface{}) bool {
|
||||
// if data == nil {
|
||||
// return false
|
||||
// }
|
||||
// for _, key := range o.keys {
|
||||
// if _, ok := data[key]; ok {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// return false
|
||||
//}
|
17
operator/having_op.go
Normal file
17
operator/having_op.go
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
35
operator/limit_op.go
Normal file
35
operator/limit_op.go
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
import (
|
||||
"github.com/rulego/streamsql/rsql"
|
||||
"github.com/rulego/streamsql/types"
|
||||
)
|
||||
|
||||
type LimitOp struct {
|
||||
*BaseOp
|
||||
Limit *rsql.Limit
|
||||
}
|
||||
|
||||
func (o *LimitOp) Init(context types.StreamSqlContext) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *LimitOp) Apply(context types.StreamSqlContext) error {
|
||||
return nil
|
||||
}
|
50
operator/lookup_field_op.go
Normal file
50
operator/lookup_field_op.go
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
import (
|
||||
"github.com/expr-lang/expr/vm"
|
||||
"github.com/rulego/streamsql/types"
|
||||
)
|
||||
|
||||
type LookupFieldOp struct {
|
||||
*BaseOp
|
||||
Field EvalField
|
||||
}
|
||||
|
||||
func (o *LookupFieldOp) Init(context types.StreamSqlContext) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *LookupFieldOp) Apply(context types.StreamSqlContext) error {
|
||||
if ctx, ok := context.(types.SelectStreamSqlContext); ok {
|
||||
if o.Field.EvalProgram != nil {
|
||||
if result, err := o.eval(o.Field.EvalProgram, ctx.InputAsMap()); err == nil {
|
||||
ctx.AddField(o.Field.FieldId, result)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type EvalField struct {
|
||||
EvalProgram *vm.Program
|
||||
FieldId string
|
||||
Alias string
|
||||
}
|
37
operator/operator.go
Normal file
37
operator/operator.go
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
import (
|
||||
"github.com/expr-lang/expr"
|
||||
"github.com/expr-lang/expr/vm"
|
||||
)
|
||||
|
||||
type BaseOp struct {
|
||||
}
|
||||
|
||||
func (o *BaseOp) eval(program *vm.Program, env interface{}) (any, error) {
|
||||
return expr.Run(program, env)
|
||||
}
|
||||
|
||||
// AsBool convert any to bool
|
||||
func AsBool(input any) bool {
|
||||
if v, ok := input.(bool); ok {
|
||||
return v
|
||||
}
|
||||
return false
|
||||
}
|
35
operator/order_op.go
Normal file
35
operator/order_op.go
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
import (
|
||||
"github.com/rulego/streamsql/rsql"
|
||||
"github.com/rulego/streamsql/types"
|
||||
)
|
||||
|
||||
type OrderByOp struct {
|
||||
*BaseOp
|
||||
OrderBy []rsql.OrderByItem
|
||||
}
|
||||
|
||||
func (o *OrderByOp) Init(context types.StreamSqlContext) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OrderByOp) Apply(context types.StreamSqlContext) error {
|
||||
return nil
|
||||
}
|
35
operator/table_op.go
Normal file
35
operator/table_op.go
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
import (
|
||||
"github.com/rulego/streamsql/rsql"
|
||||
"github.com/rulego/streamsql/types"
|
||||
)
|
||||
|
||||
type TableOp struct {
|
||||
*BaseOp
|
||||
From []rsql.Expression
|
||||
}
|
||||
|
||||
func (o *TableOp) Init(context types.StreamSqlContext) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *TableOp) Apply(context types.StreamSqlContext) error {
|
||||
return nil
|
||||
}
|
51
operator/window_op.go
Normal file
51
operator/window_op.go
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
import (
|
||||
"github.com/rulego/streamsql/rsql"
|
||||
"github.com/rulego/streamsql/types"
|
||||
"github.com/rulego/streamsql/window"
|
||||
"time"
|
||||
)
|
||||
|
||||
type WindowOp struct {
|
||||
*BaseOp
|
||||
WindowType rsql.WindowType
|
||||
}
|
||||
|
||||
func (o *WindowOp) Init(context types.StreamSqlContext) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *WindowOp) Apply(context types.StreamSqlContext) error {
|
||||
if ctx, ok := context.(types.SelectStreamSqlContext); ok && !ctx.IsInitWindow(ctx.GetCurrentGroupValues()) {
|
||||
var w types.Window
|
||||
switch o.WindowType {
|
||||
case rsql.TUMBLING_WINDOW:
|
||||
w = window.NewTumblingWindow(ctx, "", 10*time.Second, ctx.CreteWindowObserver())
|
||||
case rsql.COUNT_WINDOW:
|
||||
w = window.NewCountWindow("", 100, ctx.CreteWindowObserver())
|
||||
case rsql.SLIDING_WINDOW:
|
||||
w = window.NewSlidingWindow("", 10*time.Second, 5*time.Second, ctx.CreteWindowObserver())
|
||||
case rsql.SESSION_WINDOW:
|
||||
w = window.NewSessionWindow("", 10*time.Second, ctx.CreteWindowObserver())
|
||||
}
|
||||
ctx.AddWindow(ctx.GetCurrentGroupValues(), w)
|
||||
}
|
||||
return nil
|
||||
}
|
54
planner/filter_plan.go
Normal file
54
planner/filter_plan.go
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package planner
|
||||
|
||||
import (
|
||||
"github.com/expr-lang/expr"
|
||||
"github.com/rulego/streamsql/operator"
|
||||
"github.com/rulego/streamsql/rsql"
|
||||
"github.com/rulego/streamsql/types"
|
||||
)
|
||||
|
||||
type FilterPlan struct {
|
||||
*BaseLogicalPlan
|
||||
}
|
||||
|
||||
func (p *FilterPlan) New() types.LogicalPlan {
|
||||
return &FilterPlan{BaseLogicalPlan: &BaseLogicalPlan{}}
|
||||
}
|
||||
|
||||
func (p *FilterPlan) Plan(statement rsql.Statement) error {
|
||||
if selectStatement, ok := statement.(*rsql.Select); ok {
|
||||
if expressionLang, ok := selectStatement.Where.(*rsql.ExpressionLang); ok {
|
||||
code := expressionLang.Val
|
||||
if program, err := expr.Compile(code); err != nil {
|
||||
return err
|
||||
} else {
|
||||
p.AddOperators(&operator.FilterOp{Program: program})
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *FilterPlan) Explain() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *FilterPlan) Type() string {
|
||||
return "FilterPlan"
|
||||
}
|
56
planner/group_by_plan.go
Normal file
56
planner/group_by_plan.go
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package planner
|
||||
|
||||
import (
|
||||
"github.com/rulego/streamsql/operator"
|
||||
"github.com/rulego/streamsql/rsql"
|
||||
"github.com/rulego/streamsql/types"
|
||||
)
|
||||
|
||||
type GroupByPlan struct {
|
||||
*BaseLogicalPlan
|
||||
}
|
||||
|
||||
func (p *GroupByPlan) New() types.LogicalPlan {
|
||||
return &GroupByPlan{BaseLogicalPlan: &BaseLogicalPlan{}}
|
||||
}
|
||||
|
||||
func (p *GroupByPlan) Plan(statement rsql.Statement) error {
|
||||
if selectStatement, ok := statement.(*rsql.Select); ok {
|
||||
for _, item := range selectStatement.GroupBy {
|
||||
if functionCallField, ok := item.(*rsql.FunctionCall); ok && functionCallField.IsWindow {
|
||||
p.AddOperators(&operator.WindowOp{
|
||||
WindowType: rsql.LookupIsWindowFunc(functionCallField.Name),
|
||||
})
|
||||
} else {
|
||||
p.AddOperators(&operator.GroupByOp{
|
||||
GroupByKey: types.GroupFields(item.(*rsql.Identifier).Val),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *GroupByPlan) Explain() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *GroupByPlan) Type() string {
|
||||
return "GroupByPlan"
|
||||
}
|
48
planner/limit_plan.go
Normal file
48
planner/limit_plan.go
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package planner
|
||||
|
||||
import (
|
||||
"github.com/rulego/streamsql/operator"
|
||||
"github.com/rulego/streamsql/rsql"
|
||||
"github.com/rulego/streamsql/types"
|
||||
)
|
||||
|
||||
type LimitPlan struct {
|
||||
*BaseLogicalPlan
|
||||
}
|
||||
|
||||
func (p *LimitPlan) New() types.LogicalPlan {
|
||||
return &LimitPlan{BaseLogicalPlan: &BaseLogicalPlan{}}
|
||||
}
|
||||
|
||||
func (p *LimitPlan) Plan(statement rsql.Statement) error {
|
||||
if selectStatement, ok := statement.(*rsql.Select); ok {
|
||||
p.AddOperators(&operator.LimitOp{
|
||||
Limit: selectStatement.Limit,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *LimitPlan) Explain() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *LimitPlan) Type() string {
|
||||
return "LimitPlan"
|
||||
}
|
93
planner/look_field_plan.go
Normal file
93
planner/look_field_plan.go
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package planner
|
||||
|
||||
import (
|
||||
"github.com/expr-lang/expr"
|
||||
"github.com/expr-lang/expr/vm"
|
||||
"github.com/rulego/streamsql/operator"
|
||||
"github.com/rulego/streamsql/rsql"
|
||||
"github.com/rulego/streamsql/types"
|
||||
)
|
||||
|
||||
type LookFieldPlan struct {
|
||||
*BaseLogicalPlan
|
||||
}
|
||||
|
||||
func (p *LookFieldPlan) New() types.LogicalPlan {
|
||||
return &LookFieldPlan{BaseLogicalPlan: &BaseLogicalPlan{}}
|
||||
}
|
||||
|
||||
func (p *LookFieldPlan) Plan(statement rsql.Statement) error {
|
||||
if selectStatement, ok := statement.(*rsql.Select); ok {
|
||||
for _, field := range selectStatement.SelectExprs {
|
||||
if functionCallField, ok := field.Expr.(*rsql.FunctionCall); ok && functionCallField.IsAggregate {
|
||||
if len(functionCallField.Args) > 0 {
|
||||
code, ok := functionCallField.Args[0].(*rsql.ExpressionLang)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if program, err := expr.Compile(code.Val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
//p.AddOperators(&operator.LookupFieldOp{
|
||||
// Field: operator.EvalField{
|
||||
// EvalProgram: program,
|
||||
// FieldId: code.Val,
|
||||
// },
|
||||
//})
|
||||
p.AddOperators(&operator.AggregateOp{
|
||||
AggregateFunc: functionCallField,
|
||||
ArgsProgram: []*vm.Program{program},
|
||||
})
|
||||
}
|
||||
|
||||
} else {
|
||||
p.AddOperators(&operator.AggregateOp{
|
||||
AggregateFunc: functionCallField,
|
||||
})
|
||||
}
|
||||
|
||||
} else {
|
||||
code, ok := field.Expr.(*rsql.Identifier)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if program, err := expr.Compile(code.Val); err != nil {
|
||||
return err
|
||||
} else {
|
||||
p.AddOperators(&operator.LookupFieldOp{
|
||||
Field: operator.EvalField{
|
||||
EvalProgram: program,
|
||||
FieldId: code.Val,
|
||||
Alias: field.Alias,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *LookFieldPlan) Explain() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *LookFieldPlan) Type() string {
|
||||
return "LookFieldPlan"
|
||||
}
|
26
planner/optimizer.go
Normal file
26
planner/optimizer.go
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2024 The RuleGo Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package planner
|
||||
|
||||
import (
|
||||
"github.com/rulego/streamsql/types"
|
||||
)
|
||||
|
||||
// Optimize 优化
|
||||
func Optimize(p types.LogicalPlan) (types.LogicalPlan, error) {
|
||||
return p, nil
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user