mirror of https://github.com/pikami/cosmium.git
Implement STRINGEQUALS
This commit is contained in:
parent
2702156cb3
commit
c17509df38
|
@ -1 +1,2 @@
|
||||||
dist/
|
dist/
|
||||||
|
ignored/
|
||||||
|
|
|
@ -20,6 +20,7 @@ const (
|
||||||
SelectItemTypeObject
|
SelectItemTypeObject
|
||||||
SelectItemTypeArray
|
SelectItemTypeArray
|
||||||
SelectItemTypeConstant
|
SelectItemTypeConstant
|
||||||
|
SelectItemTypeFunctionCall
|
||||||
)
|
)
|
||||||
|
|
||||||
type SelectItem struct {
|
type SelectItem struct {
|
||||||
|
@ -75,3 +76,14 @@ type OrderExpression struct {
|
||||||
SelectItem SelectItem
|
SelectItem SelectItem
|
||||||
Direction OrderDirection
|
Direction OrderDirection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FunctionCallType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
FunctionCallStringEquals FunctionCallType = "StringEquals"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FunctionCall struct {
|
||||||
|
Arguments []interface{}
|
||||||
|
Type FunctionCallType
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -146,7 +146,7 @@ TopClause <- Top ws count:Integer {
|
||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection <- SelectValueSpec / ColumnList /SelectAsterisk
|
Selection <- SelectValueSpec / ColumnList / SelectAsterisk
|
||||||
|
|
||||||
SelectAsterisk <- "*" {
|
SelectAsterisk <- "*" {
|
||||||
selectItem, _ := makeSelectItem("c", make([]interface{}, 0), parsers.SelectItemTypeField)
|
selectItem, _ := makeSelectItem("c", make([]interface{}, 0), parsers.SelectItemTypeField)
|
||||||
|
@ -158,7 +158,7 @@ ColumnList <- column:SelectItem other_columns:(ws "," ws coll:SelectItem {return
|
||||||
return makeColumnList(column, other_columns)
|
return makeColumnList(column, other_columns)
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectValueSpec <- "VALUE" ws column:SelectItem {
|
SelectValueSpec <- "VALUE"i ws column:SelectItem {
|
||||||
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))
|
||||||
|
@ -186,7 +186,7 @@ SelectProperty <- name:Identifier path:(DotFieldAccess / ArrayFieldAccess)* {
|
||||||
return makeSelectItem(name, path, parsers.SelectItemTypeField)
|
return makeSelectItem(name, path, parsers.SelectItemTypeField)
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectItem <- selectItem:(Literal / SelectArray / SelectObject / SelectProperty) asClause:AsClause? {
|
SelectItem <- selectItem:(Literal / StringEqualsExpression / 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:
|
||||||
|
@ -196,6 +196,11 @@ SelectItem <- selectItem:(Literal / SelectArray / SelectObject / SelectProperty)
|
||||||
Type: parsers.SelectItemTypeConstant,
|
Type: parsers.SelectItemTypeConstant,
|
||||||
Value: typedValue,
|
Value: typedValue,
|
||||||
}
|
}
|
||||||
|
case parsers.FunctionCall:
|
||||||
|
itemResult = parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: typedValue,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if aliasValue, ok := asClause.(string); ok {
|
if aliasValue, ok := asClause.(string); ok {
|
||||||
|
@ -244,34 +249,36 @@ OrderExpression <- field:SelectProperty ws order:OrderDirection? {
|
||||||
return makeOrderExpression(field, order)
|
return makeOrderExpression(field, order)
|
||||||
}
|
}
|
||||||
|
|
||||||
OrderDirection <- ("ASC" / "asc" / "DESC" / "desc") {
|
OrderDirection <- ("ASC"i / "DESC"i) {
|
||||||
switch string(c.text) {
|
if strings.EqualFold(string(c.text), "DESC") {
|
||||||
case "DESC", "desc":
|
|
||||||
return parsers.OrderDirectionDesc, nil
|
return parsers.OrderDirectionDesc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsers.OrderDirectionAsc, nil
|
return parsers.OrderDirectionAsc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
Select <- ("select" / "SELECT")
|
Select <- "SELECT"i
|
||||||
|
|
||||||
Top <- ("top" / "TOP")
|
Top <- "TOP"i
|
||||||
|
|
||||||
As <- ("as" / "AS")
|
As <- "AS"i
|
||||||
|
|
||||||
From <- ("from" / "FROM")
|
From <- "FROM"i
|
||||||
|
|
||||||
Where <- ("where" / "WHERE")
|
Where <- "WHERE"i
|
||||||
|
|
||||||
And <- ("and" / "AND")
|
And <- "AND"i
|
||||||
|
|
||||||
Or <- ("or" / "OR")
|
Or <- "OR"i
|
||||||
|
|
||||||
OrderBy <- ("order" / "ORDER") ws ("by" / "BY")
|
OrderBy <- "ORDER"i ws "BY"i
|
||||||
|
|
||||||
ComparisonOperator <- "=" / "!=" / "<" / "<=" / ">" / ">=" {
|
ComparisonOperator <- "=" / "!=" / "<" / "<=" / ">" / ">=" {
|
||||||
return string(c.text), nil
|
return string(c.text), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringEquals <- "STRINGEQUALS"i
|
||||||
|
|
||||||
Literal <- FloatLiteral / IntegerLiteral / StringLiteral / BooleanLiteral / ParameterConstant / NullConstant
|
Literal <- FloatLiteral / IntegerLiteral / StringLiteral / BooleanLiteral / ParameterConstant / NullConstant
|
||||||
|
|
||||||
ParameterConstant <- "@" Identifier {
|
ParameterConstant <- "@" Identifier {
|
||||||
|
@ -291,11 +298,15 @@ FloatLiteral <- [0-9]+"."[0-9]+ {
|
||||||
floatValue, _ := strconv.ParseFloat(string(c.text), 64)
|
floatValue, _ := strconv.ParseFloat(string(c.text), 64)
|
||||||
return parsers.Constant{Type: parsers.ConstantTypeFloat, Value: floatValue}, nil
|
return parsers.Constant{Type: parsers.ConstantTypeFloat, Value: floatValue}, nil
|
||||||
}
|
}
|
||||||
BooleanLiteral <- ("true" / "false") {
|
BooleanLiteral <- ("true"i / "false"i) {
|
||||||
boolValue, _ := strconv.ParseBool(string(c.text))
|
boolValue, _ := strconv.ParseBool(string(c.text))
|
||||||
return parsers.Constant{Type: parsers.ConstantTypeBoolean, Value: boolValue}, nil
|
return parsers.Constant{Type: parsers.ConstantTypeBoolean, Value: boolValue}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringEqualsExpression <- StringEquals ws "(" ws ex1:SelectItem ws "," ws ex2:SelectItem ws ignoreCase:("," ws boolean:SelectItem { return boolean, nil })? ")" {
|
||||||
|
return parsers.FunctionCall{Type: parsers.FunctionCallStringEquals, Arguments: []interface{}{ex1, ex2, ignoreCase}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
Integer <- [0-9]+ {
|
Integer <- [0-9]+ {
|
||||||
return strconv.Atoi(string(c.text))
|
return strconv.Atoi(string(c.text))
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package nosql_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pikami/cosmium/parsers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Execute_StringFunctions(t *testing.T) {
|
||||||
|
|
||||||
|
t.Run("Should execute function STRINGEQUALS(ex1, ex2, ignoreCase)", func(t *testing.T) {
|
||||||
|
testQueryParse(
|
||||||
|
t,
|
||||||
|
`SELECT STRINGEQUALS(c.id, "123", true) FROM c`,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallStringEquals,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
parsers.SelectItem{
|
||||||
|
Path: []string{"c", "id"},
|
||||||
|
Type: parsers.SelectItemTypeField,
|
||||||
|
},
|
||||||
|
parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeString,
|
||||||
|
Value: "123",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeBoolean,
|
||||||
|
Value: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{Value: "c"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should execute function STRINGEQUALS(ex1, ex2)", func(t *testing.T) {
|
||||||
|
testQueryParse(
|
||||||
|
t,
|
||||||
|
`SELECT STRINGEQUALS(c.id, "123") FROM c`,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallStringEquals,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
parsers.SelectItem{
|
||||||
|
Path: []string{"c", "id"},
|
||||||
|
Type: parsers.SelectItemTypeField,
|
||||||
|
},
|
||||||
|
parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeString,
|
||||||
|
Value: "123",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{Value: "c"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
|
@ -161,6 +161,20 @@ func getFieldValue(field parsers.SelectItem, queryParameters map[string]interfac
|
||||||
return typedValue.Value
|
return typedValue.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if field.Type == parsers.SelectItemTypeFunctionCall {
|
||||||
|
var typedValue parsers.FunctionCall
|
||||||
|
var ok bool
|
||||||
|
if typedValue, ok = field.Value.(parsers.FunctionCall); !ok {
|
||||||
|
// TODO: Handle error
|
||||||
|
fmt.Println("parsers.Constant has incorrect Value type")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch typedValue.Type {
|
||||||
|
case parsers.FunctionCallStringEquals:
|
||||||
|
return strings_StringEquals(typedValue.Arguments, queryParameters, row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
value := row
|
value := row
|
||||||
if len(field.Path) > 1 {
|
if len(field.Path) > 1 {
|
||||||
for _, pathSegment := range field.Path[1:] {
|
for _, pathSegment := range field.Path[1:] {
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
package memoryexecutor_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pikami/cosmium/parsers"
|
||||||
|
memoryexecutor "github.com/pikami/cosmium/query_executors/memory_executor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Execute_StringFunctions(t *testing.T) {
|
||||||
|
mockData := []memoryexecutor.RowType{
|
||||||
|
map[string]interface{}{"id": "123", "pk": "aaa"},
|
||||||
|
map[string]interface{}{"id": "456", "pk": "bbb"},
|
||||||
|
map[string]interface{}{"id": "789", "pk": "AAA"},
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Should execute function STRINGEQUALS(ex1, ex2, ignoreCase)", func(t *testing.T) {
|
||||||
|
testQueryExecute(
|
||||||
|
t,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Path: []string{"c", "id"},
|
||||||
|
Type: parsers.SelectItemTypeField,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "stringEquals",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallStringEquals,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
parsers.SelectItem{
|
||||||
|
Path: []string{"c", "pk"},
|
||||||
|
Type: parsers.SelectItemTypeField,
|
||||||
|
},
|
||||||
|
parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeString,
|
||||||
|
Value: "aaa",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeBoolean,
|
||||||
|
Value: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{Value: "c"},
|
||||||
|
},
|
||||||
|
mockData,
|
||||||
|
[]memoryexecutor.RowType{
|
||||||
|
map[string]interface{}{"id": "123", "stringEquals": true},
|
||||||
|
map[string]interface{}{"id": "456", "stringEquals": false},
|
||||||
|
map[string]interface{}{"id": "789", "stringEquals": true},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should execute function STRINGEQUALS(ex1, ex2)", func(t *testing.T) {
|
||||||
|
testQueryExecute(
|
||||||
|
t,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Path: []string{"c", "id"},
|
||||||
|
Type: parsers.SelectItemTypeField,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "stringEquals",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallStringEquals,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
parsers.SelectItem{
|
||||||
|
Path: []string{"c", "pk"},
|
||||||
|
Type: parsers.SelectItemTypeField,
|
||||||
|
},
|
||||||
|
parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeString,
|
||||||
|
Value: "aaa",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{Value: "c"},
|
||||||
|
},
|
||||||
|
mockData,
|
||||||
|
[]memoryexecutor.RowType{
|
||||||
|
map[string]interface{}{"id": "123", "stringEquals": true},
|
||||||
|
map[string]interface{}{"id": "456", "stringEquals": false},
|
||||||
|
map[string]interface{}{"id": "789", "stringEquals": false},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package memoryexecutor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pikami/cosmium/parsers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func strings_StringEquals(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
||||||
|
ignoreCase := false
|
||||||
|
if len(arguments) > 2 && arguments[2] != nil {
|
||||||
|
ignoreCaseItem := arguments[2].(parsers.SelectItem)
|
||||||
|
if value, ok := getFieldValue(ignoreCaseItem, queryParameters, row).(bool); ok {
|
||||||
|
ignoreCase = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ex1Item := arguments[0].(parsers.SelectItem)
|
||||||
|
ex2Item := arguments[1].(parsers.SelectItem)
|
||||||
|
|
||||||
|
ex1 := getFieldValue(ex1Item, queryParameters, row)
|
||||||
|
ex2 := getFieldValue(ex2Item, queryParameters, row)
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
var str1 string
|
||||||
|
var str2 string
|
||||||
|
|
||||||
|
if str1, ok = ex1.(string); !ok {
|
||||||
|
fmt.Println("StringEquals got parameters of wrong type")
|
||||||
|
}
|
||||||
|
if str2, ok = ex2.(string); !ok {
|
||||||
|
fmt.Println("StringEquals got parameters of wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ignoreCase {
|
||||||
|
return strings.EqualFold(str1, str2)
|
||||||
|
}
|
||||||
|
|
||||||
|
return str1 == str2
|
||||||
|
}
|
Loading…
Reference in New Issue