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 SelectItems []SelectItem
Table Table Table Table
Filters interface{} Filters interface{}
Count int
} }
type Table struct { 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" 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{ selectStmt := parsers.SelectStmt{
SelectItems: columns.([]parsers.SelectItem), SelectItems: columns.([]parsers.SelectItem),
Table: table.(parsers.Table), Table: table.(parsers.Table),
@ -15,6 +15,10 @@ func makeSelectStmt(columns, table, whereClause interface{}) (parsers.SelectStmt
selectStmt.Filters = filters selectStmt.Filters = filters
} }
if n, ok := count.(int); ok {
selectStmt.Count = n
}
return selectStmt, nil return selectStmt, nil
} }
@ -98,10 +102,14 @@ Input <- selectStmt:SelectStmt {
return selectStmt, nil return selectStmt, nil
} }
SelectStmt <- Select ws columns:Selection ws SelectStmt <- Select ws topClause:TopClause? ws columns:Selection ws
From ws table:TableName ws From ws table:TableName ws
whereClause:(ws Where ws condition:Condition { return condition, nil })? { 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 Selection <- SelectValueSpec / ColumnList
@ -178,6 +186,8 @@ ComparisonExpression <- left:(Literal / SelectItem) ws op:ComparisonOperator ws
Select <- ("select" / "SELECT") Select <- ("select" / "SELECT")
Top <- ("top" / "TOP")
As <- ("as" / "AS") As <- ("as" / "AS")
From <- ("from" / "FROM") From <- ("from" / "FROM")
@ -190,9 +200,8 @@ ComparisonOperator <- "=" / "!=" / "<" / "<=" / ">" / ">=" {
Literal <- FloatLiteral / IntegerLiteral / StringLiteral / BooleanLiteral Literal <- FloatLiteral / IntegerLiteral / StringLiteral / BooleanLiteral
IntegerLiteral <- [0-9]+ { IntegerLiteral <- number:Integer {
intValue, _ := strconv.Atoi(string(c.text)) return parsers.Constant{Type: parsers.ConstantTypeInteger, Value: number.(int)}, nil
return parsers.Constant{Type: parsers.ConstantTypeInteger, Value: intValue}, nil
} }
StringLiteral <- "\"" chars:StringCharacter* "\"" { StringLiteral <- "\"" chars:StringCharacter* "\"" {
return parsers.Constant{Type: parsers.ConstantTypeString,Value: joinStrings(chars.([]interface{}))}, nil 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 return parsers.Constant{Type: parsers.ConstantTypeBoolean, Value: boolValue}, nil
} }
Integer <- [0-9]+ {
return strconv.Atoi(string(c.text))
}
StringCharacter <- !('"' / "\\") . { return string(c.text), nil } StringCharacter <- !('"' / "\\") . { return string(c.text), nil }
/ "\\" seq:EscapeSequenceCharacter { return seq, 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) { t.Run("Should parse SELECT VALUE", func(t *testing.T) {
testQueryParse( testQueryParse(
t, 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 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) { t.Run("Should execute SELECT VALUE", func(t *testing.T) {
testQueryExecute( testQueryExecute(
t, t,