Add support for subqueries

This commit is contained in:
Pijus Kamandulis 2024-12-07 22:29:26 +02:00
parent 3584f9b5ce
commit 66ea859f34
15 changed files with 3227 additions and 2290 deletions

View File

@ -111,7 +111,7 @@ func ExecuteQueryDocuments(databaseId string, collectionId string, query string,
if typedQuery, ok := parsedQuery.(parsers.SelectStmt); ok { if typedQuery, ok := parsedQuery.(parsers.SelectStmt); ok {
typedQuery.Parameters = queryParameters typedQuery.Parameters = queryParameters
return memoryexecutor.Execute(typedQuery, covDocs), repositorymodels.StatusOk return memoryexecutor.ExecuteQuery(typedQuery, covDocs), repositorymodels.StatusOk
} }
return nil, repositorymodels.BadRequest return nil, repositorymodels.BadRequest

View File

@ -5,6 +5,7 @@ type SelectStmt struct {
Table Table Table Table
JoinItems []JoinItem JoinItems []JoinItem
Filters interface{} Filters interface{}
Exists bool
Distinct bool Distinct bool
Count int Count int
Offset int Offset int
@ -14,7 +15,8 @@ type SelectStmt struct {
} }
type Table struct { type Table struct {
Value string Value string
SelectItem SelectItem
} }
type JoinItem struct { type JoinItem struct {
@ -30,6 +32,7 @@ const (
SelectItemTypeArray SelectItemTypeArray
SelectItemTypeConstant SelectItemTypeConstant
SelectItemTypeFunctionCall SelectItemTypeFunctionCall
SelectItemTypeSubQuery
) )
type SelectItem struct { type SelectItem struct {

View File

@ -122,4 +122,25 @@ func Test_Parse(t *testing.T) {
}, },
) )
}) })
t.Run("Should parse IN selector", func(t *testing.T) {
testQueryParse(
t,
`SELECT c.id FROM c IN c.tags`,
parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{
Path: []string{"c", "id"},
Type: parsers.SelectItemTypeField,
},
},
Table: parsers.Table{
Value: "c",
SelectItem: parsers.SelectItem{
Path: []string{"c", "tags"},
},
},
},
)
})
} }

File diff suppressed because it is too large Load Diff

View File

@ -4,16 +4,19 @@ package nosql
import "github.com/pikami/cosmium/parsers" import "github.com/pikami/cosmium/parsers"
func makeSelectStmt( func makeSelectStmt(
columns, table, joinItems, columns, fromClause, joinItems,
whereClause interface{}, distinctClause interface{}, whereClause interface{}, distinctClause interface{},
count interface{}, groupByClause interface{}, orderList interface{}, count interface{}, groupByClause interface{}, orderList interface{},
offsetClause interface{}, offsetClause interface{},
) (parsers.SelectStmt, error) { ) (parsers.SelectStmt, error) {
selectStmt := parsers.SelectStmt{ selectStmt := parsers.SelectStmt{
SelectItems: columns.([]parsers.SelectItem), SelectItems: columns.([]parsers.SelectItem),
Table: table.(parsers.Table),
} }
if fromTable, ok := fromClause.(parsers.Table); ok {
selectStmt.Table = fromTable
}
if joinItemsArray, ok := joinItems.([]interface{}); ok && len(joinItemsArray) > 0 { if joinItemsArray, ok := joinItems.([]interface{}); ok && len(joinItemsArray) > 0 {
selectStmt.JoinItems = make([]parsers.JoinItem, len(joinItemsArray)) selectStmt.JoinItems = make([]parsers.JoinItem, len(joinItemsArray))
for i, joinItem := range joinItemsArray { for i, joinItem := range joinItemsArray {
@ -56,10 +59,18 @@ func makeSelectStmt(
} }
func makeJoin(table interface{}, column interface{}) (parsers.JoinItem, error) { func makeJoin(table interface{}, column interface{}) (parsers.JoinItem, error) {
return parsers.JoinItem{ joinItem := parsers.JoinItem{}
Table: table.(parsers.Table),
SelectItem: column.(parsers.SelectItem), if selectItem, isSelectItem := column.(parsers.SelectItem); isSelectItem {
}, nil joinItem.SelectItem = selectItem
joinItem.Table.Value = selectItem.Alias
}
if tableTyped, isTable := table.(parsers.Table); isTable {
joinItem.Table = tableTyped
}
return joinItem, nil
} }
func makeSelectItem(name interface{}, path interface{}, selectItemType parsers.SelectItemType) (parsers.SelectItem, error) { func makeSelectItem(name interface{}, path interface{}, selectItemType parsers.SelectItemType) (parsers.SelectItem, error) {
@ -177,13 +188,13 @@ SelectStmt <- Select ws
distinctClause:DistinctClause? ws distinctClause:DistinctClause? ws
topClause:TopClause? ws topClause:TopClause? ws
columns:Selection ws columns:Selection ws
From ws table:TableName ws fromClause:FromClause? ws
joinClauses:JoinClause* ws joinClauses:(ws join:JoinClause { return join, nil })* ws
whereClause:(ws Where ws condition:Condition { return condition, nil })? whereClause:(ws Where ws condition:Condition { return condition, nil })?
groupByClause:(ws GroupBy ws columns:ColumnList { return columns, nil })? groupByClause:(ws GroupBy ws columns:ColumnList { return columns, nil })?
orderByClause:OrderByClause? orderByClause:(ws order:OrderByClause { return order, nil })?
offsetClause:OffsetClause? { offsetClause:(ws offset:OffsetClause { return offset, nil })? {
return makeSelectStmt(columns, table, joinClauses, whereClause, return makeSelectStmt(columns, fromClause, joinClauses, whereClause,
distinctClause, topClause, groupByClause, orderByClause, offsetClause) distinctClause, topClause, groupByClause, orderByClause, offsetClause)
} }
@ -193,8 +204,49 @@ TopClause <- Top ws count:Integer {
return count, nil return count, nil
} }
FromClause <- From ws table:TableName selectItem:(ws "IN"i ws column:SelectItem { return column, nil })? {
tableTyped := table.(parsers.Table)
if selectItem != nil {
tableTyped.SelectItem = selectItem.(parsers.SelectItem)
}
return tableTyped, nil
} / From ws subQuery:SubQuerySelectItem {
subQueryTyped := subQuery.(parsers.SelectItem)
table := parsers.Table{
Value: subQueryTyped.Alias,
SelectItem: subQueryTyped,
}
return table, nil
}
SubQuery <- exists:(exists:Exists ws { return exists, nil })? "(" ws selectStmt:SelectStmt ws ")" {
if selectStatement, isGoodValue := selectStmt.(parsers.SelectStmt); isGoodValue {
selectStatement.Exists = exists != nil
return selectStatement, nil
}
return selectStmt, nil
}
SubQuerySelectItem <- subQuery:SubQuery asClause:(ws alias:AsClause { return alias, nil })? {
selectItem := parsers.SelectItem{
Type: parsers.SelectItemTypeSubQuery,
Value: subQuery,
}
if tableName, isString := asClause.(string); isString {
selectItem.Alias = tableName
}
return selectItem, nil
}
JoinClause <- Join ws table:TableName ws "IN"i ws column:SelectItem { JoinClause <- Join ws table:TableName ws "IN"i ws column:SelectItem {
return makeJoin(table, column) return makeJoin(table, column)
} / Join ws subQuery:SubQuerySelectItem {
return makeJoin(nil, subQuery)
} }
OffsetClause <- "OFFSET"i ws offset:IntegerLiteral ws "LIMIT"i ws limit:IntegerLiteral { OffsetClause <- "OFFSET"i ws offset:IntegerLiteral ws "LIMIT"i ws limit:IntegerLiteral {
@ -241,7 +293,7 @@ SelectProperty <- name:Identifier path:(DotFieldAccess / ArrayFieldAccess)* {
return makeSelectItem(name, path, parsers.SelectItemTypeField) return makeSelectItem(name, path, parsers.SelectItemTypeField)
} }
SelectItem <- selectItem:(Literal / FunctionCall / SelectArray / SelectObject / SelectProperty) asClause:AsClause? { SelectItem <- selectItem:(SubQuerySelectItem / Literal / FunctionCall / SelectArray / SelectObject / SelectProperty) asClause:AsClause? {
var itemResult parsers.SelectItem var itemResult parsers.SelectItem
switch typedValue := selectItem.(type) { switch typedValue := selectItem.(type) {
case parsers.SelectItem: case parsers.SelectItem:
@ -322,11 +374,13 @@ From <- "FROM"i
Join <- "JOIN"i Join <- "JOIN"i
Exists <- "EXISTS"i
Where <- "WHERE"i Where <- "WHERE"i
And <- "AND"i And <- "AND"i
Or <- "OR"i Or <- "OR"i wss
GroupBy <- "GROUP"i ws "BY"i GroupBy <- "GROUP"i ws "BY"i
@ -677,4 +731,6 @@ non_escape_character <- !(escape_character) char:.
ws <- [ \t\n\r]* ws <- [ \t\n\r]*
wss <- [ \t\n\r]+
EOF <- !. EOF <- !.

View File

@ -0,0 +1,125 @@
package nosql_test
import (
"testing"
"github.com/pikami/cosmium/parsers"
)
func Test_Parse_SubQuery(t *testing.T) {
t.Run("Should parse FROM subquery", func(t *testing.T) {
testQueryParse(
t,
`SELECT c.id FROM (SELECT VALUE cc["info"] FROM cc) AS c`,
parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{Path: []string{"c", "id"}},
},
Table: parsers.Table{
Value: "c",
SelectItem: parsers.SelectItem{
Alias: "c",
Type: parsers.SelectItemTypeSubQuery,
Value: parsers.SelectStmt{
Table: parsers.Table{Value: "cc"},
SelectItems: []parsers.SelectItem{
{Path: []string{"cc", "info"}, IsTopLevel: true},
},
},
},
},
},
)
})
t.Run("Should parse JOIN subquery", func(t *testing.T) {
testQueryParse(
t,
`SELECT c.id, cc.name FROM c JOIN (SELECT tag.name FROM tag IN c.tags) AS cc`,
parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{Path: []string{"c", "id"}},
{Path: []string{"cc", "name"}},
},
Table: parsers.Table{
Value: "c",
},
JoinItems: []parsers.JoinItem{
{
Table: parsers.Table{
Value: "cc",
},
SelectItem: parsers.SelectItem{
Alias: "cc",
Type: parsers.SelectItemTypeSubQuery,
Value: parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{Path: []string{"tag", "name"}},
},
Table: parsers.Table{
Value: "tag",
SelectItem: parsers.SelectItem{
Path: []string{"c", "tags"},
},
},
},
},
},
},
},
)
})
t.Run("Should parse JOIN EXISTS subquery", func(t *testing.T) {
testQueryParse(
t,
`SELECT c.id
FROM c
JOIN (
SELECT VALUE EXISTS(SELECT tag.name FROM tag IN c.tags)
) AS hasTags
WHERE hasTags`,
parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{Path: []string{"c", "id"}},
},
Table: parsers.Table{
Value: "c",
},
JoinItems: []parsers.JoinItem{
{
Table: parsers.Table{Value: "hasTags"},
SelectItem: parsers.SelectItem{
Alias: "hasTags",
Type: parsers.SelectItemTypeSubQuery,
Value: parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{
IsTopLevel: true,
Type: parsers.SelectItemTypeSubQuery,
Value: parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{Path: []string{"tag", "name"}},
},
Table: parsers.Table{
Value: "tag",
SelectItem: parsers.SelectItem{
Path: []string{"c", "tags"},
},
},
Exists: true,
},
},
},
},
},
},
},
Filters: parsers.SelectItem{
Path: []string{"hasTags"},
},
},
)
})
}

