This commit is contained in:
rulego-team
2024-01-19 18:09:21 +08:00
parent 89c848cf0a
commit af0c5c6ca8
56 changed files with 5356 additions and 0 deletions

48
.gitignore vendored Normal file
View 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
View 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
View 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)
}

View 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
View 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)
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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"
}

View 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
View 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