mirror of
https://github.com/pikami/cosmium.git
synced 2026-07-30 17:47:02 +01:00
c78842726b
* Support single-quoted string literals in query parsing
Add single-quoted string literal support to the NoSQL query parser,
matching Cosmos DB behavior where apostrophes are escaped by doubling
them (''). Includes parser unit tests and an API integration test.
Co-authored-by: Pijus Kamandulis <pikami@users.noreply.github.com>
* Use backslash escape for apostrophes in single-quoted strings
Cosmos DB escapes apostrophes with \' rather than SQL-style doubling.
Also fix EscapeCharacter to return proper values for \', \", and \\
which were previously producing empty substitutions.
Co-authored-by: Pijus Kamandulis <pikami@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
896 lines
33 KiB
Plaintext
896 lines
33 KiB
Plaintext
{
|
|
package nosql
|
|
|
|
import "github.com/pikami/cosmium/parsers"
|
|
|
|
func makeSelectStmt(
|
|
columns, fromClause, joinItems,
|
|
whereClause interface{}, distinctClause interface{},
|
|
count interface{}, groupByClause interface{}, orderList interface{},
|
|
offsetClause interface{},
|
|
) (parsers.SelectStmt, error) {
|
|
selectStmt := parsers.SelectStmt{
|
|
SelectItems: columns.([]parsers.SelectItem),
|
|
}
|
|
|
|
if fromTable, ok := fromClause.(parsers.Table); ok {
|
|
selectStmt.Table = fromTable
|
|
}
|
|
|
|
if joinItemsArray, ok := joinItems.([]interface{}); ok && len(joinItemsArray) > 0 {
|
|
selectStmt.JoinItems = make([]parsers.JoinItem, len(joinItemsArray))
|
|
for i, joinItem := range joinItemsArray {
|
|
selectStmt.JoinItems[i] = joinItem.(parsers.JoinItem)
|
|
}
|
|
}
|
|
|
|
switch v := whereClause.(type) {
|
|
case parsers.ComparisonExpression, parsers.LogicalExpression, parsers.Constant, parsers.SelectItem:
|
|
selectStmt.Filters = v
|
|
}
|
|
|
|
if distinctClause != nil {
|
|
selectStmt.Distinct = true
|
|
}
|
|
|
|
if n, ok := count.(int); ok {
|
|
selectStmt.Count = n
|
|
}
|
|
|
|
if offsetArr, ok := offsetClause.([]interface{}); ok && len(offsetArr) == 2 {
|
|
if n, ok := offsetArr[0].(int); ok {
|
|
selectStmt.Offset = n
|
|
}
|
|
|
|
if n, ok := offsetArr[1].(int); ok {
|
|
selectStmt.Count = n
|
|
}
|
|
}
|
|
|
|
if orderExpressions, ok := orderList.([]parsers.OrderExpression); ok {
|
|
selectStmt.OrderExpressions = orderExpressions
|
|
}
|
|
|
|
if groupByClause != nil {
|
|
selectStmt.GroupBy = groupByClause.([]parsers.SelectItem)
|
|
}
|
|
|
|
return selectStmt, nil
|
|
}
|
|
|
|
func makeJoin(table interface{}, column interface{}) (parsers.JoinItem, error) {
|
|
joinItem := parsers.JoinItem{}
|
|
|
|
if selectItem, isSelectItem := column.(parsers.SelectItem); isSelectItem {
|
|
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) {
|
|
ps := path.([]interface{})
|
|
|
|
paths := make([]string, 1)
|
|
paths[0] = name.(string)
|
|
for _, p := range ps {
|
|
paths = append(paths, p.(string))
|
|
}
|
|
|
|
return parsers.SelectItem{Path: paths, Type: selectItemType}, nil
|
|
}
|
|
|
|
func makeColumnList(column interface{}, other_columns interface{}) ([]parsers.SelectItem, error) {
|
|
collsAsArray := other_columns.([]interface{})
|
|
columnList := make([]parsers.SelectItem, len(collsAsArray) + 1)
|
|
columnList[0] = column.(parsers.SelectItem)
|
|
|
|
for i, v := range collsAsArray {
|
|
if col, ok := v.(parsers.SelectItem); ok {
|
|
columnList[i+1] = col
|
|
}
|
|
}
|
|
|
|
return columnList, nil
|
|
}
|
|
|
|
func makeSelectArray(columns interface{}) (parsers.SelectItem, error) {
|
|
return parsers.SelectItem{
|
|
SelectItems: columns.([]parsers.SelectItem),
|
|
Type: parsers.SelectItemTypeArray,
|
|
}, nil
|
|
}
|
|
|
|
func makeSelectObject(field interface{}, other_fields interface{}) (parsers.SelectItem, error) {
|
|
fieldsAsArray := other_fields.([]interface{})
|
|
fieldsList := make([]parsers.SelectItem, len(fieldsAsArray)+1)
|
|
fieldsList[0] = field.(parsers.SelectItem)
|
|
|
|
for i, v := range fieldsAsArray {
|
|
if col, ok := v.(parsers.SelectItem); ok {
|
|
fieldsList[i+1] = col
|
|
}
|
|
}
|
|
|
|
return parsers.SelectItem{
|
|
SelectItems: fieldsList,
|
|
Type: parsers.SelectItemTypeObject,
|
|
}, nil
|
|
}
|
|
|
|
func makeOrderByClause(ex1 interface{}, others interface{}) ([]parsers.OrderExpression, error) {
|
|
othersArray := others.([]interface{})
|
|
orderList := make([]parsers.OrderExpression, len(othersArray)+1)
|
|
orderList[0] = ex1.(parsers.OrderExpression)
|
|
|
|
for i, v := range othersArray {
|
|
if col, ok := v.(parsers.OrderExpression); ok {
|
|
orderList[i+1] = col
|
|
}
|
|
}
|
|
|
|
return orderList, nil
|
|
}
|
|
|
|
func makeOrderExpression(field interface{}, order interface{}) (parsers.OrderExpression, error) {
|
|
value := parsers.OrderExpression{
|
|
SelectItem: field.(parsers.SelectItem),
|
|
Direction: parsers.OrderDirectionAsc,
|
|
}
|
|
|
|
if orderValue, ok := order.(parsers.OrderDirection); ok {
|
|
value.Direction = orderValue
|
|
}
|
|
|
|
return value, nil
|
|
}
|
|
|
|
func createFunctionCall(functionType parsers.FunctionCallType, arguments []interface{}) (parsers.FunctionCall, error) {
|
|
return parsers.FunctionCall{Type: functionType, Arguments: arguments}, nil
|
|
}
|
|
|
|
func joinStrings(array []interface{}) string {
|
|
var stringsArray []string
|
|
for _, elem := range array {
|
|
str, ok := elem.(string)
|
|
if !ok {
|
|
continue
|
|
}
|
|
stringsArray = append(stringsArray, str)
|
|
}
|
|
|
|
return strings.Join(stringsArray, "")
|
|
}
|
|
|
|
func combineExpressions(ex1 interface{}, exs interface{}, operation parsers.LogicalExpressionType) (interface{}, error) {
|
|
if exs == nil || len(exs.([]interface{})) < 1 {
|
|
return ex1, nil
|
|
}
|
|
|
|
return parsers.LogicalExpression{
|
|
Expressions: append([]interface{}{ex1}, exs.([]interface{})...),
|
|
Operation: operation,
|
|
}, nil
|
|
}
|
|
|
|
func makeMathExpression(left interface{}, operations interface{}) (interface{}, error) {
|
|
if operations == nil || len(operations.([]interface{})) == 0 {
|
|
return left, nil
|
|
}
|
|
|
|
result := left.(parsers.SelectItem)
|
|
ops := operations.([]interface{})
|
|
|
|
for _, op := range ops {
|
|
opData := op.([]interface{})
|
|
operation := opData[0].(string)
|
|
right := opData[1].(parsers.SelectItem)
|
|
|
|
result = parsers.SelectItem{
|
|
Type: parsers.SelectItemTypeBinaryExpression,
|
|
Value: parsers.BinaryExpression{
|
|
Left: result,
|
|
Right: right,
|
|
Operation: operation,
|
|
},
|
|
}
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
}
|
|
|
|
Input <- selectStmt:SelectStmt {
|
|
return selectStmt, nil
|
|
}
|
|
|
|
SelectStmt <- Select ws
|
|
distinctClause:DistinctClause? ws
|
|
topClause:TopClause? ws
|
|
columns:Selection ws
|
|
fromClause:FromClause? ws
|
|
joinClauses:(ws join:JoinClause { return join, nil })* ws
|
|
whereClause:(ws Where ws condition:Condition { return condition, nil })?
|
|
groupByClause:(ws GroupBy ws columns:ColumnList { return columns, nil })?
|
|
orderByClause:(ws order:OrderByClause { return order, nil })?
|
|
offsetClause:(ws offset:OffsetClause { return offset, nil })? {
|
|
return makeSelectStmt(columns, fromClause, joinClauses, whereClause,
|
|
distinctClause, topClause, groupByClause, orderByClause, offsetClause)
|
|
}
|
|
|
|
DistinctClause <- "DISTINCT"i
|
|
|
|
TopClause <- Top ws count:Integer {
|
|
return count, nil
|
|
}
|
|
|
|
FromClause <- From ws table:TableName selectItem:(ws In ws column:SelectItemWithAlias { return column, nil }) {
|
|
tableTyped := table.(parsers.Table)
|
|
|
|
if selectItem != nil {
|
|
tableTyped.SelectItem = selectItem.(parsers.SelectItem)
|
|
tableTyped.IsInSelect = true
|
|
}
|
|
|
|
return tableTyped, nil
|
|
} / From ws column:SelectItemWithAlias {
|
|
tableSelectItem := column.(parsers.SelectItem)
|
|
table := parsers.Table{
|
|
Value: tableSelectItem.Alias,
|
|
SelectItem: tableSelectItem,
|
|
}
|
|
return table, 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 ws column:SelectItemWithAlias {
|
|
return makeJoin(table, column)
|
|
} / Join ws subQuery:SubQuerySelectItem {
|
|
return makeJoin(nil, subQuery)
|
|
}
|
|
|
|
OffsetClause <- Offset ws offset:IntegerLiteral ws "LIMIT"i ws limit:IntegerLiteral {
|
|
return []interface{}{offset.(parsers.Constant).Value, limit.(parsers.Constant).Value}, nil
|
|
}
|
|
|
|
Selection <- SelectValueSpec / ColumnList / SelectAsterisk
|
|
|
|
SelectAsterisk <- "*" {
|
|
selectItem, _ := makeSelectItem("c", make([]interface{}, 0), parsers.SelectItemTypeField)
|
|
selectItem.IsTopLevel = true
|
|
return makeColumnList(selectItem, make([]interface{}, 0))
|
|
}
|
|
|
|
ColumnList <- column:ExpressionOrSelectItem other_columns:(ws "," ws coll:ExpressionOrSelectItem {return coll, nil })* {
|
|
return makeColumnList(column, other_columns)
|
|
}
|
|
|
|
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.IsTopLevel = true
|
|
return makeColumnList(selectItem, make([]interface{}, 0))
|
|
}
|
|
|
|
TableName <- key:Identifier {
|
|
return parsers.Table{Value: key.(string)}, nil
|
|
}
|
|
|
|
SelectArray <- "[" ws columns:ColumnList ws "]" {
|
|
return makeSelectArray(columns)
|
|
}
|
|
|
|
SelectObject <- "{" ws field:SelectObjectField ws other_fields:(ws "," ws coll:SelectObjectField {return coll, nil })* ws "}" {
|
|
return makeSelectObject(field, other_fields)
|
|
} / "{" ws "}" {
|
|
return parsers.SelectItem{
|
|
SelectItems: []parsers.SelectItem{},
|
|
Type: parsers.SelectItemTypeObject,
|
|
}, nil
|
|
}
|
|
|
|
SelectObjectField <- name:(Identifier / "\"" key:Identifier "\"" { return key, nil }) ws ":" ws selectItem:SelectItem {
|
|
item := selectItem.(parsers.SelectItem)
|
|
item.Alias = name.(string)
|
|
return item, nil
|
|
}
|
|
|
|
SelectProperty <- name:Identifier path:(DotFieldAccess / ArrayFieldAccess)* {
|
|
return makeSelectItem(name, path, parsers.SelectItemTypeField)
|
|
}
|
|
|
|
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
|
|
switch typedValue := selectItem.(type) {
|
|
case parsers.SelectItem:
|
|
itemResult = typedValue
|
|
case parsers.Constant:
|
|
itemResult = parsers.SelectItem{
|
|
Type: parsers.SelectItemTypeConstant,
|
|
Value: typedValue,
|
|
}
|
|
case parsers.FunctionCall:
|
|
itemResult = parsers.SelectItem{
|
|
Type: parsers.SelectItemTypeFunctionCall,
|
|
Value: typedValue,
|
|
}
|
|
}
|
|
|
|
return itemResult, nil
|
|
}
|
|
|
|
AsClause <- (ws As)? ws !ExcludedKeywords alias:Identifier {
|
|
return alias, nil
|
|
}
|
|
|
|
ExcludedKeywords <- Select / Top / As / From / In / Join / Exists / Where / And / Or / Not / GroupBy / OrderBy / Offset
|
|
|
|
DotFieldAccess <- "." id:Identifier {
|
|
return id, nil
|
|
}
|
|
|
|
ArrayFieldAccess <- "[\"" id:Identifier "\"]" { return id, nil }
|
|
/ "[" id:Integer "]" { return strconv.Itoa(id.(int)), nil }
|
|
/ "[" id:ParameterConstant "]" { return id.(parsers.Constant).Value.(string), nil }
|
|
|
|
Identifier <- [a-zA-Z_][a-zA-Z0-9_]* {
|
|
return string(c.text), nil
|
|
}
|
|
|
|
Condition <- expression:OrExpression {
|
|
return expression, nil
|
|
}
|
|
|
|
OrExpression <- ex1:AndExpression ex2:(ws Or ws ex:AndExpression { return ex, nil })* {
|
|
return combineExpressions(ex1, ex2, parsers.LogicalExpressionTypeOr)
|
|
}
|
|
|
|
AndExpression <- ex1:ComparisonExpression ex2:(ws And ws ex:ComparisonExpression { return ex, nil })* {
|
|
return combineExpressions(ex1, ex2, parsers.LogicalExpressionTypeAnd)
|
|
}
|
|
|
|
ComparisonExpression <- left:AddSubExpression ws op:ComparisonOperator ws right:AddSubExpression {
|
|
return parsers.ComparisonExpression{Left:left,Right:right,Operation:op.(string)}, nil
|
|
} / ex:AddSubExpression { return ex, nil }
|
|
|
|
AddSubExpression <- left:MulDivExpression operations:(ws op:AddOrSubtractOperation ws right:MulDivExpression { return []interface{}{op, right}, nil })* {
|
|
return makeMathExpression(left, operations)
|
|
}
|
|
|
|
MulDivExpression <- left:SelectItemWithParentheses operations:(ws op:MultiplyOrDivideOperation ws right:SelectItemWithParentheses { return []interface{}{op, right}, nil })* {
|
|
return makeMathExpression(left, operations)
|
|
}
|
|
|
|
SelectItemWithParentheses <- inv:(Not ws)? "(" ws ex:OrExpression ws ")" {
|
|
if inv != nil {
|
|
if ex1, ok := ex.(parsers.SelectItem); ok {
|
|
ex1.Invert = true
|
|
return ex1, nil
|
|
}
|
|
}
|
|
return ex, nil
|
|
}
|
|
/ inv:(Not ws)? ex:SelectItem {
|
|
if inv != nil {
|
|
ex1 := ex.(parsers.SelectItem)
|
|
ex1.Invert = true
|
|
return ex1, nil
|
|
}
|
|
return ex, nil
|
|
} / ex:BooleanLiteral { return ex, nil }
|
|
|
|
OrderByClause <- OrderBy ws ex1:OrderExpression others:(ws "," ws ex:OrderExpression { return ex, nil })* {
|
|
return makeOrderByClause(ex1, others)
|
|
}
|
|
|
|
OrderExpression <- field:SelectProperty ws order:OrderDirection? {
|
|
return makeOrderExpression(field, order)
|
|
}
|
|
|
|
OrderDirection <- ("ASC"i / "DESC"i) {
|
|
if strings.EqualFold(string(c.text), "DESC") {
|
|
return parsers.OrderDirectionDesc, nil
|
|
}
|
|
|
|
return parsers.OrderDirectionAsc, nil
|
|
}
|
|
|
|
Select <- "SELECT"i
|
|
|
|
Top <- "TOP"i
|
|
|
|
As <- "AS"i
|
|
|
|
From <- "FROM"i
|
|
|
|
In <- "IN"i
|
|
|
|
Join <- "JOIN"i
|
|
|
|
Exists <- "EXISTS"i
|
|
|
|
Where <- "WHERE"i
|
|
|
|
And <- "AND"i
|
|
|
|
Or <- "OR"i wss
|
|
|
|
Not <- "NOT"i
|
|
|
|
GroupBy <- "GROUP"i ws "BY"i
|
|
|
|
OrderBy <- "ORDER"i ws "BY"i
|
|
|
|
Offset <- "OFFSET"i
|
|
|
|
ComparisonOperator <- ("<=" / ">=" / "=" / "!=" / "<" / ">") {
|
|
return string(c.text), nil
|
|
}
|
|
|
|
AddOrSubtractOperation <- ("+" / "-") { return string(c.text), nil }
|
|
|
|
MultiplyOrDivideOperation <- ("*" / "/") { return string(c.text), nil }
|
|
|
|
Literal <- FloatLiteral / IntegerLiteral / StringLiteral / BooleanLiteral / ParameterConstant / NullConstant
|
|
|
|
ParameterConstant <- "@" Identifier {
|
|
return parsers.Constant{Type: parsers.ConstantTypeParameterConstant, Value: string(c.text)}, nil
|
|
}
|
|
NullConstant <- "null"i {
|
|
return parsers.Constant{Value: nil}, nil
|
|
}
|
|
|
|
IntegerLiteral <- number:Integer {
|
|
return parsers.Constant{Type: parsers.ConstantTypeInteger, Value: number.(int)}, nil
|
|
}
|
|
StringLiteral <- "\"" chars:StringCharacter* "\"" {
|
|
return parsers.Constant{Type: parsers.ConstantTypeString,Value: joinStrings(chars.([]interface{}))}, nil
|
|
} / "'" chars:SingleQuotedStringCharacter* "'" {
|
|
return parsers.Constant{Type: parsers.ConstantTypeString,Value: joinStrings(chars.([]interface{}))}, nil
|
|
}
|
|
FloatLiteral <- [0-9]+"."[0-9]+ {
|
|
floatValue, _ := strconv.ParseFloat(string(c.text), 64)
|
|
return parsers.Constant{Type: parsers.ConstantTypeFloat, Value: floatValue}, nil
|
|
}
|
|
BooleanLiteral <- ("true"i / "false"i) {
|
|
boolValue, _ := strconv.ParseBool(string(c.text))
|
|
return parsers.Constant{Type: parsers.ConstantTypeBoolean, Value: boolValue}, nil
|
|
}
|
|
|
|
FunctionCall <- StringFunctions
|
|
/ TypeCheckingFunctions
|
|
/ ArrayFunctions
|
|
/ ConditionalFunctions
|
|
/ InFunction
|
|
/ AggregateFunctions
|
|
/ MathFunctions
|
|
|
|
StringFunctions <- StringEqualsExpression
|
|
/ ToStringExpression
|
|
/ ConcatExpression
|
|
/ ThreeArgumentStringFunctionExpression
|
|
/ UpperExpression
|
|
/ LowerExpression
|
|
/ LeftExpression
|
|
/ LengthExpression
|
|
/ LTrimExpression
|
|
/ ReplaceExpression
|
|
/ ReplicateExpression
|
|
/ ReverseExpression
|
|
/ RightExpression
|
|
/ RTrimExpression
|
|
/ SubstringExpression
|
|
/ TrimExpression
|
|
|
|
TypeCheckingFunctions <- IsDefined
|
|
/ IsArray
|
|
/ IsBool
|
|
/ IsFiniteNumber
|
|
/ IsInteger
|
|
/ IsNull
|
|
/ IsNumber
|
|
/ IsObject
|
|
/ IsPrimitive
|
|
/ IsString
|
|
|
|
AggregateFunctions <- AvgAggregateExpression
|
|
/ CountAggregateExpression
|
|
/ MaxAggregateExpression
|
|
/ MinAggregateExpression
|
|
/ SumAggregateExpression
|
|
|
|
ArrayFunctions <- ArrayConcatExpression
|
|
/ ArrayContainsExpression
|
|
/ ArrayContainsAnyExpression
|
|
/ ArrayContainsAllExpression
|
|
/ ArrayLengthExpression
|
|
/ ArraySliceExpression
|
|
/ SetIntersectExpression
|
|
/ SetUnionExpression
|
|
|
|
ConditionalFunctions <- IifExpression
|
|
|
|
MathFunctions <- MathAbsExpression
|
|
/ MathAcosExpression
|
|
/ MathAsinExpression
|
|
/ MathAtanExpression
|
|
/ MathCeilingExpression
|
|
/ MathCosExpression
|
|
/ MathCotExpression
|
|
/ MathDegreesExpression
|
|
/ MathExpExpression
|
|
/ MathFloorExpression
|
|
/ MathIntBitNotExpression
|
|
/ MathLog10Expression
|
|
/ MathRadiansExpression
|
|
/ MathRoundExpression
|
|
/ MathSignExpression
|
|
/ MathSinExpression
|
|
/ MathSqrtExpression
|
|
/ MathSquareExpression
|
|
/ MathTanExpression
|
|
/ MathTruncExpression
|
|
/ MathAtn2Expression
|
|
/ MathIntAddExpression
|
|
/ MathIntBitAndExpression
|
|
/ MathIntBitLeftShiftExpression
|
|
/ MathIntBitOrExpression
|
|
/ MathIntBitRightShiftExpression
|
|
/ MathIntBitXorExpression
|
|
/ MathIntDivExpression
|
|
/ MathIntModExpression
|
|
/ MathIntMulExpression
|
|
/ MathIntSubExpression
|
|
/ MathPowerExpression
|
|
/ MathLogExpression
|
|
/ MathNumberBinExpression
|
|
/ MathPiExpression
|
|
/ MathRandExpression
|
|
|
|
UpperExpression <- "UPPER"i ws "(" ex:SelectItem ")" {
|
|
return createFunctionCall(parsers.FunctionCallUpper, []interface{}{ex})
|
|
}
|
|
|
|
LowerExpression <- "LOWER"i ws "(" ex:SelectItem ")" {
|
|
return createFunctionCall(parsers.FunctionCallLower, []interface{}{ex})
|
|
}
|
|
|
|
StringEqualsExpression <- "STRINGEQUALS"i ws "(" ws ex1:SelectItem ws "," ws ex2:SelectItem ws ignoreCase:("," ws boolean:SelectItem { return boolean, nil })? ")" {
|
|
return createFunctionCall(parsers.FunctionCallStringEquals, []interface{}{ex1, ex2, ignoreCase})
|
|
}
|
|
|
|
ToStringExpression <- "TOSTRING"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallToString, []interface{}{ex})
|
|
}
|
|
|
|
ConcatExpression <- "CONCAT"i ws "(" ws ex1:SelectItem others:(ws "," ws ex:SelectItem { return ex, nil })+ ws ")" {
|
|
arguments := append([]interface{}{ex1}, others.([]interface{})...)
|
|
return createFunctionCall(parsers.FunctionCallConcat, arguments)
|
|
}
|
|
|
|
LeftExpression <- "LEFT"i ws "(" ws ex:SelectItem ws "," ws length:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallLeft, []interface{}{ex, length})
|
|
}
|
|
|
|
LengthExpression <- "LENGTH"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallLength, []interface{}{ex})
|
|
}
|
|
|
|
LTrimExpression <- "LTRIM"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallLTrim, []interface{}{ex})
|
|
}
|
|
|
|
ReplaceExpression <- "REPLACE"i ws "(" ws ex1:SelectItem ws "," ws ex2:SelectItem ws "," ws ex3:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallReplace, []interface{}{ex1, ex2, ex3})
|
|
}
|
|
|
|
ReplicateExpression <- "REPLICATE"i ws "(" ws ex1:SelectItem ws "," ws ex2:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallReplicate, []interface{}{ex1, ex2})
|
|
}
|
|
|
|
ReverseExpression <- "REVERSE"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallReverse, []interface{}{ex})
|
|
}
|
|
|
|
RightExpression <- "RIGHT"i ws "(" ws ex:SelectItem ws "," ws length:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallRight, []interface{}{ex, length})
|
|
}
|
|
|
|
RTrimExpression <- "RTRIM"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallRTrim, []interface{}{ex})
|
|
}
|
|
|
|
SubstringExpression <- "SUBSTRING"i ws "(" ws ex:SelectItem ws "," ws startPos:SelectItem ws "," ws length:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallSubstring, []interface{}{ex, startPos, length})
|
|
}
|
|
|
|
TrimExpression <- "TRIM"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallTrim, []interface{}{ex})
|
|
}
|
|
|
|
ThreeArgumentStringFunctionExpression <- function:ThreeArgumentStringFunction ws "(" ws ex1:SelectItem ws "," ws ex2:SelectItem ws ignoreCase:("," ws boolean:SelectItem { return boolean, nil })? ")" {
|
|
var functionType parsers.FunctionCallType
|
|
|
|
lowerFunction := strings.ToUpper(function.(string))
|
|
switch lowerFunction {
|
|
case "CONTAINS":
|
|
functionType = parsers.FunctionCallContains
|
|
case "ENDSWITH":
|
|
functionType = parsers.FunctionCallEndsWith
|
|
case "STARTSWITH":
|
|
functionType = parsers.FunctionCallStartsWith
|
|
case "REGEXMATCH":
|
|
functionType = parsers.FunctionCallRegexMatch
|
|
case "INDEX_OF":
|
|
functionType = parsers.FunctionCallIndexOf
|
|
}
|
|
|
|
return createFunctionCall(functionType, []interface{}{ex1, ex2, ignoreCase})
|
|
}
|
|
|
|
ThreeArgumentStringFunction <- ("CONTAINS"i / "ENDSWITH"i / "STARTSWITH"i / "REGEXMATCH"i / "INDEX_OF"i) {
|
|
return string(c.text), nil
|
|
}
|
|
|
|
IsDefined <- "IS_DEFINED"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallIsDefined, []interface{}{ex})
|
|
}
|
|
|
|
IsArray <- "IS_ARRAY"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallIsArray, []interface{}{ex})
|
|
}
|
|
|
|
IsBool <- "IS_BOOL"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallIsBool, []interface{}{ex})
|
|
}
|
|
|
|
IsFiniteNumber <- "IS_FINITE_NUMBER"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallIsFiniteNumber, []interface{}{ex})
|
|
}
|
|
|
|
IsInteger <- "IS_INTEGER"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallIsInteger, []interface{}{ex})
|
|
}
|
|
|
|
IsNull <- "IS_NULL"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallIsNull, []interface{}{ex})
|
|
}
|
|
|
|
IsNumber <- "IS_NUMBER"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallIsNumber, []interface{}{ex})
|
|
}
|
|
|
|
IsObject <- "IS_OBJECT"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallIsObject, []interface{}{ex})
|
|
}
|
|
|
|
IsPrimitive <- "IS_PRIMITIVE"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallIsPrimitive, []interface{}{ex})
|
|
}
|
|
|
|
IsString <- "IS_STRING"i ws "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallIsString, []interface{}{ex})
|
|
}
|
|
|
|
ArrayConcatExpression <- "ARRAY_CONCAT"i ws "(" ws arrays:SelectItem others:(ws "," ws ex:SelectItem { return ex, nil })+ ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallArrayConcat, append([]interface{}{arrays}, others.([]interface{})...))
|
|
}
|
|
|
|
ArrayContainsExpression <- "ARRAY_CONTAINS"i ws "(" ws array:SelectItem ws "," ws item:SelectItem partialMatch:(ws "," ws ex:SelectItem { return ex, nil })? ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallArrayContains, []interface{}{array, item, partialMatch})
|
|
}
|
|
|
|
ArrayContainsAnyExpression <- "ARRAY_CONTAINS_ANY"i ws "(" ws array:SelectItem items:(ws "," ws ex:SelectItem { return ex, nil })+ ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallArrayContainsAny, append([]interface{}{array}, items.([]interface{})...))
|
|
}
|
|
|
|
ArrayContainsAllExpression <- "ARRAY_CONTAINS_ALL"i ws "(" ws array:SelectItem items:(ws "," ws ex:SelectItem { return ex, nil })+ ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallArrayContainsAll, append([]interface{}{array}, items.([]interface{})...))
|
|
}
|
|
|
|
ArrayLengthExpression <- "ARRAY_LENGTH"i ws "(" ws array:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallArrayLength, []interface{}{array})
|
|
}
|
|
|
|
ArraySliceExpression <- "ARRAY_SLICE"i ws "(" ws array:SelectItem ws "," ws start:SelectItem length:(ws "," ws ex:SelectItem { return ex, nil })? ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallArraySlice, []interface{}{array, start, length})
|
|
}
|
|
|
|
SetIntersectExpression <- "SetIntersect"i ws "(" ws set1:SelectItem ws "," ws set2:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallSetIntersect, []interface{}{set1, set2})
|
|
}
|
|
|
|
SetUnionExpression <- "SetUnion"i ws "(" ws set1:SelectItem ws "," ws set2:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallSetUnion, []interface{}{set1, set2})
|
|
}
|
|
|
|
IifExpression <- "IIF"i ws "(" ws condition:SelectItem ws "," ws trueValue:SelectItem ws "," ws falseValue:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallIif, []interface{}{condition, trueValue, falseValue})
|
|
}
|
|
|
|
MathAbsExpression <- "ABS"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathAbs, []interface{}{ex}) }
|
|
MathAcosExpression <- "ACOS"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathAcos, []interface{}{ex}) }
|
|
MathAsinExpression <- "ASIN"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathAsin, []interface{}{ex}) }
|
|
MathAtanExpression <- "ATAN"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathAtan, []interface{}{ex}) }
|
|
MathCeilingExpression <- "CEILING"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathCeiling, []interface{}{ex}) }
|
|
MathCosExpression <- "COS"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathCos, []interface{}{ex}) }
|
|
MathCotExpression <- "COT"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathCot, []interface{}{ex}) }
|
|
MathDegreesExpression <- "DEGREES"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathDegrees, []interface{}{ex}) }
|
|
MathExpExpression <- "EXP"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathExp, []interface{}{ex}) }
|
|
MathFloorExpression <- "FLOOR"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathFloor, []interface{}{ex}) }
|
|
MathIntBitNotExpression <- "IntBitNot"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathIntBitNot, []interface{}{ex}) }
|
|
MathLog10Expression <- "LOG10"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathLog10, []interface{}{ex}) }
|
|
MathRadiansExpression <- "RADIANS"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathRadians, []interface{}{ex}) }
|
|
MathRoundExpression <- "ROUND"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathRound, []interface{}{ex}) }
|
|
MathSignExpression <- "SIGN"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathSign, []interface{}{ex}) }
|
|
MathSinExpression <- "SIN"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathSin, []interface{}{ex}) }
|
|
MathSqrtExpression <- "SQRT"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathSqrt, []interface{}{ex}) }
|
|
MathSquareExpression <- "SQUARE"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathSquare, []interface{}{ex}) }
|
|
MathTanExpression <- "TAN"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathTan, []interface{}{ex}) }
|
|
MathTruncExpression <- "TRUNC"i ws "(" ws ex:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathTrunc, []interface{}{ex}) }
|
|
|
|
MathAtn2Expression <- "ATN2"i ws "(" ws set1:SelectItem ws "," ws set2:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathAtn2, []interface{}{set1, set2}) }
|
|
MathIntAddExpression <- "IntAdd"i ws "(" ws set1:SelectItem ws "," ws set2:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathIntAdd, []interface{}{set1, set2}) }
|
|
MathIntBitAndExpression <- "IntBitAnd"i ws "(" ws set1:SelectItem ws "," ws set2:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathIntBitAnd, []interface{}{set1, set2}) }
|
|
MathIntBitLeftShiftExpression <- "IntBitLeftShift"i ws "(" ws set1:SelectItem ws "," ws set2:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathIntBitLeftShift, []interface{}{set1, set2}) }
|
|
MathIntBitOrExpression <- "IntBitOr"i ws "(" ws set1:SelectItem ws "," ws set2:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathIntBitOr, []interface{}{set1, set2}) }
|
|
MathIntBitRightShiftExpression <- "IntBitRightShift"i ws "(" ws set1:SelectItem ws "," ws set2:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathIntBitRightShift, []interface{}{set1, set2}) }
|
|
MathIntBitXorExpression <- "IntBitXor"i ws "(" ws set1:SelectItem ws "," ws set2:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathIntBitXor, []interface{}{set1, set2}) }
|
|
MathIntDivExpression <- "IntDiv"i ws "(" ws set1:SelectItem ws "," ws set2:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathIntDiv, []interface{}{set1, set2}) }
|
|
MathIntModExpression <- "IntMod"i ws "(" ws set1:SelectItem ws "," ws set2:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathIntMod, []interface{}{set1, set2}) }
|
|
MathIntMulExpression <- "IntMul"i ws "(" ws set1:SelectItem ws "," ws set2:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathIntMul, []interface{}{set1, set2}) }
|
|
MathIntSubExpression <- "IntSub"i ws "(" ws set1:SelectItem ws "," ws set2:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathIntSub, []interface{}{set1, set2}) }
|
|
MathPowerExpression <- "POWER"i ws "(" ws set1:SelectItem ws "," ws set2:SelectItem ws ")" { return createFunctionCall(parsers.FunctionCallMathPower, []interface{}{set1, set2}) }
|
|
|
|
MathLogExpression <- "LOG"i ws "(" ws ex1:SelectItem others:(ws "," ws ex:SelectItem { return ex, nil })* ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallMathLog, append([]interface{}{ex1}, others.([]interface{})...))
|
|
}
|
|
MathNumberBinExpression <- "NumberBin"i ws "(" ws ex1:SelectItem others:(ws "," ws ex:SelectItem { return ex, nil })* ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallMathNumberBin, append([]interface{}{ex1}, others.([]interface{})...))
|
|
}
|
|
MathPiExpression <- "PI"i ws "(" ws ")" { return createFunctionCall(parsers.FunctionCallMathPi, []interface{}{}) }
|
|
MathRandExpression <- "RAND"i ws "(" ws ")" { return createFunctionCall(parsers.FunctionCallMathRand, []interface{}{}) }
|
|
|
|
InFunction <- ex1:SelectProperty ws notIn:("NOT"i ws)? In ws "(" ws ex2:SelectItem others:(ws "," ws ex:SelectItem { return ex, nil })* ws ")" {
|
|
arguments := append([]interface{}{ex1, ex2}, others.([]interface{})...)
|
|
functionCall, _ := createFunctionCall(parsers.FunctionCallIn, arguments)
|
|
|
|
if notIn != nil {
|
|
return parsers.SelectItem{
|
|
Type: parsers.SelectItemTypeFunctionCall,
|
|
Value: functionCall,
|
|
Invert: true,
|
|
}, nil
|
|
}
|
|
|
|
return functionCall, nil
|
|
}
|
|
/ "(" ws ex1:SelectItem ws notIn:("NOT"i ws)? In ws "(" ws ex2:SelectItem others:(ws "," ws ex:SelectItem { return ex, nil })* ws ")" ws ")" {
|
|
arguments := append([]interface{}{ex1, ex2}, others.([]interface{})...)
|
|
functionCall, _ := createFunctionCall(parsers.FunctionCallIn, arguments)
|
|
|
|
if notIn != nil {
|
|
return parsers.SelectItem{
|
|
Type: parsers.SelectItemTypeFunctionCall,
|
|
Value: functionCall,
|
|
Invert: true,
|
|
}, nil
|
|
}
|
|
|
|
return functionCall, nil
|
|
}
|
|
|
|
AvgAggregateExpression <- "AVG"i "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallAggregateAvg, []interface{}{ex})
|
|
}
|
|
|
|
CountAggregateExpression <- "COUNT"i "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallAggregateCount, []interface{}{ex})
|
|
}
|
|
|
|
MaxAggregateExpression <- "MAX"i "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallAggregateMax, []interface{}{ex})
|
|
}
|
|
|
|
MinAggregateExpression <- "MIN"i "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallAggregateMin, []interface{}{ex})
|
|
}
|
|
|
|
SumAggregateExpression <- "SUM"i "(" ws ex:SelectItem ws ")" {
|
|
return createFunctionCall(parsers.FunctionCallAggregateSum, []interface{}{ex})
|
|
}
|
|
|
|
Integer <- [0-9]+ {
|
|
return strconv.Atoi(string(c.text))
|
|
}
|
|
|
|
StringCharacter <- !('"' / "\\") . { return string(c.text), nil }
|
|
/ "\\" seq:EscapeSequenceCharacter { return seq, nil }
|
|
|
|
SingleQuotedStringCharacter <- !("'" / "\\") . { return string(c.text), nil }
|
|
/ "\\" seq:EscapeSequenceCharacter { return seq, nil }
|
|
|
|
EscapeSequenceCharacter <- char:EscapeCharacter
|
|
|
|
EscapeCharacter <- "'" { return "'", nil }
|
|
/ '"' { return "\"", nil }
|
|
/ "\\" { return "\\", nil }
|
|
/ "b" { return "\b", nil }
|
|
/ "f" { return "\f", nil }
|
|
/ "n" { return "\n", nil }
|
|
/ "r" { return "\r", nil }
|
|
/ "t" { return "\t", nil }
|
|
|
|
non_escape_character <- !(escape_character) char:.
|
|
{ return string(c.text), nil }
|
|
|
|
ws <- [ \t\n\r]*
|
|
|
|
wss <- [ \t\n\r]+
|
|
|
|
EOF <- !.
|