View File

@ -6,21 +6,19 @@ import (
"github.com/pikami/cosmium/parsers" "github.com/pikami/cosmium/parsers"
) )
func (c memoryExecutorContext) aggregate_Avg(arguments []interface{}, row RowType) interface{} { func (r rowContext) aggregate_Avg(arguments []interface{}) interface{} {
selectExpression := arguments[0].(parsers.SelectItem) selectExpression := arguments[0].(parsers.SelectItem)
sum := 0.0 sum := 0.0
count := 0 count := 0
if array, isArray := row.([]RowWithJoins); isArray { for _, item := range r.grouppedRows {
for _, item := range array { value := item.resolveSelectItem(selectExpression)
value := c.getFieldValue(selectExpression, item) if numericValue, ok := value.(float64); ok {
if numericValue, ok := value.(float64); ok { sum += numericValue
sum += numericValue count++
count++ } else if numericValue, ok := value.(int); ok {
} else if numericValue, ok := value.(int); ok { sum += float64(numericValue)
sum += float64(numericValue) count++
count++
}
} }
} }
@ -31,41 +29,37 @@ func (c memoryExecutorContext) aggregate_Avg(arguments []interface{}, row RowTyp
} }
} }
func (c memoryExecutorContext) aggregate_Count(arguments []interface{}, row RowType) interface{} { func (r rowContext) aggregate_Count(arguments []interface{}) interface{} {
selectExpression := arguments[0].(parsers.SelectItem) selectExpression := arguments[0].(parsers.SelectItem)
count := 0 count := 0
if array, isArray := row.([]RowWithJoins); isArray { for _, item := range r.grouppedRows {
for _, item := range array { value := item.resolveSelectItem(selectExpression)
value := c.getFieldValue(selectExpression, item) if value != nil {
if value != nil { count++
count++
}
} }
} }
return count return count
} }
func (c memoryExecutorContext) aggregate_Max(arguments []interface{}, row RowType) interface{} { func (r rowContext) aggregate_Max(arguments []interface{}) interface{} {
selectExpression := arguments[0].(parsers.SelectItem) selectExpression := arguments[0].(parsers.SelectItem)
max := 0.0 max := 0.0
count := 0 count := 0
if array, isArray := row.([]RowWithJoins); isArray { for _, item := range r.grouppedRows {
for _, item := range array { value := item.resolveSelectItem(selectExpression)
value := c.getFieldValue(selectExpression, item) if numericValue, ok := value.(float64); ok {
if numericValue, ok := value.(float64); ok { if numericValue > max {
if numericValue > max { max = numericValue
max = numericValue
}
count++
} else if numericValue, ok := value.(int); ok {
if float64(numericValue) > max {
max = float64(numericValue)
}
count++
} }
count++
} else if numericValue, ok := value.(int); ok {
if float64(numericValue) > max {
max = float64(numericValue)
}
count++
} }
} }
@ -76,25 +70,23 @@ func (c memoryExecutorContext) aggregate_Max(arguments []interface{}, row RowTyp
} }
} }
func (c memoryExecutorContext) aggregate_Min(arguments []interface{}, row RowType) interface{} { func (r rowContext) aggregate_Min(arguments []interface{}) interface{} {
selectExpression := arguments[0].(parsers.SelectItem) selectExpression := arguments[0].(parsers.SelectItem)
min := math.MaxFloat64 min := math.MaxFloat64
count := 0 count := 0
if array, isArray := row.([]RowWithJoins); isArray { for _, item := range r.grouppedRows {
for _, item := range array { value := item.resolveSelectItem(selectExpression)
value := c.getFieldValue(selectExpression, item) if numericValue, ok := value.(float64); ok {
if numericValue, ok := value.(float64); ok { if numericValue < min {
if numericValue < min { min = numericValue
min = numericValue
}
count++
} else if numericValue, ok := value.(int); ok {
if float64(numericValue) < min {
min = float64(numericValue)
}
count++
} }
count++
} else if numericValue, ok := value.(int); ok {
if float64(numericValue) < min {
min = float64(numericValue)
}
count++
} }
} }
@ -105,21 +97,19 @@ func (c memoryExecutorContext) aggregate_Min(arguments []interface{}, row RowTyp
} }
} }
func (c memoryExecutorContext) aggregate_Sum(arguments []interface{}, row RowType) interface{} { func (r rowContext) aggregate_Sum(arguments []interface{}) interface{} {
selectExpression := arguments[0].(parsers.SelectItem) selectExpression := arguments[0].(parsers.SelectItem)
sum := 0.0 sum := 0.0
count := 0 count := 0
if array, isArray := row.([]RowWithJoins); isArray { for _, item := range r.grouppedRows {
for _, item := range array { value := item.resolveSelectItem(selectExpression)
value := c.getFieldValue(selectExpression, item) if numericValue, ok := value.(float64); ok {
if numericValue, ok := value.(float64); ok { sum += numericValue
sum += numericValue count++
count++ } else if numericValue, ok := value.(int); ok {
} else if numericValue, ok := value.(int); ok { sum += float64(numericValue)
sum += float64(numericValue) count++
count++
}
} }
} }

View File

@ -7,17 +7,17 @@ import (
"github.com/pikami/cosmium/parsers" "github.com/pikami/cosmium/parsers"
) )
func (c memoryExecutorContext) array_Concat(arguments []interface{}, row RowType) []interface{} { func (r rowContext) array_Concat(arguments []interface{}) []interface{} {
var result []interface{} var result []interface{}
for _, arg := range arguments { for _, arg := range arguments {
array := c.parseArray(arg, row) array := r.parseArray(arg)
result = append(result, array...) result = append(result, array...)
} }
return result return result
} }
func (c memoryExecutorContext) array_Length(arguments []interface{}, row RowType) int { func (r rowContext) array_Length(arguments []interface{}) int {
array := c.parseArray(arguments[0], row) array := r.parseArray(arguments[0])
if array == nil { if array == nil {
return 0 return 0
} }
@ -25,15 +25,15 @@ func (c memoryExecutorContext) array_Length(arguments []interface{}, row RowType
return len(array) return len(array)
} }
func (c memoryExecutorContext) array_Slice(arguments []interface{}, row RowType) []interface{} { func (r rowContext) array_Slice(arguments []interface{}) []interface{} {
var ok bool var ok bool
var start int var start int
var length int var length int
array := c.parseArray(arguments[0], row) array := r.parseArray(arguments[0])
startEx := c.getFieldValue(arguments[1].(parsers.SelectItem), row) startEx := r.resolveSelectItem(arguments[1].(parsers.SelectItem))
if arguments[2] != nil { if arguments[2] != nil {
lengthEx := c.getFieldValue(arguments[2].(parsers.SelectItem), row) lengthEx := r.resolveSelectItem(arguments[2].(parsers.SelectItem))
if length, ok = lengthEx.(int); !ok { if length, ok = lengthEx.(int); !ok {
logger.Error("array_Slice - got length parameters of wrong type") logger.Error("array_Slice - got length parameters of wrong type")
@ -65,9 +65,9 @@ func (c memoryExecutorContext) array_Slice(arguments []interface{}, row RowType)
return array[start:end] return array[start:end]
} }
func (c memoryExecutorContext) set_Intersect(arguments []interface{}, row RowType) []interface{} { func (r rowContext) set_Intersect(arguments []interface{}) []interface{} {
set1 := c.parseArray(arguments[0], row) set1 := r.parseArray(arguments[0])
set2 := c.parseArray(arguments[1], row) set2 := r.parseArray(arguments[1])
intersection := make(map[interface{}]struct{}) intersection := make(map[interface{}]struct{})
if set1 == nil || set2 == nil { if set1 == nil || set2 == nil {
@ -88,9 +88,9 @@ func (c memoryExecutorContext) set_Intersect(arguments []interface{}, row RowTyp
return result return result
} }
func (c memoryExecutorContext) set_Union(arguments []interface{}, row RowType) []interface{} { func (r rowContext) set_Union(arguments []interface{}) []interface{} {
set1 := c.parseArray(arguments[0], row) set1 := r.parseArray(arguments[0])
set2 := c.parseArray(arguments[1], row) set2 := r.parseArray(arguments[1])
var result []interface{} var result []interface{}
union := make(map[interface{}]struct{}) union := make(map[interface{}]struct{})
@ -111,9 +111,9 @@ func (c memoryExecutorContext) set_Union(arguments []interface{}, row RowType) [
return result return result
} }
func (c memoryExecutorContext) parseArray(argument interface{}, row RowType) []interface{} { func (r rowContext) parseArray(argument interface{}) []interface{} {
exItem := argument.(parsers.SelectItem) exItem := argument.(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
arrValue := reflect.ValueOf(ex) arrValue := reflect.ValueOf(ex)
if arrValue.Kind() != reflect.Slice { if arrValue.Kind() != reflect.Slice {

View File

@ -8,9 +8,9 @@ import (
"github.com/pikami/cosmium/parsers" "github.com/pikami/cosmium/parsers"
) )
func (c memoryExecutorContext) math_Abs(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Abs(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
switch val := ex.(type) { switch val := ex.(type) {
case float64: case float64:
@ -26,9 +26,9 @@ func (c memoryExecutorContext) math_Abs(arguments []interface{}, row RowType) in
} }
} }
func (c memoryExecutorContext) math_Acos(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Acos(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
val, valIsNumber := numToFloat64(ex) val, valIsNumber := numToFloat64(ex)
if !valIsNumber { if !valIsNumber {
@ -44,9 +44,9 @@ func (c memoryExecutorContext) math_Acos(arguments []interface{}, row RowType) i
return math.Acos(val) * 180 / math.Pi return math.Acos(val) * 180 / math.Pi
} }
func (c memoryExecutorContext) math_Asin(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Asin(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
val, valIsNumber := numToFloat64(ex) val, valIsNumber := numToFloat64(ex)
if !valIsNumber { if !valIsNumber {
@ -62,9 +62,9 @@ func (c memoryExecutorContext) math_Asin(arguments []interface{}, row RowType) i
return math.Asin(val) * 180 / math.Pi return math.Asin(val) * 180 / math.Pi
} }
func (c memoryExecutorContext) math_Atan(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Atan(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
val, valIsNumber := numToFloat64(ex) val, valIsNumber := numToFloat64(ex)
if !valIsNumber { if !valIsNumber {
@ -75,9 +75,9 @@ func (c memoryExecutorContext) math_Atan(arguments []interface{}, row RowType) i
return math.Atan(val) * 180 / math.Pi return math.Atan(val) * 180 / math.Pi
} }
func (c memoryExecutorContext) math_Ceiling(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Ceiling(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
switch val := ex.(type) { switch val := ex.(type) {
case float64: case float64:
@ -90,9 +90,9 @@ func (c memoryExecutorContext) math_Ceiling(arguments []interface{}, row RowType
} }
} }
func (c memoryExecutorContext) math_Cos(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Cos(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
val, valIsNumber := numToFloat64(ex) val, valIsNumber := numToFloat64(ex)
if !valIsNumber { if !valIsNumber {
@ -103,9 +103,9 @@ func (c memoryExecutorContext) math_Cos(arguments []interface{}, row RowType) in
return math.Cos(val) return math.Cos(val)
} }
func (c memoryExecutorContext) math_Cot(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Cot(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
val, valIsNumber := numToFloat64(ex) val, valIsNumber := numToFloat64(ex)
if !valIsNumber { if !valIsNumber {
@ -121,9 +121,9 @@ func (c memoryExecutorContext) math_Cot(arguments []interface{}, row RowType) in
return 1 / math.Tan(val) return 1 / math.Tan(val)
} }
func (c memoryExecutorContext) math_Degrees(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Degrees(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
val, valIsNumber := numToFloat64(ex) val, valIsNumber := numToFloat64(ex)
if !valIsNumber { if !valIsNumber {
@ -134,9 +134,9 @@ func (c memoryExecutorContext) math_Degrees(arguments []interface{}, row RowType
return val * (180 / math.Pi) return val * (180 / math.Pi)
} }
func (c memoryExecutorContext) math_Exp(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Exp(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
val, valIsNumber := numToFloat64(ex) val, valIsNumber := numToFloat64(ex)
if !valIsNumber { if !valIsNumber {
@ -147,9 +147,9 @@ func (c memoryExecutorContext) math_Exp(arguments []interface{}, row RowType) in
return math.Exp(val) return math.Exp(val)
} }
func (c memoryExecutorContext) math_Floor(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Floor(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
switch val := ex.(type) { switch val := ex.(type) {
case float64: case float64:
@ -162,9 +162,9 @@ func (c memoryExecutorContext) math_Floor(arguments []interface{}, row RowType)
} }
} }
func (c memoryExecutorContext) math_IntBitNot(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_IntBitNot(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
switch val := ex.(type) { switch val := ex.(type) {
case int: case int:
@ -175,9 +175,9 @@ func (c memoryExecutorContext) math_IntBitNot(arguments []interface{}, row RowTy
} }
} }
func (c memoryExecutorContext) math_Log10(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Log10(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
val, valIsNumber := numToFloat64(ex) val, valIsNumber := numToFloat64(ex)
if !valIsNumber { if !valIsNumber {
@ -193,9 +193,9 @@ func (c memoryExecutorContext) math_Log10(arguments []interface{}, row RowType)
return math.Log10(val) return math.Log10(val)
} }
func (c memoryExecutorContext) math_Radians(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Radians(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
val, valIsNumber := numToFloat64(ex) val, valIsNumber := numToFloat64(ex)
if !valIsNumber { if !valIsNumber {
@ -206,9 +206,9 @@ func (c memoryExecutorContext) math_Radians(arguments []interface{}, row RowType
return val * (math.Pi / 180.0) return val * (math.Pi / 180.0)
} }
func (c memoryExecutorContext) math_Round(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Round(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
switch val := ex.(type) { switch val := ex.(type) {
case float64: case float64:
@ -221,9 +221,9 @@ func (c memoryExecutorContext) math_Round(arguments []interface{}, row RowType)
} }
} }
func (c memoryExecutorContext) math_Sign(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Sign(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
switch val := ex.(type) { switch val := ex.(type) {
case float64: case float64:
@ -248,9 +248,9 @@ func (c memoryExecutorContext) math_Sign(arguments []interface{}, row RowType) i
} }
} }
func (c memoryExecutorContext) math_Sin(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Sin(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
val, valIsNumber := numToFloat64(ex) val, valIsNumber := numToFloat64(ex)
if !valIsNumber { if !valIsNumber {
@ -261,9 +261,9 @@ func (c memoryExecutorContext) math_Sin(arguments []interface{}, row RowType) in
return math.Sin(val) return math.Sin(val)
} }
func (c memoryExecutorContext) math_Sqrt(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Sqrt(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
val, valIsNumber := numToFloat64(ex) val, valIsNumber := numToFloat64(ex)
if !valIsNumber { if !valIsNumber {
@ -274,9 +274,9 @@ func (c memoryExecutorContext) math_Sqrt(arguments []interface{}, row RowType) i
return math.Sqrt(val) return math.Sqrt(val)
} }
func (c memoryExecutorContext) math_Square(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Square(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
val, valIsNumber := numToFloat64(ex) val, valIsNumber := numToFloat64(ex)
if !valIsNumber { if !valIsNumber {
@ -287,9 +287,9 @@ func (c memoryExecutorContext) math_Square(arguments []interface{}, row RowType)
return math.Pow(val, 2) return math.Pow(val, 2)
} }
func (c memoryExecutorContext) math_Tan(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Tan(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
val, valIsNumber := numToFloat64(ex) val, valIsNumber := numToFloat64(ex)
if !valIsNumber { if !valIsNumber {
@ -300,9 +300,9 @@ func (c memoryExecutorContext) math_Tan(arguments []interface{}, row RowType) in
return math.Tan(val) return math.Tan(val)
} }
func (c memoryExecutorContext) math_Trunc(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Trunc(arguments []interface{}) interface{} {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
switch val := ex.(type) { switch val := ex.(type) {
case float64: case float64:
@ -315,11 +315,11 @@ func (c memoryExecutorContext) math_Trunc(arguments []interface{}, row RowType)
} }
} }
func (c memoryExecutorContext) math_Atn2(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Atn2(arguments []interface{}) interface{} {
exItem1 := arguments[0].(parsers.SelectItem) exItem1 := arguments[0].(parsers.SelectItem)
exItem2 := arguments[1].(parsers.SelectItem) exItem2 := arguments[1].(parsers.SelectItem)
ex1 := c.getFieldValue(exItem1, row) ex1 := r.resolveSelectItem(exItem1)
ex2 := c.getFieldValue(exItem2, row) ex2 := r.resolveSelectItem(exItem2)
y, yIsNumber := numToFloat64(ex1) y, yIsNumber := numToFloat64(ex1)
x, xIsNumber := numToFloat64(ex2) x, xIsNumber := numToFloat64(ex2)
@ -332,11 +332,11 @@ func (c memoryExecutorContext) math_Atn2(arguments []interface{}, row RowType) i
return math.Atan2(y, x) return math.Atan2(y, x)
} }
func (c memoryExecutorContext) math_IntAdd(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_IntAdd(arguments []interface{}) interface{} {
exItem1 := arguments[0].(parsers.SelectItem) exItem1 := arguments[0].(parsers.SelectItem)
exItem2 := arguments[1].(parsers.SelectItem) exItem2 := arguments[1].(parsers.SelectItem)
ex1 := c.getFieldValue(exItem1, row) ex1 := r.resolveSelectItem(exItem1)
ex2 := c.getFieldValue(exItem2, row) ex2 := r.resolveSelectItem(exItem2)
ex1Number, ex1IsNumber := numToInt(ex1) ex1Number, ex1IsNumber := numToInt(ex1)
ex2Number, ex2IsNumber := numToInt(ex2) ex2Number, ex2IsNumber := numToInt(ex2)
@ -349,11 +349,11 @@ func (c memoryExecutorContext) math_IntAdd(arguments []interface{}, row RowType)
return ex1Number + ex2Number return ex1Number + ex2Number
} }
func (c memoryExecutorContext) math_IntBitAnd(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_IntBitAnd(arguments []interface{}) interface{} {
exItem1 := arguments[0].(parsers.SelectItem) exItem1 := arguments[0].(parsers.SelectItem)
exItem2 := arguments[1].(parsers.SelectItem) exItem2 := arguments[1].(parsers.SelectItem)
ex1 := c.getFieldValue(exItem1, row) ex1 := r.resolveSelectItem(exItem1)
ex2 := c.getFieldValue(exItem2, row) ex2 := r.resolveSelectItem(exItem2)
ex1Int, ex1IsInt := numToInt(ex1) ex1Int, ex1IsInt := numToInt(ex1)
ex2Int, ex2IsInt := numToInt(ex2) ex2Int, ex2IsInt := numToInt(ex2)
@ -366,11 +366,11 @@ func (c memoryExecutorContext) math_IntBitAnd(arguments []interface{}, row RowTy
return ex1Int & ex2Int return ex1Int & ex2Int
} }
func (c memoryExecutorContext) math_IntBitLeftShift(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_IntBitLeftShift(arguments []interface{}) interface{} {
exItem1 := arguments[0].(parsers.SelectItem) exItem1 := arguments[0].(parsers.SelectItem)
exItem2 := arguments[1].(parsers.SelectItem) exItem2 := arguments[1].(parsers.SelectItem)
ex1 := c.getFieldValue(exItem1, row) ex1 := r.resolveSelectItem(exItem1)
ex2 := c.getFieldValue(exItem2, row) ex2 := r.resolveSelectItem(exItem2)
num1, num1IsInt := numToInt(ex1) num1, num1IsInt := numToInt(ex1)
num2, num2IsInt := numToInt(ex2) num2, num2IsInt := numToInt(ex2)
@ -383,11 +383,11 @@ func (c memoryExecutorContext) math_IntBitLeftShift(arguments []interface{}, row
return num1 << uint(num2) return num1 << uint(num2)
} }
func (c memoryExecutorContext) math_IntBitOr(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_IntBitOr(arguments []interface{}) interface{} {
exItem1 := arguments[0].(parsers.SelectItem) exItem1 := arguments[0].(parsers.SelectItem)
exItem2 := arguments[1].(parsers.SelectItem) exItem2 := arguments[1].(parsers.SelectItem)
ex1 := c.getFieldValue(exItem1, row) ex1 := r.resolveSelectItem(exItem1)
ex2 := c.getFieldValue(exItem2, row) ex2 := r.resolveSelectItem(exItem2)
num1, num1IsInt := ex1.(int) num1, num1IsInt := ex1.(int)
num2, num2IsInt := ex2.(int) num2, num2IsInt := ex2.(int)
@ -400,11 +400,11 @@ func (c memoryExecutorContext) math_IntBitOr(arguments []interface{}, row RowTyp
return num1 | num2 return num1 | num2
} }
func (c memoryExecutorContext) math_IntBitRightShift(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_IntBitRightShift(arguments []interface{}) interface{} {
exItem1 := arguments[0].(parsers.SelectItem) exItem1 := arguments[0].(parsers.SelectItem)
exItem2 := arguments[1].(parsers.SelectItem) exItem2 := arguments[1].(parsers.SelectItem)
ex1 := c.getFieldValue(exItem1, row) ex1 := r.resolveSelectItem(exItem1)
ex2 := c.getFieldValue(exItem2, row) ex2 := r.resolveSelectItem(exItem2)
num1, num1IsInt := numToInt(ex1) num1, num1IsInt := numToInt(ex1)
num2, num2IsInt := numToInt(ex2) num2, num2IsInt := numToInt(ex2)
@ -417,11 +417,11 @@ func (c memoryExecutorContext) math_IntBitRightShift(arguments []interface{}, ro
return num1 >> uint(num2) return num1 >> uint(num2)
} }
func (c memoryExecutorContext) math_IntBitXor(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_IntBitXor(arguments []interface{}) interface{} {
exItem1 := arguments[0].(parsers.SelectItem) exItem1 := arguments[0].(parsers.SelectItem)
exItem2 := arguments[1].(parsers.SelectItem) exItem2 := arguments[1].(parsers.SelectItem)
ex1 := c.getFieldValue(exItem1, row) ex1 := r.resolveSelectItem(exItem1)
ex2 := c.getFieldValue(exItem2, row) ex2 := r.resolveSelectItem(exItem2)
num1, num1IsInt := ex1.(int) num1, num1IsInt := ex1.(int)
num2, num2IsInt := ex2.(int) num2, num2IsInt := ex2.(int)
@ -434,11 +434,11 @@ func (c memoryExecutorContext) math_IntBitXor(arguments []interface{}, row RowTy
return num1 ^ num2 return num1 ^ num2
} }
func (c memoryExecutorContext) math_IntDiv(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_IntDiv(arguments []interface{}) interface{} {
exItem1 := arguments[0].(parsers.SelectItem) exItem1 := arguments[0].(parsers.SelectItem)
exItem2 := arguments[1].(parsers.SelectItem) exItem2 := arguments[1].(parsers.SelectItem)
ex1 := c.getFieldValue(exItem1, row) ex1 := r.resolveSelectItem(exItem1)
ex2 := c.getFieldValue(exItem2, row) ex2 := r.resolveSelectItem(exItem2)
num1, num1IsInt := ex1.(int) num1, num1IsInt := ex1.(int)
num2, num2IsInt := ex2.(int) num2, num2IsInt := ex2.(int)
@ -451,11 +451,11 @@ func (c memoryExecutorContext) math_IntDiv(arguments []interface{}, row RowType)
return num1 / num2 return num1 / num2
} }
func (c memoryExecutorContext) math_IntMul(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_IntMul(arguments []interface{}) interface{} {
exItem1 := arguments[0].(parsers.SelectItem) exItem1 := arguments[0].(parsers.SelectItem)
exItem2 := arguments[1].(parsers.SelectItem) exItem2 := arguments[1].(parsers.SelectItem)
ex1 := c.getFieldValue(exItem1, row) ex1 := r.resolveSelectItem(exItem1)
ex2 := c.getFieldValue(exItem2, row) ex2 := r.resolveSelectItem(exItem2)
num1, num1IsInt := ex1.(int) num1, num1IsInt := ex1.(int)
num2, num2IsInt := ex2.(int) num2, num2IsInt := ex2.(int)
@ -468,11 +468,11 @@ func (c memoryExecutorContext) math_IntMul(arguments []interface{}, row RowType)
return num1 * num2 return num1 * num2
} }
func (c memoryExecutorContext) math_IntSub(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_IntSub(arguments []interface{}) interface{} {
exItem1 := arguments[0].(parsers.SelectItem) exItem1 := arguments[0].(parsers.SelectItem)
exItem2 := arguments[1].(parsers.SelectItem) exItem2 := arguments[1].(parsers.SelectItem)
ex1 := c.getFieldValue(exItem1, row) ex1 := r.resolveSelectItem(exItem1)
ex2 := c.getFieldValue(exItem2, row) ex2 := r.resolveSelectItem(exItem2)
num1, num1IsInt := ex1.(int) num1, num1IsInt := ex1.(int)
num2, num2IsInt := ex2.(int) num2, num2IsInt := ex2.(int)
@ -485,11 +485,11 @@ func (c memoryExecutorContext) math_IntSub(arguments []interface{}, row RowType)
return num1 - num2 return num1 - num2
} }
func (c memoryExecutorContext) math_IntMod(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_IntMod(arguments []interface{}) interface{} {
exItem1 := arguments[0].(parsers.SelectItem) exItem1 := arguments[0].(parsers.SelectItem)
exItem2 := arguments[1].(parsers.SelectItem) exItem2 := arguments[1].(parsers.SelectItem)
ex1 := c.getFieldValue(exItem1, row) ex1 := r.resolveSelectItem(exItem1)
ex2 := c.getFieldValue(exItem2, row) ex2 := r.resolveSelectItem(exItem2)
num1, num1IsInt := ex1.(int) num1, num1IsInt := ex1.(int)
num2, num2IsInt := ex2.(int) num2, num2IsInt := ex2.(int)
@ -502,11 +502,11 @@ func (c memoryExecutorContext) math_IntMod(arguments []interface{}, row RowType)
return num1 % num2 return num1 % num2
} }
func (c memoryExecutorContext) math_Power(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Power(arguments []interface{}) interface{} {
exItem1 := arguments[0].(parsers.SelectItem) exItem1 := arguments[0].(parsers.SelectItem)
exItem2 := arguments[1].(parsers.SelectItem) exItem2 := arguments[1].(parsers.SelectItem)
ex1 := c.getFieldValue(exItem1, row) ex1 := r.resolveSelectItem(exItem1)
ex2 := c.getFieldValue(exItem2, row) ex2 := r.resolveSelectItem(exItem2)
base, baseIsNumber := numToFloat64(ex1) base, baseIsNumber := numToFloat64(ex1)
exponent, exponentIsNumber := numToFloat64(ex2) exponent, exponentIsNumber := numToFloat64(ex2)
@ -519,14 +519,14 @@ func (c memoryExecutorContext) math_Power(arguments []interface{}, row RowType)
return math.Pow(base, exponent) return math.Pow(base, exponent)
} }
func (c memoryExecutorContext) math_Log(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_Log(arguments []interface{}) interface{} {
exItem1 := arguments[0].(parsers.SelectItem) exItem1 := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem1, row) ex := r.resolveSelectItem(exItem1)
var base float64 = math.E var base float64 = math.E
if len(arguments) > 1 { if len(arguments) > 1 {
exItem2 := arguments[1].(parsers.SelectItem) exItem2 := arguments[1].(parsers.SelectItem)
baseValueObject := c.getFieldValue(exItem2, row) baseValueObject := r.resolveSelectItem(exItem2)
baseValue, baseValueIsNumber := numToFloat64(baseValueObject) baseValue, baseValueIsNumber := numToFloat64(baseValueObject)
if !baseValueIsNumber { if !baseValueIsNumber {
@ -551,15 +551,15 @@ func (c memoryExecutorContext) math_Log(arguments []interface{}, row RowType) in
return math.Log(num) / math.Log(base) return math.Log(num) / math.Log(base)
} }
func (c memoryExecutorContext) math_NumberBin(arguments []interface{}, row RowType) interface{} { func (r rowContext) math_NumberBin(arguments []interface{}) interface{} {
exItem1 := arguments[0].(parsers.SelectItem) exItem1 := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem1, row) ex := r.resolveSelectItem(exItem1)
binSize := 1.0 binSize := 1.0
if len(arguments) > 1 { if len(arguments) > 1 {
exItem2 := arguments[1].(parsers.SelectItem) exItem2 := arguments[1].(parsers.SelectItem)
binSizeValueObject := c.getFieldValue(exItem2, row) binSizeValueObject := r.resolveSelectItem(exItem2)
binSizeValue, binSizeValueIsNumber := numToFloat64(binSizeValueObject) binSizeValue, binSizeValueIsNumber := numToFloat64(binSizeValueObject)
if !binSizeValueIsNumber { if !binSizeValueIsNumber {
@ -584,11 +584,11 @@ func (c memoryExecutorContext) math_NumberBin(arguments []interface{}, row RowTy
return math.Floor(num/binSize) * binSize return math.Floor(num/binSize) * binSize
} }
func (c memoryExecutorContext) math_Pi() interface{} { func (r rowContext) math_Pi() interface{} {
return math.Pi return math.Pi
} }
func (c memoryExecutorContext) math_Rand() interface{} { func (r rowContext) math_Rand() interface{} {
return rand.Float64() return rand.Float64()
} }

File diff suppressed because it is too large Load Diff

View File

@ -4,11 +4,11 @@ import (
"github.com/pikami/cosmium/parsers" "github.com/pikami/cosmium/parsers"
) )
func (c memoryExecutorContext) misc_In(arguments []interface{}, row RowType) bool { func (r rowContext) misc_In(arguments []interface{}) bool {
value := c.getFieldValue(arguments[0].(parsers.SelectItem), row) value := r.resolveSelectItem(arguments[0].(parsers.SelectItem))
for i := 1; i < len(arguments); i++ { for i := 1; i < len(arguments); i++ {
compareValue := c.getFieldValue(arguments[i].(parsers.SelectItem), row) compareValue := r.resolveSelectItem(arguments[i].(parsers.SelectItem))
if compareValues(value, compareValue) == 0 { if compareValues(value, compareValue) == 0 {
return true return true
} }

View File

@ -14,7 +14,7 @@ func testQueryExecute(
data []memoryexecutor.RowType, data []memoryexecutor.RowType,
expectedData []memoryexecutor.RowType, expectedData []memoryexecutor.RowType,
) { ) {
result := memoryexecutor.Execute(query, data) result := memoryexecutor.ExecuteQuery(query, data)
if !reflect.DeepEqual(result, expectedData) { if !reflect.DeepEqual(result, expectedData) {
t.Errorf("execution result does not match expected data.\nExpected: %+v\nGot: %+v", expectedData, result) t.Errorf("execution result does not match expected data.\nExpected: %+v\nGot: %+v", expectedData, result)
@ -25,8 +25,20 @@ func Test_Execute(t *testing.T) {
mockData := []memoryexecutor.RowType{ mockData := []memoryexecutor.RowType{
map[string]interface{}{"id": "12345", "pk": 123, "_self": "self1", "_rid": "rid1", "_ts": 123456, "isCool": false}, map[string]interface{}{"id": "12345", "pk": 123, "_self": "self1", "_rid": "rid1", "_ts": 123456, "isCool": false},
map[string]interface{}{"id": "67890", "pk": 456, "_self": "self2", "_rid": "rid2", "_ts": 789012, "isCool": true}, map[string]interface{}{"id": "67890", "pk": 456, "_self": "self2", "_rid": "rid2", "_ts": 789012, "isCool": true},
map[string]interface{}{"id": "456", "pk": 456, "_self": "self2", "_rid": "rid2", "_ts": 789012, "isCool": true}, map[string]interface{}{
map[string]interface{}{"id": "123", "pk": 456, "_self": "self2", "_rid": "rid2", "_ts": 789012, "isCool": true}, "id": "456", "pk": 456, "_self": "self2", "_rid": "rid2", "_ts": 789012, "isCool": true,
"tags": []map[string]interface{}{
{"name": "tag-a"},
{"name": "tag-b"},
},
},
map[string]interface{}{
"id": "123", "pk": 456, "_self": "self2", "_rid": "rid2", "_ts": 789012, "isCool": true,
"tags": []map[string]interface{}{
{"name": "tag-b"},
{"name": "tag-c"},
},
},
} }
t.Run("Should execute SELECT with ORDER BY", func(t *testing.T) { t.Run("Should execute SELECT with ORDER BY", func(t *testing.T) {
@ -124,4 +136,31 @@ func Test_Execute(t *testing.T) {
}, },
) )
}) })
t.Run("Should execute IN selector", func(t *testing.T) {
testQueryExecute(
t,
parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{
Path: []string{"c", "name"},
Type: parsers.SelectItemTypeField,
},
},
Table: parsers.Table{
Value: "c",
SelectItem: parsers.SelectItem{
Path: []string{"c", "tags"},
},
},
},
mockData,
[]memoryexecutor.RowType{
map[string]interface{}{"name": "tag-a"},
map[string]interface{}{"name": "tag-b"},
map[string]interface{}{"name": "tag-b"},
map[string]interface{}{"name": "tag-c"},
},
)
})
} }

View File

@ -8,10 +8,10 @@ import (
"github.com/pikami/cosmium/parsers" "github.com/pikami/cosmium/parsers"
) )
func (c memoryExecutorContext) strings_StringEquals(arguments []interface{}, row RowType) bool { func (r rowContext) strings_StringEquals(arguments []interface{}) bool {
str1 := c.parseString(arguments[0], row) str1 := r.parseString(arguments[0])
str2 := c.parseString(arguments[1], row) str2 := r.parseString(arguments[1])
ignoreCase := c.getBoolFlag(arguments, row) ignoreCase := r.getBoolFlag(arguments)
if ignoreCase { if ignoreCase {
return strings.EqualFold(str1, str2) return strings.EqualFold(str1, str2)
@ -20,10 +20,10 @@ func (c memoryExecutorContext) strings_StringEquals(arguments []interface{}, row
return str1 == str2 return str1 == str2
} }
func (c memoryExecutorContext) strings_Contains(arguments []interface{}, row RowType) bool { func (r rowContext) strings_Contains(arguments []interface{}) bool {
str1 := c.parseString(arguments[0], row) str1 := r.parseString(arguments[0])
str2 := c.parseString(arguments[1], row) str2 := r.parseString(arguments[1])
ignoreCase := c.getBoolFlag(arguments, row) ignoreCase := r.getBoolFlag(arguments)
if ignoreCase { if ignoreCase {
str1 = strings.ToLower(str1) str1 = strings.ToLower(str1)
@ -33,10 +33,10 @@ func (c memoryExecutorContext) strings_Contains(arguments []interface{}, row Row
return strings.Contains(str1, str2) return strings.Contains(str1, str2)
} }
func (c memoryExecutorContext) strings_EndsWith(arguments []interface{}, row RowType) bool { func (r rowContext) strings_EndsWith(arguments []interface{}) bool {
str1 := c.parseString(arguments[0], row) str1 := r.parseString(arguments[0])
str2 := c.parseString(arguments[1], row) str2 := r.parseString(arguments[1])
ignoreCase := c.getBoolFlag(arguments, row) ignoreCase := r.getBoolFlag(arguments)
if ignoreCase { if ignoreCase {
str1 = strings.ToLower(str1) str1 = strings.ToLower(str1)
@ -46,10 +46,10 @@ func (c memoryExecutorContext) strings_EndsWith(arguments []interface{}, row Row
return strings.HasSuffix(str1, str2) return strings.HasSuffix(str1, str2)
} }
func (c memoryExecutorContext) strings_StartsWith(arguments []interface{}, row RowType) bool { func (r rowContext) strings_StartsWith(arguments []interface{}) bool {
str1 := c.parseString(arguments[0], row) str1 := r.parseString(arguments[0])
str2 := c.parseString(arguments[1], row) str2 := r.parseString(arguments[1])
ignoreCase := c.getBoolFlag(arguments, row) ignoreCase := r.getBoolFlag(arguments)
if ignoreCase { if ignoreCase {
str1 = strings.ToLower(str1) str1 = strings.ToLower(str1)
@ -59,12 +59,12 @@ func (c memoryExecutorContext) strings_StartsWith(arguments []interface{}, row R
return strings.HasPrefix(str1, str2) return strings.HasPrefix(str1, str2)
} }
func (c memoryExecutorContext) strings_Concat(arguments []interface{}, row RowType) string { func (r rowContext) strings_Concat(arguments []interface{}) string {
result := "" result := ""
for _, arg := range arguments { for _, arg := range arguments {
if selectItem, ok := arg.(parsers.SelectItem); ok { if selectItem, ok := arg.(parsers.SelectItem); ok {
value := c.getFieldValue(selectItem, row) value := r.resolveSelectItem(selectItem)
result += convertToString(value) result += convertToString(value)
} }
} }
@ -72,13 +72,13 @@ func (c memoryExecutorContext) strings_Concat(arguments []interface{}, row RowTy
return result return result
} }
func (c memoryExecutorContext) strings_IndexOf(arguments []interface{}, row RowType) int { func (r rowContext) strings_IndexOf(arguments []interface{}) int {
str1 := c.parseString(arguments[0], row) str1 := r.parseString(arguments[0])
str2 := c.parseString(arguments[1], row) str2 := r.parseString(arguments[1])
start := 0 start := 0
if len(arguments) > 2 && arguments[2] != nil { if len(arguments) > 2 && arguments[2] != nil {
if startPos, ok := c.getFieldValue(arguments[2].(parsers.SelectItem), row).(int); ok { if startPos, ok := r.resolveSelectItem(arguments[2].(parsers.SelectItem)).(int); ok {
start = startPos start = startPos
} }
} }
@ -97,26 +97,26 @@ func (c memoryExecutorContext) strings_IndexOf(arguments []interface{}, row RowT
} }
} }
func (c memoryExecutorContext) strings_ToString(arguments []interface{}, row RowType) string { func (r rowContext) strings_ToString(arguments []interface{}) string {
value := c.getFieldValue(arguments[0].(parsers.SelectItem), row) value := r.resolveSelectItem(arguments[0].(parsers.SelectItem))
return convertToString(value) return convertToString(value)
} }
func (c memoryExecutorContext) strings_Upper(arguments []interface{}, row RowType) string { func (r rowContext) strings_Upper(arguments []interface{}) string {
value := c.getFieldValue(arguments[0].(parsers.SelectItem), row) value := r.resolveSelectItem(arguments[0].(parsers.SelectItem))
return strings.ToUpper(convertToString(value)) return strings.ToUpper(convertToString(value))
} }
func (c memoryExecutorContext) strings_Lower(arguments []interface{}, row RowType) string { func (r rowContext) strings_Lower(arguments []interface{}) string {
value := c.getFieldValue(arguments[0].(parsers.SelectItem), row) value := r.resolveSelectItem(arguments[0].(parsers.SelectItem))
return strings.ToLower(convertToString(value)) return strings.ToLower(convertToString(value))
} }
func (c memoryExecutorContext) strings_Left(arguments []interface{}, row RowType) string { func (r rowContext) strings_Left(arguments []interface{}) string {
var ok bool var ok bool
var length int var length int
str := c.parseString(arguments[0], row) str := r.parseString(arguments[0])
lengthEx := c.getFieldValue(arguments[1].(parsers.SelectItem), row) lengthEx := r.resolveSelectItem(arguments[1].(parsers.SelectItem))
if length, ok = lengthEx.(int); !ok { if length, ok = lengthEx.(int); !ok {
logger.Error("strings_Left - got parameters of wrong type") logger.Error("strings_Left - got parameters of wrong type")
@ -134,28 +134,28 @@ func (c memoryExecutorContext) strings_Left(arguments []interface{}, row RowType
return str[:length] return str[:length]
} }
func (c memoryExecutorContext) strings_Length(arguments []interface{}, row RowType) int { func (r rowContext) strings_Length(arguments []interface{}) int {
str := c.parseString(arguments[0], row) str := r.parseString(arguments[0])
return len(str) return len(str)
} }
func (c memoryExecutorContext) strings_LTrim(arguments []interface{}, row RowType) string { func (r rowContext) strings_LTrim(arguments []interface{}) string {
str := c.parseString(arguments[0], row) str := r.parseString(arguments[0])
return strings.TrimLeft(str, " ") return strings.TrimLeft(str, " ")
} }
func (c memoryExecutorContext) strings_Replace(arguments []interface{}, row RowType) string { func (r rowContext) strings_Replace(arguments []interface{}) string {
str := c.parseString(arguments[0], row) str := r.parseString(arguments[0])
oldStr := c.parseString(arguments[1], row) oldStr := r.parseString(arguments[1])
newStr := c.parseString(arguments[2], row) newStr := r.parseString(arguments[2])
return strings.Replace(str, oldStr, newStr, -1) return strings.Replace(str, oldStr, newStr, -1)
} }
func (c memoryExecutorContext) strings_Replicate(arguments []interface{}, row RowType) string { func (r rowContext) strings_Replicate(arguments []interface{}) string {
var ok bool var ok bool
var times int var times int
str := c.parseString(arguments[0], row) str := r.parseString(arguments[0])
timesEx := c.getFieldValue(arguments[1].(parsers.SelectItem), row) timesEx := r.resolveSelectItem(arguments[1].(parsers.SelectItem))
if times, ok = timesEx.(int); !ok { if times, ok = timesEx.(int); !ok {
logger.Error("strings_Replicate - got parameters of wrong type") logger.Error("strings_Replicate - got parameters of wrong type")
@ -173,8 +173,8 @@ func (c memoryExecutorContext) strings_Replicate(arguments []interface{}, row Ro
return strings.Repeat(str, times) return strings.Repeat(str, times)
} }
func (c memoryExecutorContext) strings_Reverse(arguments []interface{}, row RowType) string { func (r rowContext) strings_Reverse(arguments []interface{}) string {
str := c.parseString(arguments[0], row) str := r.parseString(arguments[0])
runes := []rune(str) runes := []rune(str)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 { for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
@ -184,11 +184,11 @@ func (c memoryExecutorContext) strings_Reverse(arguments []interface{}, row RowT
return string(runes) return string(runes)
} }
func (c memoryExecutorContext) strings_Right(arguments []interface{}, row RowType) string { func (r rowContext) strings_Right(arguments []interface{}) string {
var ok bool var ok bool
var length int var length int
str := c.parseString(arguments[0], row) str := r.parseString(arguments[0])
lengthEx := c.getFieldValue(arguments[1].(parsers.SelectItem), row) lengthEx := r.resolveSelectItem(arguments[1].(parsers.SelectItem))
if length, ok = lengthEx.(int); !ok { if length, ok = lengthEx.(int); !ok {
logger.Error("strings_Right - got parameters of wrong type") logger.Error("strings_Right - got parameters of wrong type")
@ -206,18 +206,18 @@ func (c memoryExecutorContext) strings_Right(arguments []interface{}, row RowTyp
return str[len(str)-length:] return str[len(str)-length:]
} }
func (c memoryExecutorContext) strings_RTrim(arguments []interface{}, row RowType) string { func (r rowContext) strings_RTrim(arguments []interface{}) string {
str := c.parseString(arguments[0], row) str := r.parseString(arguments[0])
return strings.TrimRight(str, " ") return strings.TrimRight(str, " ")
} }
func (c memoryExecutorContext) strings_Substring(arguments []interface{}, row RowType) string { func (r rowContext) strings_Substring(arguments []interface{}) string {
var ok bool var ok bool
var startPos int var startPos int
var length int var length int
str := c.parseString(arguments[0], row) str := r.parseString(arguments[0])
startPosEx := c.getFieldValue(arguments[1].(parsers.SelectItem), row) startPosEx := r.resolveSelectItem(arguments[1].(parsers.SelectItem))
lengthEx := c.getFieldValue(arguments[2].(parsers.SelectItem), row) lengthEx := r.resolveSelectItem(arguments[2].(parsers.SelectItem))
if startPos, ok = startPosEx.(int); !ok { if startPos, ok = startPosEx.(int); !ok {
logger.Error("strings_Substring - got start parameters of wrong type") logger.Error("strings_Substring - got start parameters of wrong type")
@ -240,16 +240,16 @@ func (c memoryExecutorContext) strings_Substring(arguments []interface{}, row Ro
return str[startPos:endPos] return str[startPos:endPos]
} }
func (c memoryExecutorContext) strings_Trim(arguments []interface{}, row RowType) string { func (r rowContext) strings_Trim(arguments []interface{}) string {
str := c.parseString(arguments[0], row) str := r.parseString(arguments[0])
return strings.TrimSpace(str) return strings.TrimSpace(str)
} }
func (c memoryExecutorContext) getBoolFlag(arguments []interface{}, row RowType) bool { func (r rowContext) getBoolFlag(arguments []interface{}) bool {
ignoreCase := false ignoreCase := false
if len(arguments) > 2 && arguments[2] != nil { if len(arguments) > 2 && arguments[2] != nil {
ignoreCaseItem := arguments[2].(parsers.SelectItem) ignoreCaseItem := arguments[2].(parsers.SelectItem)
if value, ok := c.getFieldValue(ignoreCaseItem, row).(bool); ok { if value, ok := r.resolveSelectItem(ignoreCaseItem).(bool); ok {
ignoreCase = value ignoreCase = value
} }
} }
@ -257,9 +257,9 @@ func (c memoryExecutorContext) getBoolFlag(arguments []interface{}, row RowType)
return ignoreCase return ignoreCase
} }
func (c memoryExecutorContext) parseString(argument interface{}, row RowType) string { func (r rowContext) parseString(argument interface{}) string {
exItem := argument.(parsers.SelectItem) exItem := argument.(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
if str1, ok := ex.(string); ok { if str1, ok := ex.(string); ok {
return str1 return str1
} }

View File

@ -0,0 +1,155 @@
package memoryexecutor_test
import (
"testing"
"github.com/pikami/cosmium/parsers"
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
)
func Test_Execute_SubQuery(t *testing.T) {
mockData := []memoryexecutor.RowType{
map[string]interface{}{"id": "123", "info": map[string]interface{}{"name": "row-1"}},
map[string]interface{}{
"id": "456",
"info": map[string]interface{}{"name": "row-2"},
"tags": []map[string]interface{}{
{"name": "tag-a"},
{"name": "tag-b"},
},
},
map[string]interface{}{
"id": "789",
"info": map[string]interface{}{"name": "row-3"},
"tags": []map[string]interface{}{
{"name": "tag-b"},
{"name": "tag-c"},
},
},
}
t.Run("Should execute FROM subquery", func(t *testing.T) {
testQueryExecute(
t,
parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{Path: []string{"c", "name"}},
},
Table: parsers.Table{
Value: "c",
SelectItem: parsers.SelectItem{
Alias: "c",
Type: parsers.SelectItemTypeSubQuery,
Value: parsers.SelectStmt{
Table: parsers.Table{Value: "cc"},
SelectItems: []parsers.SelectItem{
{Path: []string{"cc", "info"}, IsTopLevel: true},
},
},
},
},
},
mockData,
[]memoryexecutor.RowType{
map[string]interface{}{"name": "row-1"},
map[string]interface{}{"name": "row-2"},
map[string]interface{}{"name": "row-3"},
},
)
})
t.Run("Should execute JOIN subquery", func(t *testing.T) {
testQueryExecute(
t,
parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{Path: []string{"c", "id"}},
{Path: []string{"cc", "name"}},
},
Table: parsers.Table{
Value: "c",
},
JoinItems: []parsers.JoinItem{
{
Table: parsers.Table{
Value: "cc",
},
SelectItem: parsers.SelectItem{
Alias: "cc",
Type: parsers.SelectItemTypeSubQuery,
Value: parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{Path: []string{"tag", "name"}},
},
Table: parsers.Table{
Value: "tag",
SelectItem: parsers.SelectItem{
Path: []string{"c", "tags"},
},
},
},
},
},
},
},
mockData,
[]memoryexecutor.RowType{
map[string]interface{}{"id": "456", "name": "tag-a"},
map[string]interface{}{"id": "456", "name": "tag-b"},
map[string]interface{}{"id": "789", "name": "tag-b"},
map[string]interface{}{"id": "789", "name": "tag-c"},
},
)
})
t.Run("Should execute JOIN EXISTS subquery", func(t *testing.T) {
testQueryExecute(
t,
parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{Path: []string{"c", "id"}},
},
Table: parsers.Table{
Value: "c",
},
JoinItems: []parsers.JoinItem{
{
Table: parsers.Table{Value: "hasTags"},
SelectItem: parsers.SelectItem{
Alias: "hasTags",
Type: parsers.SelectItemTypeSubQuery,
Value: parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{
IsTopLevel: true,
Type: parsers.SelectItemTypeSubQuery,
Value: parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{Path: []string{"tag", "name"}},
},
Table: parsers.Table{
Value: "tag",
SelectItem: parsers.SelectItem{
Path: []string{"c", "tags"},
},
},
Exists: true,
},
},
},
},
},
},
},
Filters: parsers.SelectItem{
Path: []string{"hasTags"},
},
},
mockData,
[]memoryexecutor.RowType{
map[string]interface{}{"id": "456"},
map[string]interface{}{"id": "789"},
},
)
})
}

View File

@ -6,32 +6,32 @@ import (
"github.com/pikami/cosmium/parsers" "github.com/pikami/cosmium/parsers"
) )
func (c memoryExecutorContext) typeChecking_IsDefined(arguments []interface{}, row RowType) bool { func (r rowContext) typeChecking_IsDefined(arguments []interface{}) bool {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
return ex != nil return ex != nil
} }
func (c memoryExecutorContext) typeChecking_IsArray(arguments []interface{}, row RowType) bool { func (r rowContext) typeChecking_IsArray(arguments []interface{}) bool {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
_, isArray := ex.([]interface{}) _, isArray := ex.([]interface{})
return isArray return isArray
} }
func (c memoryExecutorContext) typeChecking_IsBool(arguments []interface{}, row RowType) bool { func (r rowContext) typeChecking_IsBool(arguments []interface{}) bool {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
_, isBool := ex.(bool) _, isBool := ex.(bool)
return isBool return isBool
} }
func (c memoryExecutorContext) typeChecking_IsFiniteNumber(arguments []interface{}, row RowType) bool { func (r rowContext) typeChecking_IsFiniteNumber(arguments []interface{}) bool {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
switch num := ex.(type) { switch num := ex.(type) {
case int: case int:
@ -43,41 +43,41 @@ func (c memoryExecutorContext) typeChecking_IsFiniteNumber(arguments []interface
} }
} }
func (c memoryExecutorContext) typeChecking_IsInteger(arguments []interface{}, row RowType) bool { func (r rowContext) typeChecking_IsInteger(arguments []interface{}) bool {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
_, isInt := ex.(int) _, isInt := ex.(int)
return isInt return isInt
} }
func (c memoryExecutorContext) typeChecking_IsNull(arguments []interface{}, row RowType) bool { func (r rowContext) typeChecking_IsNull(arguments []interface{}) bool {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
return ex == nil return ex == nil
} }
func (c memoryExecutorContext) typeChecking_IsNumber(arguments []interface{}, row RowType) bool { func (r rowContext) typeChecking_IsNumber(arguments []interface{}) bool {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
_, isFloat := ex.(float64) _, isFloat := ex.(float64)
_, isInt := ex.(int) _, isInt := ex.(int)
return isFloat || isInt return isFloat || isInt
} }
func (c memoryExecutorContext) typeChecking_IsObject(arguments []interface{}, row RowType) bool { func (r rowContext) typeChecking_IsObject(arguments []interface{}) bool {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
_, isObject := ex.(map[string]interface{}) _, isObject := ex.(map[string]interface{})
return isObject return isObject
} }
func (c memoryExecutorContext) typeChecking_IsPrimitive(arguments []interface{}, row RowType) bool { func (r rowContext) typeChecking_IsPrimitive(arguments []interface{}) bool {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
switch ex.(type) { switch ex.(type) {
case bool, string, float64, int, nil: case bool, string, float64, int, nil:
@ -87,9 +87,9 @@ func (c memoryExecutorContext) typeChecking_IsPrimitive(arguments []interface{},
} }
} }
func (c memoryExecutorContext) typeChecking_IsString(arguments []interface{}, row RowType) bool { func (r rowContext) typeChecking_IsString(arguments []interface{}) bool {
exItem := arguments[0].(parsers.SelectItem) exItem := arguments[0].(parsers.SelectItem)
ex := c.getFieldValue(exItem, row) ex := r.resolveSelectItem(exItem)
_, isStr := ex.(string) _, isStr := ex.(string)
return isStr return isStr