mirror of
https://github.com/pikami/cosmium.git
synced 2025-05-25 17:52:58 +01:00
Add support for expressions in SELECT clause
This commit is contained in:
parent
e20a6ca7cd
commit
560ea5296d
@ -34,6 +34,7 @@ const (
|
|||||||
SelectItemTypeConstant
|
SelectItemTypeConstant
|
||||||
SelectItemTypeFunctionCall
|
SelectItemTypeFunctionCall
|
||||||
SelectItemTypeSubQuery
|
SelectItemTypeSubQuery
|
||||||
|
SelectItemTypeExpression
|
||||||
)
|
)
|
||||||
|
|
||||||
type SelectItem struct {
|
type SelectItem struct {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -204,7 +204,7 @@ TopClause <- Top ws count:Integer {
|
|||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
FromClause <- From ws table:TableName selectItem:(ws In ws column:SelectItem { return column, nil }) {
|
FromClause <- From ws table:TableName selectItem:(ws In ws column:SelectItemWithAlias { return column, nil }) {
|
||||||
tableTyped := table.(parsers.Table)
|
tableTyped := table.(parsers.Table)
|
||||||
|
|
||||||
if selectItem != nil {
|
if selectItem != nil {
|
||||||
@ -213,7 +213,7 @@ FromClause <- From ws table:TableName selectItem:(ws In ws column:SelectItem { r
|
|||||||
}
|
}
|
||||||
|
|
||||||
return tableTyped, nil
|
return tableTyped, nil
|
||||||
} / From ws column:SelectItem {
|
} / From ws column:SelectItemWithAlias {
|
||||||
tableSelectItem := column.(parsers.SelectItem)
|
tableSelectItem := column.(parsers.SelectItem)
|
||||||
table := parsers.Table{
|
table := parsers.Table{
|
||||||
Value: tableSelectItem.Alias,
|
Value: tableSelectItem.Alias,
|
||||||
@ -251,7 +251,7 @@ SubQuerySelectItem <- subQuery:SubQuery asClause:(ws alias:AsClause { return ali
|
|||||||
return selectItem, nil
|
return selectItem, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
JoinClause <- Join ws table:TableName ws In ws column:SelectItem {
|
JoinClause <- Join ws table:TableName ws In ws column:SelectItemWithAlias {
|
||||||
return makeJoin(table, column)
|
return makeJoin(table, column)
|
||||||
} / Join ws subQuery:SubQuerySelectItem {
|
} / Join ws subQuery:SubQuerySelectItem {
|
||||||
return makeJoin(nil, subQuery)
|
return makeJoin(nil, subQuery)
|
||||||
@ -269,11 +269,34 @@ SelectAsterisk <- "*" {
|
|||||||
return makeColumnList(selectItem, make([]interface{}, 0))
|
return makeColumnList(selectItem, make([]interface{}, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnList <- column:SelectItem other_columns:(ws "," ws coll:SelectItem {return coll, nil })* {
|
ColumnList <- column:ExpressionOrSelectItem other_columns:(ws "," ws coll:ExpressionOrSelectItem {return coll, nil })* {
|
||||||
return makeColumnList(column, other_columns)
|
return makeColumnList(column, other_columns)
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectValueSpec <- "VALUE"i ws column:SelectItem {
|
ExpressionOrSelectItem <- expression:OrExpression asClause:AsClause? {
|
||||||
|
switch typedValue := expression.(type) {
|
||||||
|
case parsers.ComparisonExpression, parsers.LogicalExpression:
|
||||||
|
selectItem := parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeExpression,
|
||||||
|
Value: typedValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
if aliasValue, ok := asClause.(string); ok {
|
||||||
|
selectItem.Alias = aliasValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectItem, nil
|
||||||
|
case parsers.SelectItem:
|
||||||
|
if aliasValue, ok := asClause.(string); ok {
|
||||||
|
typedValue.Alias = aliasValue
|
||||||
|
}
|
||||||
|
return typedValue, nil
|
||||||
|
default:
|
||||||
|
return typedValue, nil
|
||||||
|
}
|
||||||
|
} / item:SelectItemWithAlias { return item, nil }
|
||||||
|
|
||||||
|
SelectValueSpec <- "VALUE"i ws column:SelectItemWithAlias {
|
||||||
selectItem := column.(parsers.SelectItem)
|
selectItem := column.(parsers.SelectItem)
|
||||||
selectItem.IsTopLevel = true
|
selectItem.IsTopLevel = true
|
||||||
return makeColumnList(selectItem, make([]interface{}, 0))
|
return makeColumnList(selectItem, make([]interface{}, 0))
|
||||||
@ -306,7 +329,15 @@ SelectProperty <- name:Identifier path:(DotFieldAccess / ArrayFieldAccess)* {
|
|||||||
return makeSelectItem(name, path, parsers.SelectItemTypeField)
|
return makeSelectItem(name, path, parsers.SelectItemTypeField)
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectItem <- selectItem:(SubQuerySelectItem / Literal / FunctionCall / SelectArray / SelectObject / SelectProperty) asClause:AsClause? {
|
SelectItemWithAlias <- selectItem:SelectItem asClause:AsClause? {
|
||||||
|
item := selectItem.(parsers.SelectItem)
|
||||||
|
if aliasValue, ok := asClause.(string); ok {
|
||||||
|
item.Alias = aliasValue
|
||||||
|
}
|
||||||
|
return item, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectItem <- selectItem:(SubQuerySelectItem / Literal / FunctionCall / SelectArray / SelectObject / SelectProperty) {
|
||||||
var itemResult parsers.SelectItem
|
var itemResult parsers.SelectItem
|
||||||
switch typedValue := selectItem.(type) {
|
switch typedValue := selectItem.(type) {
|
||||||
case parsers.SelectItem:
|
case parsers.SelectItem:
|
||||||
@ -323,10 +354,6 @@ SelectItem <- selectItem:(SubQuerySelectItem / Literal / FunctionCall / SelectAr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if aliasValue, ok := asClause.(string); ok {
|
|
||||||
itemResult.Alias = aliasValue
|
|
||||||
}
|
|
||||||
|
|
||||||
return itemResult, nil
|
return itemResult, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,4 +195,73 @@ func Test_Parse_Select(t *testing.T) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Should parse comparison expressions in SELECT", func(t *testing.T) {
|
||||||
|
testQueryParse(
|
||||||
|
t,
|
||||||
|
`SELECT c["id"] = "123", c["pk"] > 456 FROM c`,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Type: parsers.SelectItemTypeExpression,
|
||||||
|
Value: parsers.ComparisonExpression{
|
||||||
|
Operation: "=",
|
||||||
|
Left: testutils.SelectItem_Path("c", "id"),
|
||||||
|
Right: testutils.SelectItem_Constant_String("123"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: parsers.SelectItemTypeExpression,
|
||||||
|
Value: parsers.ComparisonExpression{
|
||||||
|
Operation: ">",
|
||||||
|
Left: testutils.SelectItem_Path("c", "pk"),
|
||||||
|
Right: testutils.SelectItem_Constant_Int(456),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{SelectItem: testutils.SelectItem_Path("c")},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should parse logical expressions in SELECT", func(t *testing.T) {
|
||||||
|
testQueryParse(
|
||||||
|
t,
|
||||||
|
`SELECT c["id"] = "123" OR c["pk"] > 456, c["isCool"] AND c["hasRizz"] AS isRizzler FROM c`,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Type: parsers.SelectItemTypeExpression,
|
||||||
|
Value: parsers.LogicalExpression{
|
||||||
|
Operation: parsers.LogicalExpressionTypeOr,
|
||||||
|
Expressions: []interface{}{
|
||||||
|
parsers.ComparisonExpression{
|
||||||
|
Operation: "=",
|
||||||
|
Left: testutils.SelectItem_Path("c", "id"),
|
||||||
|
Right: testutils.SelectItem_Constant_String("123"),
|
||||||
|
},
|
||||||
|
parsers.ComparisonExpression{
|
||||||
|
Operation: ">",
|
||||||
|
Left: testutils.SelectItem_Path("c", "pk"),
|
||||||
|
Right: testutils.SelectItem_Constant_Int(456),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: parsers.SelectItemTypeExpression,
|
||||||
|
Alias: "isRizzler",
|
||||||
|
Value: parsers.LogicalExpression{
|
||||||
|
Operation: parsers.LogicalExpressionTypeAnd,
|
||||||
|
Expressions: []interface{}{
|
||||||
|
testutils.SelectItem_Path("c", "isCool"),
|
||||||
|
testutils.SelectItem_Path("c", "hasRizz"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{SelectItem: testutils.SelectItem_Path("c")},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,19 @@ func (r rowContext) resolveSelectItem(selectItem parsers.SelectItem) interface{}
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if selectItem.Type == parsers.SelectItemTypeExpression {
|
||||||
|
if typedExpression, ok := selectItem.Value.(parsers.ComparisonExpression); ok {
|
||||||
|
return r.filters_ComparisonExpression(typedExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
if typedExpression, ok := selectItem.Value.(parsers.LogicalExpression); ok {
|
||||||
|
return r.filters_LogicalExpression(typedExpression)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.ErrorLn("parsers.SelectItem has incorrect Value type (expected parsers.ComparisonExpression)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return r.selectItem_SelectItemTypeField(selectItem)
|
return r.selectItem_SelectItemTypeField(selectItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
package memoryexecutor_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pikami/cosmium/parsers"
|
||||||
|
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
||||||
|
testutils "github.com/pikami/cosmium/test_utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Execute_Expressions(t *testing.T) {
|
||||||
|
mockData := []memoryexecutor.RowType{
|
||||||
|
map[string]interface{}{"id": "123", "age": 10, "isCool": true},
|
||||||
|
map[string]interface{}{"id": "456", "age": 20, "isCool": false},
|
||||||
|
map[string]interface{}{"id": "789", "age": 30, "isCool": true},
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Should execute comparison expressions in SELECT", func(t *testing.T) {
|
||||||
|
testQueryExecute(
|
||||||
|
t,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Path: []string{"c", "id"},
|
||||||
|
Type: parsers.SelectItemTypeField,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "isAdult",
|
||||||
|
Type: parsers.SelectItemTypeExpression,
|
||||||
|
Value: parsers.ComparisonExpression{
|
||||||
|
Operation: ">=",
|
||||||
|
Left: testutils.SelectItem_Path("c", "age"),
|
||||||
|
Right: testutils.SelectItem_Constant_Int(18),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "isNotCool",
|
||||||
|
Type: parsers.SelectItemTypeExpression,
|
||||||
|
Value: parsers.ComparisonExpression{
|
||||||
|
Operation: "!=",
|
||||||
|
Left: testutils.SelectItem_Path("c", "isCool"),
|
||||||
|
Right: testutils.SelectItem_Constant_Bool(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{SelectItem: testutils.SelectItem_Path("c")},
|
||||||
|
},
|
||||||
|
mockData,
|
||||||
|
[]memoryexecutor.RowType{
|
||||||
|
map[string]interface{}{"id": "123", "isAdult": false, "isNotCool": false},
|
||||||
|
map[string]interface{}{"id": "456", "isAdult": true, "isNotCool": true},
|
||||||
|
map[string]interface{}{"id": "789", "isAdult": true, "isNotCool": false},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should execute logical expressions in SELECT", func(t *testing.T) {
|
||||||
|
testQueryExecute(
|
||||||
|
t,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Path: []string{"c", "id"},
|
||||||
|
Type: parsers.SelectItemTypeField,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "isCoolAndAdult",
|
||||||
|
Type: parsers.SelectItemTypeExpression,
|
||||||
|
Value: parsers.LogicalExpression{
|
||||||
|
Operation: parsers.LogicalExpressionTypeAnd,
|
||||||
|
Expressions: []interface{}{
|
||||||
|
testutils.SelectItem_Path("c", "isCool"),
|
||||||
|
parsers.ComparisonExpression{
|
||||||
|
Operation: ">=",
|
||||||
|
Left: testutils.SelectItem_Path("c", "age"),
|
||||||
|
Right: testutils.SelectItem_Constant_Int(18),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{SelectItem: testutils.SelectItem_Path("c")},
|
||||||
|
},
|
||||||
|
mockData,
|
||||||
|
[]memoryexecutor.RowType{
|
||||||
|
map[string]interface{}{"id": "123", "isCoolAndAdult": false},
|
||||||
|
map[string]interface{}{"id": "456", "isCoolAndAdult": false},
|
||||||
|
map[string]interface{}{"id": "789", "isCoolAndAdult": true},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user