Added support for TOP statement

This commit is contained in:
Pijus Kamandulis 2024-02-14 21:03:49 +02:00
parent 62ac9ddf6b
commit b13434eeff
6 changed files with 477 additions and 316 deletions

View File

@ -28,6 +28,7 @@ type SelectStmt struct {
SelectItems []SelectItem
Table Table
Filters interface{}
Count int
}
type Table struct {

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@ package nosql
import "github.com/pikami/cosmium/parsers"
func makeSelectStmt(columns, table, whereClause interface{}) (parsers.SelectStmt, error) {
func makeSelectStmt(columns, table, whereClause interface{}, count interface{}) (parsers.SelectStmt, error) {
selectStmt := parsers.SelectStmt{
SelectItems: columns.([]parsers.SelectItem),
Table: table.(parsers.Table),
@ -15,6 +15,10 @@ func makeSelectStmt(columns, table, whereClause interface{}) (parsers.SelectStmt
selectStmt.Filters = filters
}
if n, ok := count.(int); ok {
selectStmt.Count = n
}
return selectStmt, nil
}
@ -98,10 +102,14 @@ Input <- selectStmt:SelectStmt {
return selectStmt, nil
}
SelectStmt <- Select ws columns:Selection ws
SelectStmt <- Select ws topClause:TopClause? ws columns:Selection ws
From ws table:TableName ws
whereClause:(ws Where ws condition:Condition { return condition, nil })? {
return makeSelectStmt(columns, table, whereClause)
return makeSelectStmt(columns, table, whereClause, topClause)
}
TopClause <- Top ws count:Integer {
return count, nil
}
Selection <- SelectValueSpec / ColumnList
@ -178,6 +186,8 @@ ComparisonExpression <- left:(Literal / SelectItem) ws op:ComparisonOperator ws
Select <- ("select" / "SELECT")
Top <- ("top" / "TOP")
As <- ("as" / "AS")
From <- ("from" / "FROM")
@ -190,9 +200,8 @@ ComparisonOperator <- "=" / "!=" / "<" / "<=" / ">" / ">=" {
Literal <- FloatLiteral / IntegerLiteral / StringLiteral / BooleanLiteral
IntegerLiteral <- [0-9]+ {
intValue, _ := strconv.Atoi(string(c.text))
return parsers.Constant{Type: parsers.ConstantTypeInteger, Value: intValue}, 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
@ -206,6 +215,10 @@ BooleanLiteral <- ("true" / "false") {
return parsers.Constant{Type: parsers.ConstantTypeBoolean, Value: boolValue}, nil
}
Integer <- [0-9]+ {
return strconv.Atoi(string(c.text))
}
StringCharacter <- !('"' / "\\") . { return string(c.text), nil }
/ "\\" seq:EscapeSequenceCharacter { return seq, nil }

View File

@ -52,6 +52,20 @@ func Test_Parse(t *testing.T) {
)
})
t.Run("Should parse SELECT TOP", func(t *testing.T) {
testQueryParse(
t,
`SELECT TOP 1 c.id FROM c`,
parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{Path: []string{"c", "id"}},
},
Table: parsers.Table{Value: "c"},
Count: 1,
},
)
})
t.Run("Should parse SELECT VALUE", func(t *testing.T) {
testQueryParse(
t,

View File

@ -18,6 +18,17 @@ func Execute(query parsers.SelectStmt, data []RowType) []RowType {
}
}
// Apply result limit
if query.Count > 0 {
count := func() int {
if len(result) < query.Count {
return len(result)
}
return query.Count
}()
result = result[:count]
}
return result
}

View File

@ -45,6 +45,24 @@ func Test_Execute(t *testing.T) {
)
})
t.Run("Should execute SELECT TOP", func(t *testing.T) {
testQueryExecute(
t,
parsers.SelectStmt{
SelectItems: []parsers.SelectItem{
{Path: []string{"c", "id"}},
{Path: []string{"c", "pk"}},
},
Table: parsers.Table{Value: "c"},
Count: 1,
},
mockData,
[]memoryexecutor.RowType{
map[string]interface{}{"id": "12345", "pk": 123},
},
)
})
t.Run("Should execute SELECT VALUE", func(t *testing.T) {
testQueryExecute(
t,