mirror of https://github.com/pikami/cosmium.git
Implement INDEX_OF function
This commit is contained in:
parent
6a40492c7b
commit
59632ec966
|
@ -86,6 +86,7 @@ const (
|
||||||
FunctionCallContains FunctionCallType = "Contains"
|
FunctionCallContains FunctionCallType = "Contains"
|
||||||
FunctionCallEndsWith FunctionCallType = "EndsWith"
|
FunctionCallEndsWith FunctionCallType = "EndsWith"
|
||||||
FunctionCallStartsWith FunctionCallType = "StartsWith"
|
FunctionCallStartsWith FunctionCallType = "StartsWith"
|
||||||
|
FunctionCallIndexOf FunctionCallType = "IndexOf"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FunctionCall struct {
|
type FunctionCall struct {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -240,7 +240,7 @@ AndExpression <- ex1:ComparisonExpression ex2:(ws And ws ex:ComparisonExpression
|
||||||
|
|
||||||
ComparisonExpression <- "(" ws ex:OrExpression ws ")" { return ex, nil }
|
ComparisonExpression <- "(" ws ex:OrExpression ws ")" { return ex, nil }
|
||||||
/ left:SelectItem ws op:ComparisonOperator ws right:SelectItem {
|
/ left:SelectItem ws op:ComparisonOperator ws right:SelectItem {
|
||||||
return parsers.ComparisonExpression{Left:left,Right:right,Operation:string(op.([]uint8))}, nil
|
return parsers.ComparisonExpression{Left:left,Right:right,Operation:op.(string)}, nil
|
||||||
} / ex:BooleanLiteral { return ex, nil }
|
} / ex:BooleanLiteral { return ex, nil }
|
||||||
/ ex:SelectItem { return ex, nil }
|
/ ex:SelectItem { return ex, nil }
|
||||||
|
|
||||||
|
@ -276,7 +276,7 @@ Or <- "OR"i
|
||||||
|
|
||||||
OrderBy <- "ORDER"i ws "BY"i
|
OrderBy <- "ORDER"i ws "BY"i
|
||||||
|
|
||||||
ComparisonOperator <- "=" / "!=" / "<" / "<=" / ">" / ">=" {
|
ComparisonOperator <- ("=" / "!=" / "<" / "<=" / ">" / ">=") {
|
||||||
return string(c.text), nil
|
return string(c.text), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,12 +332,16 @@ ThreeArgumentStringFunctionExpression <- function:ThreeArgumentStringFunction ws
|
||||||
functionType = parsers.FunctionCallEndsWith
|
functionType = parsers.FunctionCallEndsWith
|
||||||
case "STARTSWITH":
|
case "STARTSWITH":
|
||||||
functionType = parsers.FunctionCallStartsWith
|
functionType = parsers.FunctionCallStartsWith
|
||||||
|
case "INDEX_OF":
|
||||||
|
functionType = parsers.FunctionCallIndexOf
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsers.FunctionCall{Type: functionType, Arguments: []interface{}{ex1, ex2, ignoreCase}}, nil
|
return parsers.FunctionCall{Type: functionType, Arguments: []interface{}{ex1, ex2, ignoreCase}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreeArgumentStringFunction <- "CONTAINS"i / "ENDSWITH"i / "STARTSWITH"i
|
ThreeArgumentStringFunction <- ("CONTAINS"i / "ENDSWITH"i / "STARTSWITH"i / "INDEX_OF"i) {
|
||||||
|
return string(c.text), nil
|
||||||
|
}
|
||||||
|
|
||||||
IsDefined <- "IS_DEFINED"i ws "(" ws ex:SelectItem ws ")" {
|
IsDefined <- "IS_DEFINED"i ws "(" ws ex:SelectItem ws ")" {
|
||||||
return parsers.FunctionCall{Type: parsers.FunctionCallIsDefined, Arguments: []interface{}{ex}}, nil
|
return parsers.FunctionCall{Type: parsers.FunctionCallIsDefined, Arguments: []interface{}{ex}}, nil
|
||||||
|
|
|
@ -226,4 +226,42 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Should parse function INDEX_OF()", func(t *testing.T) {
|
||||||
|
testQueryParse(
|
||||||
|
t,
|
||||||
|
`SELECT INDEX_OF(c.id, "2", 1) FROM c`,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallIndexOf,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
parsers.SelectItem{
|
||||||
|
Path: []string{"c", "id"},
|
||||||
|
Type: parsers.SelectItemTypeField,
|
||||||
|
},
|
||||||
|
parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeString,
|
||||||
|
Value: "2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeInteger,
|
||||||
|
Value: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{Value: "c"},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,6 +186,8 @@ func getFieldValue(field parsers.SelectItem, queryParameters map[string]interfac
|
||||||
return strings_StartsWith(typedValue.Arguments, queryParameters, row)
|
return strings_StartsWith(typedValue.Arguments, queryParameters, row)
|
||||||
case parsers.FunctionCallConcat:
|
case parsers.FunctionCallConcat:
|
||||||
return strings_Concat(typedValue.Arguments, queryParameters, row)
|
return strings_Concat(typedValue.Arguments, queryParameters, row)
|
||||||
|
case parsers.FunctionCallIndexOf:
|
||||||
|
return strings_IndexOf(typedValue.Arguments, queryParameters, row)
|
||||||
case parsers.FunctionCallIsDefined:
|
case parsers.FunctionCallIsDefined:
|
||||||
return typeChecking_IsDefined(typedValue.Arguments, queryParameters, row)
|
return typeChecking_IsDefined(typedValue.Arguments, queryParameters, row)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ import (
|
||||||
|
|
||||||
func Test_Execute_StringFunctions(t *testing.T) {
|
func Test_Execute_StringFunctions(t *testing.T) {
|
||||||
mockData := []memoryexecutor.RowType{
|
mockData := []memoryexecutor.RowType{
|
||||||
map[string]interface{}{"id": "123", "pk": "aaa"},
|
map[string]interface{}{"id": "123", "pk": "aaa", "str": "hello"},
|
||||||
map[string]interface{}{"id": "456", "pk": "bbb"},
|
map[string]interface{}{"id": "456", "pk": "bbb", "str": "world"},
|
||||||
map[string]interface{}{"id": "789", "pk": "AAA"},
|
map[string]interface{}{"id": "789", "pk": "AAA", "str": "cool world"},
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("Should execute function STRINGEQUALS(ex1, ex2, ignoreCase)", func(t *testing.T) {
|
t.Run("Should execute function STRINGEQUALS(ex1, ex2, ignoreCase)", func(t *testing.T) {
|
||||||
|
@ -295,4 +295,52 @@ func Test_Execute_StringFunctions(t *testing.T) {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Should execute function INDEX_OF()", func(t *testing.T) {
|
||||||
|
testQueryExecute(
|
||||||
|
t,
|
||||||
|
parsers.SelectStmt{
|
||||||
|
SelectItems: []parsers.SelectItem{
|
||||||
|
{
|
||||||
|
Path: []string{"c", "str"},
|
||||||
|
Type: parsers.SelectItemTypeField,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alias: "index",
|
||||||
|
Type: parsers.SelectItemTypeFunctionCall,
|
||||||
|
Value: parsers.FunctionCall{
|
||||||
|
Type: parsers.FunctionCallIndexOf,
|
||||||
|
Arguments: []interface{}{
|
||||||
|
parsers.SelectItem{
|
||||||
|
Path: []string{"c", "str"},
|
||||||
|
Type: parsers.SelectItemTypeField,
|
||||||
|
},
|
||||||
|
parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeString,
|
||||||
|
Value: "o",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
parsers.SelectItem{
|
||||||
|
Type: parsers.SelectItemTypeConstant,
|
||||||
|
Value: parsers.Constant{
|
||||||
|
Type: parsers.ConstantTypeInteger,
|
||||||
|
Value: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Table: parsers.Table{Value: "c"},
|
||||||
|
},
|
||||||
|
mockData,
|
||||||
|
[]memoryexecutor.RowType{
|
||||||
|
map[string]interface{}{"str": "hello", "index": 4},
|
||||||
|
map[string]interface{}{"str": "world", "index": -1},
|
||||||
|
map[string]interface{}{"str": "cool world", "index": 6},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,31 @@ func strings_Concat(arguments []interface{}, queryParameters map[string]interfac
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func strings_IndexOf(arguments []interface{}, queryParameters map[string]interface{}, row RowType) int {
|
||||||
|
str1 := parseString(arguments[0], queryParameters, row)
|
||||||
|
str2 := parseString(arguments[1], queryParameters, row)
|
||||||
|
|
||||||
|
start := 0
|
||||||
|
if len(arguments) > 2 && arguments[2] != nil {
|
||||||
|
if startPos, ok := getFieldValue(arguments[2].(parsers.SelectItem), queryParameters, row).(int); ok {
|
||||||
|
start = startPos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(str1) <= start {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
str1 = str1[start:]
|
||||||
|
result := strings.Index(str1, str2)
|
||||||
|
|
||||||
|
if result == -1 {
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
return result + start
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func getBoolFlag(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
func getBoolFlag(arguments []interface{}, queryParameters map[string]interface{}, row RowType) bool {
|
||||||
ignoreCase := false
|
ignoreCase := false
|
||||||
if len(arguments) > 2 && arguments[2] != nil {
|
if len(arguments) > 2 && arguments[2] != nil {
|
||||||
|
|
Loading…
Reference in New Issue